按键加数码管显示,好好的程序被我写成这样,我还有救吗

[复制链接]
 楼主| renwocai 发表于 2013-5-30 13:25 | 显示全部楼层 |阅读模式

本次任务很简单,数码管用于动态显示,三个按键的作用为:第一个按键为模式按键,第一次按下时千位的数码管闪烁;第二次按下时百位的数码管闪烁,同时千位不再闪烁;第三次按下时十位的数码管闪烁,同时百位不再闪烁;依此类推。
第二个按键为加1按键,当某位闪烁时按此按键则加1,到10时复为0。
第三个按键为减1按键,作用同上。

现在我的程序已经写出来了,也能实现功能。但总觉得别扭。没有可读性,不能拓展。现贴出代码及工程打包,希望各位能指点下
  1. #include <reg51.h>
  2. #include <intrins.h>
  3. typedef unsigned char uchar;
  4. typedef unsigned int uint;
  5. sbit wei1=P2^0;
  6. sbit wei2=P2^1;
  7. sbit wei3=P2^2;
  8. sbit wei4=P2^3;
  9. uchar code tab[]= {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff};
  10. uchar num[4]= {1,2,3,4};
  11. uchar disp[4];
  12. uchar dida1ms;
  13. uint dida1ms2;
  14. uchar Trag,Cont;
  15. void InitT0()
  16. {
  17.     TH0=0Xfc;
  18.     TL0=0X18;
  19.     EA=1;
  20.     ET0=1;
  21.     TR0=1;
  22. }
  23. void Getkey()
  24. {
  25.     uchar ReadData;
  26.     ReadData=P3^0XFF;
  27.     Trag=ReadData&(Cont^ReadData);
  28.     Cont=ReadData;
  29. }
  30. void main(void)
  31. {
  32.     uchar moshi=0;
  33.     InitT0();
  34.     disp[0]=num[0];
  35.     disp[1]=num[1];
  36.     disp[2]=num[2];
  37.     disp[3]=num[3];
  38.     while (1)
  39.     {
  40.         if(dida1ms==50)
  41.         {
  42.             wei1=1;
  43.             wei2=0;
  44.             P0=tab[disp[1]];
  45.         }
  46.         else if(dida1ms==100)
  47.         {
  48.             wei2=1;
  49.             wei3=0;
  50.             P0=tab[disp[2]];
  51.         }
  52.         else if(dida1ms==150)
  53.         {
  54.             wei3=1;
  55.             wei4=0;
  56.             P0=tab[disp[3]];
  57.         }
  58.         else if(dida1ms==200)
  59.         {
  60.             dida1ms=0;
  61.             wei4=1;
  62.             wei1=0;
  63.             P0=tab[disp[0]];
  64.         }
  65.         Getkey();
  66.         if(Trag&1)
  67.         {
  68.             moshi++;
  69.         }
  70.         if(moshi==5)
  71.         {
  72.             moshi=0;
  73.         }
  74.         if(moshi!=0)
  75.         {
  76.             if(Trag&2)
  77.             {
  78.                 num[moshi-1]++;
  79.             }
  80.             if(num[moshi-1]==10)
  81.             {
  82.                 num[moshi-1]=0;
  83.             }
  84.             if(Trag&4)
  85.             {
  86.                 num[moshi-1]--;
  87.             }
  88.             if(num[moshi-1]==255)
  89.             {
  90.                 num[moshi-1]=9;
  91.             }
  92.             if(moshi!=1)
  93.             {
  94.                 disp[moshi-2]=num[moshi-2];
  95.             }
  96.             if(dida1ms2==2000)
  97.             {
  98.                 disp[moshi-1]=num[moshi-1];
  99.             }
  100.             else if(dida1ms2>=4000)
  101.             {
  102.                 disp[moshi-1]=10;
  103.                 dida1ms2=0;
  104.             }
  105.         }
  106.         else
  107.         {
  108.             disp[3]=num[3];
  109.         }
  110.     }
  111. }
  112. void T0ser() interrupt 1
  113. {
  114.     TH0=0Xfc;
  115.     TL0=0X18;
  116.     dida1ms++;
  117.     dida1ms2++;
  118. }



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| renwocai 发表于 2013-5-30 13:54 | 显示全部楼层
自顶一层吧,对于程序框架,都来说说。
 楼主| renwocai 发表于 2013-5-30 14:02 | 显示全部楼层
对于这个任务大部分高手都做过吧,也贴出代码交流下~~
huangxz 发表于 2013-5-30 14:23 | 显示全部楼层
楼主写成这样说明已经有一定的程序修养了,最好那么多if改成switch-case语句,这样可读性强一点
ayb_ice 发表于 2013-5-30 15:06 | 显示全部楼层
仿真看起来可以

但看了一下代码
每位显示50MS,4位共200MS,刷新周期只有5HZ,实际根本不是这效果,
第二这个架构没有延展性,中间某个任务处理较长时间,显示也会闪烁
ayb_ice 发表于 2013-5-30 15:14 | 显示全部楼层
另外对dida1ms2变量的访问没有满足原子操作规则,实际中会有很多隐性的BUG,随时可能出现怪现象
 楼主| renwocai 发表于 2013-5-30 15:51 | 显示全部楼层
huangxz 发表于 2013-5-30 14:23
楼主写成这样说明已经有一定的程序修养了,最好那么多if改成switch-case语句,这样可读性强一点 ...

谢谢,这几行.是可以写成SWITCH-CASE
        if(dida1ms==50)
        {
            wei1=1;
            wei2=0;
            P0=tab[disp[1]];
        }
        else if(dida1ms==100)
        {
            wei2=1;
            wei3=0;
            P0=tab[disp[2]];
        }
        else if(dida1ms==150)
        {
            wei3=1;
            wei4=0;
            P0=tab[disp[3]];
        }
        else if(dida1ms==200)
        {
            dida1ms=0;
            wei4=1;
            wei1=0;
            P0=tab[disp[0]];
        }
 楼主| renwocai 发表于 2013-5-30 15:59 | 显示全部楼层
ayb_ice 发表于 2013-5-30 15:06
仿真看起来可以

但看了一下代码

谢谢,这也是我想发贴想表达的意思,数码管的刷新周期不是问题,好像在仿真里面有点怪,这么低的刷新率也没有闪.而我用延时的写法一定要在15ms才能达到静态的效果.按下模式键时某位的闪烁效果也是这样,在这个程序中,把dida1ms2加到2000才得到想要的闪烁效果,这个闪烁周期达到4S了,可看起来好像1S都不到的样子。

不过,这些都不是重点,这个程序没有延展性,我也想到了,应该怎么做才能解决这一问题?何谓原子操作规则?



wolension 发表于 2013-5-31 16:44 | 显示全部楼层
我改了一下,楼主看下有没有帮助.

#include <reg51.h>
#include <intrins.h>
typedef unsigned char uchar;
typedef unsigned int uint;
sbit wei1=P2^0;
sbit wei2=P2^1;
sbit wei3=P2^2;
sbit wei4=P2^3;
uchar code tab[]= {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff};
uchar num[4]= {1,2,3,4};
uchar disp[4];
uchar dida1ms;
static uchar moshi=0;
uint dida1ms2;
uchar Trag,Cont;
void InitT0()
{
    TH0=0Xfc;
    TL0=0X18;
    EA=1;
    ET0=1;
    TR0=1;
}
void Getkey()
{
    uchar ReadData;
    ReadData=P3^0XFF;
    Trag=ReadData&(Cont^ReadData);
    Cont=ReadData;
}

void DecodeKey()
{
wolension 发表于 2013-5-31 16:46 | 显示全部楼层
怎么看不全?
再来
void DecodeKey()
{
        if(Trag&1)
    {
        if(++moshi >= 5)   moshi=0;               
    }
    if(moshi!=0)
    {
        if(Trag&2)
        {
            if(++num[moshi-1] >= 10) num[moshi-1]=0;
        }   
        if(Trag&4)
        {
            if(--num[moshi-1] >= 255) num[moshi-1]=9;
        }               
    }   
}

void Display(void)
{
        uchar temp = (dida1ms & 0x0f);          
        if(temp & 3) return;                         //4ms

        disp[0] = num[0];
    disp[1] = num[1];
    disp[2] = num[2];
    disp[3] = num[3];
        if((dida1ms2 >= 2000) && (moshi != 0))  disp[moshi-1] = 10;
          
        temp >>= 2;
        P2 |= 0x0f;
        P0 = tab[disp[temp]];
        P2 &=  ~(1<<temp);
}

void main(void)
{  
    InitT0();
   
    while (1)
    {
               Display();
        Getkey();
        DecodeKey();
    }
}
void T0ser() interrupt 1
{
    TH0=0Xfc;
    TL0=0X18;
        dida1ms++;
        if(++dida1ms2 >= 4000) dida1ms2 = 0;
}
兰天白云 发表于 2013-5-31 16:50 | 显示全部楼层
已经不错了,能认识到自己的不足就是最大的优点,楼主3年后定是高人
cjseng 发表于 2013-5-31 22:59 | 显示全部楼层
本帖最后由 cjseng 于 2013-5-31 23:01 编辑

我来写的话,我会这样写:

#include <stdio.h>
#include <REGX52.H>
#include <test.h>

#define XD 20                     //按键消抖时间50ms

main()
{
Delay(500);         //延时一段时间
Init_Mcu();                        //初始化
D05s=200;                             //半秒计数初值

for(;;)
{
  WTD=0;          //看门狗
  PCON|=0x01;                  //休眠
}
}

//定时器1中断服务程序     2.5ms
void Time_1() interrupt 3
{
TR1=0;
TH1=0xf6;
TL1=0x40;
TR1=1;

WTD=1;           //看门狗

Get_Key();                            //按键扫描
Display();          //数码管显示
Out();            //输出
。。。

if(D05s>1)
{
  D05s--;
}
else     
{
  D05s=200;                   //半秒整,可以用其它以秒为单位的计数,或用于数码管闪烁显示
}
。。。
}  

。。。
gx_huang 发表于 2013-6-1 10:36 | 显示全部楼层
50毫秒刷新一个数码管,会闪的。
在主程序里刷新显示,程序架构就不会好的。
不能因为目前要求低,将来扩展应用,程序怎么写?

一般是定时中断里刷新显示。
主程序干其它的事情。
 楼主| renwocai 发表于 2013-6-1 18:10 | 显示全部楼层
wolension 发表于 2013-5-31 16:46
怎么看不全?
再来
void DecodeKey()

谢谢,比我在主楼写的要好很多。

其一,把main函数中的大段代码进行了分解,成为按键,解码,显示三段,更符合模块化的规范

其二,显示部分的实现也比主楼的要好。


也希望版主们,高手们可以这种代码的方式交流,拍砖。
 楼主| renwocai 发表于 2013-6-1 18:16 | 显示全部楼层
cjseng 发表于 2013-5-31 22:59
我来写的话,我会这样写:

#include

谢谢,就是说把热键扫描,处理,显示都丢到中断里。时间不到就睡觉?

这样写是低功耗的需要?
 楼主| renwocai 发表于 2013-6-1 19:49 | 显示全部楼层
gx_huang 发表于 2013-6-1 10:36
50毫秒刷新一个数码管,会闪的。
在主程序里刷新显示,程序架构就不会好的。
不能因为目前要求低,将来扩展 ...

我也在想,在要求高的场合,刷新显示到底是放在主函数好呢,还是放在定时中断里面好呢?

一般定时器服务程序都有产生时标的任务,放太多代码到定时器中断程序里面,会让这个时标产生误差而影响实时性。当然,放在主函数里面,则要保证一次大循环执行完毕要有一定的时间余量,否则也会影响实时性。

评论

这个还用想 当然放主函数。  发表于 2013-6-2 07:29
cjseng 发表于 2013-6-2 00:15 | 显示全部楼层
本帖最后由 cjseng 于 2013-6-2 00:27 编辑
renwocai 发表于 2013-6-1 18:16
谢谢,就是说把热键扫描,处理,显示都丢到中断里。时间不到就睡觉?

这样写是低功耗的需要? ...


抗干扰的要求,睡觉时干扰基本不起作用。
我写的所有程序都是这种架构,main()函数除了开机时的初始化,以及睡觉,啥也不干,所有的任务都在中断里完成,到目前为止,没遇到不能实现的。我做的一个产品,有31位数码管(动态扫描,可以用程序控制数码管亮度)。14个指示灯,35个按键,8路数字量输入、8路数字量输出,还要和7个变频器通讯,我也是用的这种结构,用的就是51单片机。
xlsbz 发表于 2013-6-2 07:16 | 显示全部楼层
  • 有人说用switch 我觉得没必要

    另外 排兵布阵  
    if(dida1ms==50)
  • {
  • wei1=1;
  • wei2=0;
  • P0=tab[disp[1]];
  • }
  • else if(dida1ms==100)
  • {
  • wei2=1;
  • wei3=0;
  • P0=tab[disp[2]];
  • }
  • else if(dida1ms==150)
  • {
  • wei3=1;
  • wei4=0;
  • P0=tab[disp[3]];

可以 这样弄
  if () {}
else if (){}
elseif (){}
else if (){}
elseif (){}

这样对的多整齐。不要过于形式主义 追求规范。
另外 那个

  •   if(moshi!=1)
  •             {
  •                 disp[moshi-2]=num[moshi-2];
  •             }

看起来不太妥当
moshii 一定要大于2啊
即便你程序里面别的地方moshi都大于2,也可以考虑

  •   if(moshi!=1)
  •             {
                       if (moshi>2){
  •                 disp[moshi-2]=num[moshi-2];
  •                     }
  •             }

xlsbz 发表于 2013-6-2 07:17 | 显示全部楼层
有人说显示全放中断里,这个楼主肯定不会采纳的
xlsbz 发表于 2013-6-2 07:19 | 显示全部楼层
本帖最后由 xlsbz 于 2013-6-2 07:26 编辑

另外 有可能的话 楼主最好搞个带参数的函数 看起来比较有档次

INT8U  get_P口值(INT8U  dida1ms, INT8U Y ........) {
....
}


P0 = get_P口值;
您需要登录后才可以回帖 登录 | 注册

本版积分规则

8

主题

173

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部