打印

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

[复制链接]
4930|25
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
renwocai|  楼主 | 2013-5-30 13:25 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

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

现在我的程序已经写出来了,也能实现功能。但总觉得别扭。没有可读性,不能拓展。现贴出代码及工程打包,希望各位能指点下
#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;
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 main(void)
{
    uchar moshi=0;
    InitT0();
    disp[0]=num[0];
    disp[1]=num[1];
    disp[2]=num[2];
    disp[3]=num[3];
    while (1)
    {
        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]];
        }
        Getkey();
        if(Trag&1)
        {
            moshi++;
        }
        if(moshi==5)
        {
            moshi=0;
        }
        if(moshi!=0)
        {
            if(Trag&2)
            {
                num[moshi-1]++;
            }
            if(num[moshi-1]==10)
            {
                num[moshi-1]=0;
            }
            if(Trag&4)
            {
                num[moshi-1]--;
            }
            if(num[moshi-1]==255)
            {
                num[moshi-1]=9;
            }
            if(moshi!=1)
            {
                disp[moshi-2]=num[moshi-2];
            }
            if(dida1ms2==2000)
            {
                disp[moshi-1]=num[moshi-1];
            }
            else if(dida1ms2>=4000)
            {
                disp[moshi-1]=10;
                dida1ms2=0;
            }
        }
        else
        {
            disp[3]=num[3];
        }
    }
}
void T0ser() interrupt 1
{
    TH0=0Xfc;
    TL0=0X18;
    dida1ms++;
    dida1ms2++;
}
按键加数码管显示.rar (39.46 KB)


相关帖子

沙发
renwocai|  楼主 | 2013-5-30 13:54 | 只看该作者
自顶一层吧,对于程序框架,都来说说。

使用特权

评论回复
板凳
renwocai|  楼主 | 2013-5-30 14:02 | 只看该作者
对于这个任务大部分高手都做过吧,也贴出代码交流下~~

使用特权

评论回复
地板
huangxz| | 2013-5-30 14:23 | 只看该作者
楼主写成这样说明已经有一定的程序修养了,最好那么多if改成switch-case语句,这样可读性强一点

使用特权

评论回复
5
ayb_ice| | 2013-5-30 15:06 | 只看该作者
仿真看起来可以

但看了一下代码
每位显示50MS,4位共200MS,刷新周期只有5HZ,实际根本不是这效果,
第二这个架构没有延展性,中间某个任务处理较长时间,显示也会闪烁

使用特权

评论回复
6
ayb_ice| | 2013-5-30 15:14 | 只看该作者
另外对dida1ms2变量的访问没有满足原子操作规则,实际中会有很多隐性的BUG,随时可能出现怪现象

使用特权

评论回复
7
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]];
        }

使用特权

评论回复
8
renwocai|  楼主 | 2013-5-30 15:59 | 只看该作者
ayb_ice 发表于 2013-5-30 15:06
仿真看起来可以

但看了一下代码

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

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



使用特权

评论回复
9
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()
{

使用特权

评论回复
10
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;
}

使用特权

评论回复
11
兰天白云| | 2013-5-31 16:50 | 只看该作者
已经不错了,能认识到自己的不足就是最大的优点,楼主3年后定是高人

使用特权

评论回复
12
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;                   //半秒整,可以用其它以秒为单位的计数,或用于数码管闪烁显示
}
。。。
}  

。。。

使用特权

评论回复
13
gx_huang| | 2013-6-1 10:36 | 只看该作者
50毫秒刷新一个数码管,会闪的。
在主程序里刷新显示,程序架构就不会好的。
不能因为目前要求低,将来扩展应用,程序怎么写?

一般是定时中断里刷新显示。
主程序干其它的事情。

使用特权

评论回复
14
renwocai|  楼主 | 2013-6-1 18:10 | 只看该作者
wolension 发表于 2013-5-31 16:46
怎么看不全?
再来
void DecodeKey()

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

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

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


也希望版主们,高手们可以这种代码的方式交流,拍砖。

使用特权

评论回复
15
renwocai|  楼主 | 2013-6-1 18:16 | 只看该作者
cjseng 发表于 2013-5-31 22:59
我来写的话,我会这样写:

#include

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

这样写是低功耗的需要?

使用特权

评论回复
16
renwocai|  楼主 | 2013-6-1 19:49 | 只看该作者
gx_huang 发表于 2013-6-1 10:36
50毫秒刷新一个数码管,会闪的。
在主程序里刷新显示,程序架构就不会好的。
不能因为目前要求低,将来扩展 ...

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

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

使用特权

评论回复
评论
xlsbz 2013-6-2 07:29 回复TA
这个还用想 当然放主函数。 
17
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单片机。

使用特权

评论回复
18
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];
  •                     }
  •             }

使用特权

评论回复
19
xlsbz| | 2013-6-2 07:17 | 只看该作者
有人说显示全放中断里,这个楼主肯定不会采纳的

使用特权

评论回复
20
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

粉丝