正文

【045】数码管显示简单电子钟2007-05-05 16:33:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/wentao/25599.html

分享到:

  • ;**************************************************************************   
  • ; 标题: 数码管显示电子钟(汇编)   
  • ; 作者: wentao     http://blog.liuwentao.net   
  • ;                  http://wentao.programfan.com   
  • ; 日期: 2007.3.3   
  • ; 软件: Keil A51 V8.00    
  • ; 芯片: AT89X51   
  • ; 说明: 实验板实测通过,数码管为8位共阳   
  • ; 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!    
  • ;**************************************************************************   
  •   
  • sec_l  equ  30h        ;30单元存储秒个位值   
  • sec_h  equ  31h        ;31单元存储秒十位值   
  • bar_2  equ  32h        ;32单元存储"-"段码的偏移量   
  • min_l  equ  33h        ;33单元存储分个位值   
  • min_h  equ  34h        ;34单元存储分十位值   
  • bar_5  equ  35h        ;35单元存储"-"段码的偏移量   
  • hou_l  equ  36h        ;36单元存储时个位值   
  • hou_h  equ  37h        ;37单元存储时十位值   
  •   
  • sec    equ  38h        ;38单元为秒计数器(00s-59s)   
  • min    equ  39h        ;39单元为分计数器(00m-59m)   
  • hou    equ  40h        ;40单元为时计数器(00h-23h)   
  •   
  • cou    equ  41h        ;41单元为软计数器,对10ms时基信号累加到1s   
  •   
  • dis_b  equ  42h        ;dis_b(42单元)作为位码选通数码管   
  • dis_r  equ  43h        ;dis_r(43单元)为取段码时的偏移量   
  •   
  • key_v  equ  44h        ;存储键值   
  • key_t  equ  45h        ;按键扫描中临时存储键值   
  •   
  •           org   0000h  
  •           ajmp  start   
  •           org   000bh           ;定时器0的中断入口地址   
  •           ajmp  time0           ;跳到定时器0的中断服务程序处   
  •           org   001bh           ;定时器1的中断入口地址   
  •           ajmp  time1           ;跳到定时器1的中断服务程序处   
  •           org   0030h  
  • start:       
  •           mov   p2,#0xff        ;关所有数码管   
  •           mov   p1,#0xff        ;p1为准双向口,作输入时先写1   
  •           mov   key_v,#0xff     ;初始键值为ff   
  •              
  •           mov   bar_2,#10       ;'-'段码偏移量为10   
  •           mov   bar_5,#10       ;'-'段码偏移量为10   
  •           mov   dis_b,#0x7f     ;初始选通P2.7口数码管   
  •           mov   dis_r,#0        ;初始化偏移量为0   
  •           mov   sec,#0          ;秒计数清零   
  •           mov   min,#0          ;分计数清零   
  •           mov   hou,#0          ;时计数清零   
  •           mov   cou,#0          ;软计数器清零   
  •              
  •           mov   tmod,#00010001b ;定时/计数器0、1工作于方式1   
  •           mov   th0,#0xd8       ;预置定时常数55536(d8f0),产生10ms时基信号   
  •           mov   tl0,#0xf0  
  •           mov   th1,#0xfc       ;预置定时常数64536(fc18),产生1ms间隔用于动态显示   
  •           mov   tl1,#0x18  
  •              
  •           setb  ea              ;开总中断   
  •           setb  et0             ;定时/计数器0允许中断   
  •           setb  et1             ;定时/计数器1允许中断   
  •           setb  tr0             ;开定时/计数器0   
  •           setb  tr1             ;开定时/计数器1   
  •              
  • key:  
  •           mov   a,p1            ;读入键值   
  •           mov   key_t,a         ;存储到临时变量中   
  •           xrl   a,key_v         ;检测键值是否改变   
  •           jz    key             ;未改变则重新扫描   
  •           lcall d_10ms          ;有键按下则延时10ms消抖   
  •           mov   a,p1            ;再次读入键值   
  •           mov   key_t,a         ;存入临时变量   
  •           xrl   a,key_v         ;检测键值是否改变   
  •           jz    key             ;未改变则为抖动继续扫描   
  •           mov   key_v,key_t     ;确定为键按下则保存键值   
  •           lcall key_to          ;调用键处理部分   
  •           ajmp  key             ;循环扫描按键   
  •   
  • key_to:                         ;键处理子程序   
  •           mov   a,key_v         ;读入键值   
  •           cjne  a,#0xef,next    ;不是P1.4口键值则查下一个   
  •           ajmp  k1              ;是则转去执行该键的处理   
  • next:     cjne  a,#0xdf,back    ;也不是P1.5口键值则结束   
  •           ajmp  k2              ;是则转去执行该键的处理   
  • k1:       mov   a,min           ;读入分计数器的值   
  •           cjne  a,#59,k1_add    ;分计数值未到59   
  •           mov   min,#0          ;分钟加到59时则清零   
  •           ajmp  back            ;结束   
  • k1_add:   inc   min             ;分加1   
  •           ajmp  back            ;结束   
  • k2:       mov   a,hou           ;读入时计数器的值   
  •           cjne  a,#23,k2_add    ;时计数值未到23   
  •           mov   hou,#0          ;时加到23时则清零   
  •           ajmp  back            ;结束   
  • k2_add:   inc   hou             ;时加1               
  • back:     ret                   ;结束   
  • ;--------------------------------------------------------------------------------   
  • time0:                        ;定时器0中断服务程序   
  •          push  psw            ;保护现场   
  •          push  acc  
  •             
  •          inc   cou            ;软计数器加1   
  •          mov   a,cou          ;计数器值送入a   
  •          cjne  a,#100,over    ;未计到100则返回继续计数   
  •          mov   cou,#0         ;计到100后软计数器清零(到1s)   
  •             
  •          inc   sec            ;秒计数器加1(进位10ms*100=1s)   
  •          mov   a,sec          ;秒计数值送入a   
  •          cjne  a,#60,over     ;未计到60则返回继续计数   
  •          mov   sec,#0         ;计到60后秒计数器清零   
  •             
  •          inc   min            ;分计数器加1(进位60s=1m)   
  •          mov   a,min          ;分计数值送入a   
  •          cjne  a,#60,over     ;未计到60则返回继续计数   
  •          mov   min,#0         ;计到60后分计数器清零   
  •             
  •          inc   hou            ;时计数器加1(进位60m=1h)   
  •          mov   a,hou          ;时计数值送入a   
  •          cjne  a,#24,over     ;未计到24则返回继续计数   
  •          mov   hou,#0         ;计到24后时计数器清零,重新计时   
  •             
  • over:    mov   th0,#0xd8      ;重置定时常数   
  •          mov   tl0,#0xf0  
  •          pop   acc            ;恢复现场   
  •          pop   psw  
  •          reti                 ;中断返回   
  • ;--------------------------------------------------------------------------------   
  • time1:                     ;定时器1中断服务程序   
  •          push  psw         ;保护现场   
  •          push  acc  
  •          push  b  
  •                            ;以下是秒计数器值个位十位分开   
  •          mov   a,sec       ;秒计数器值送入a(被除数)   
  •          mov   b,#10       ;除数10送入b   
  •          div   ab  
  •          mov   sec_l,b     ;余数b(秒个位值)送入秒个位存储单元   
  •          mov   sec_h,a     ;商a(秒十位值)送入秒十位存储单元   
  •                            ;以下是分计数器值个位十位分开   
  •          mov   a,min       ;分计数器值送入a(被除数)   
  •          mov   b,#10       ;除数10送入b   
  •          div   ab  
  •          mov   min_l,b     ;余数b(分个位值)送入分个位存储单元   
  •          mov   min_h,a     ;商a(分十位值)送入分十位存储单元   
  •                            ;以下是时计数器值个位十位分开   
  •          mov   a,hou       ;时计数器值送入a(被除数)   
  •          mov   b,#10       ;除数10送入b   
  •          div   ab  
  •          mov   hou_l,b     ;余数b(时个位值)送入时个位存储单元   
  •          mov   hou_h,a     ;商a(时十位值)送入时十位存储单元   
  •             
  •          mov   dptr,#table ;数码管段码表首址送入dptr   
  •             
  •          mov   a,#sec_l    ;取秒个位值的地址   
  •          add   a,dis_r     ;基址+偏移量   
  •          mov   r0,a        ;R0为欲显示值的地址   
  •          mov   a,@r0       ;取欲显示值送入a   
  •                            ; dis_r  :   0     1     2     3     4     5     6     7   
  •                            ;对应单元: sec_l sec_h bar_2 min_l min_h bar_5 hou_l hou_h   
  •          movc  a,@a+dptr   ;取对应值的段码   
  •          mov   p0,a        ;段码送入P0口   
  •          mov   p2,dis_b    ;位码送入P2口   
  •             
  •          inc   dis_r       ;偏移量加1,下次中断时显示下个数   
  •          anl   dis_r,#0x07 ;dis_r增到8时自动清0(使之在0到7间循环)   
  •             
  •          mov   a,dis_b     ;位码循环右移,下次中断时选通下个数码管   
  •          rr    a  
  •          mov   dis_b,a  
  •             
  •          mov   th1,#0xfc   ;重置定时常数   
  •          mov   tl1,#0x18  
  •             
  •          pop   b  
  •          pop   acc         ;恢复现场   
  •          pop   psw  
  •          reti  
  •   
  • d_10ms:  mov   r5,#20      ;1+(1+2*255)*20+2*20=10.261ms@12M   
  • temp1:   mov   r6,#255     ;1+2*255   
  •          djnz  r6,$   
  •          djnz  r5,temp1   
  •          ret  
  •               
  • table:  db 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf ;段码表   
  •          ;   0    1    2    3    4    5    6    7    8    9    -  对应内容   
  •   
  • end 


  • /**************************************************************************  
  • * 标题: 数码管显示电子钟(C语言)  
  • * 作者: wentao     http://blog.liuwentao.net  
  •                    http://wentao.programfan.com  
  • * 日期: 2007.3.3  
  • * 软件: Keil C51 V8.02  
  • * 芯片: AT89X51  
  • * 说明: 实验板实测通过,数码管为8位共阳  
  • * 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!   
  • **************************************************************************/  
  •   
  • #include <reg51.h>   
  • #include <intrins.h>   
  • #define uchar unsigned char   
  •   
  • void delay_ms(uchar ms);  // 延时毫秒@12M,ms最大值255   
  • void key_scan();          // 按键扫描   
  • void key_to();            // 按键处理   
  •   
  • uchar code dis_code[11] = {0xc0,0xf9,0xa4,0xb0,0x99,       //段码表   
  •                           // 0    1    2    3    4         对应内容   
  •                            0x92,0x82,0xf8,0x80,0x90,0xbf};   
  •                           // 5    6    7    8    9    -   
  •   
  • uchar data dis[8];       // dis[0]为秒个位值,dis[1]为秒十位值   
  •                          // dis[2],dis[5]为'-'段码的偏移量   
  •                          // dis[3]为分个位值,dis[4为分十位值   
  •                          // dis[6]为时个位值,dis[7]为时十位值   
  •   
  • uchar data sec = 0;      // 秒计数器(00s-59s)   
  • uchar data min = 0;      // 分计数器(00m-59m)   
  • uchar data hou = 0;      // 时计数器)00h-23h)   
  •   
  • uchar data cou  = 0;     // 软计数器,对10ms时基信号累加到1s   
  •   
  • uchar data dis_b;        // dis_b为位码选通数码管   
  • uchar data dis_r;        // dis_r为取段码时的偏移量   
  •   
  • uchar data key_v = 0;    // 存储键值   
  • uchar data key_t = 0;    // 按键扫描中临时存储键值   
  •   
  • void main()   
  • {   
  •     P2 = 0xff;           // 关所有数码管   
  •     P1 = 0xff;           // p1为准双向口,作输入时先写1   
  •     dis[2] = 10;         // '-'在段码表中偏移量为10   
  •     dis[5] = 10;         // '-'在段码表中偏移量为10   
  •     dis_b = 0x7f;        // 初始选通P2.7口数码管   
  •     dis_r = 0;           // 初始化偏移量为0   
  •        
  •     TMOD = 0x11;         // 定时/计数器0,1工作于方式1   
  •     TH0 = 0xd8;          // 预置定时常数55536(d8f0),产生10ms时基信号   
  •     TL0 = 0xf0;   
  •     TH1 = 0xfc;          // 预置定时常数64536(fc18),产生1ms间隔用于动态显示   
  •     TH1 = 0x18;   
  •     EA = 1;              // 开总中断   
  •     ET0 = 1;             // 定时/计数器0允许中断   
  •     ET1 = 1;             // 定时/计数器1允许中断   
  •     TR0 = 1;             // 开闭定时/计数器0   
  •     TR1 = 1;             // 启动定时/计数器1   
  •     while(1)   
  •     {   
  •         key_t = P1;            // 读入键值   
  •         if(key_t != key_v)     // 键值改变   
  •         {   
  •             delay_ms(10);      // 延时10ms消抖   
  •             key_t = P1;        // 再次读入键值   
  •             if(key_t != key_v) // 键值仍未改变则不是抖动   
  •             {   
  •                 key_v = key_t; // 保存键值   
  •                 key_to();      // 键处理   
  •             }   
  •         }   
  •     }   
  • }   
  • void key_to()                  // 按键处理子程序   
  • {   
  •     if(key_v == 0xef)          // P1.4口键值   
  •     {   
  •         if(min == 59)          // 分计数已加到59   
  •             min = 0;           // 清零之   
  •         else  
  •             min++;             // 否则加1   
  •     }   
  •     else  
  •     {   
  •         if(key_v == 0xdf)      // P1.5口键值   
  •         {   
  •             if(hou == 23)      // 时计数已加到23   
  •                 hou = 0;       // 清零之   
  •             else  
  •                 hou++;         // 否则加1   
  •         }   
  •     }   
  • }   
  • void tiem0(voidinterrupt 1   // T/C0中断服务程序(产生10ms时基信号)   
  • {   
  •     cou++;                     // 软计数器加1   
  •     if(cou == 100)             // 计数值到100(1s)   
  •     {   
  •         cou = 0;               // 软计数器清零   
  •         sec++;                 // 秒计数器加1(进位10ms*100=1s)   
  •         if(sec == 60)          // 秒计数值到60   
  •         {   
  •             sec = 0;           // 秒计数器清零   
  •             min++;             // 分计数器加1(进位60s=1m)   
  •             if(min == 60)      // 分计数到60   
  •             {   
  •                 min = 0;       // 分计数器清零   
  •                 hou++;         // 时计数器加1(进位60m=1h)   
  •                 if(hou == 23)  // 时计数到23   
  •                     hou = 0;   // 时计数器清零   
  •             }   
  •         }   
  •     }   
  •     TH0 = 0xd8;                // 重置定时常数   
  •     TL0 = 0xf0;   
  • }   
  • void time1(voidinterrupt 3   // T/C1中断服务程序(延时1ms数码管动态显示)   
  • {   
  •     dis[0] = sec % 10;         // 秒计数器个位赋绐dis[0]   
  •     dis[1] = sec / 10;         // 秒计数器十位赋绐dis[1]   
  •     dis[3] = min % 10;         // 分计数器个位赋绐dis[3]   
  •     dis[4] = min / 10;         // 分计数器十位赋绐dis[4]   
  •     dis[6] = hou % 10;         // 时计数器个位赋绐dis[6]   
  •     dis[7] = hou / 10;         // 时计数器十位赋绐dis[7]   
  •   
  •     P0 = dis_code[dis[dis_r]]; // 段码送P0口(dis[0]...dis[7])   
  •     P2 = dis_b;                // 位码送P2口   
  •   
  •     dis_r++;                   // 偏移量加1,下次中断时显示下个数   
  •     dis_r &= 0x07;             // dis_r增到8时自动清0(使之在0到7间循环)   
  •        
  •     dis_b = _cror_(dis_b,1);   // 位码循环右移,下次中断时选通下个数码管   
  •   
  •     TH1 = 0xfc;                // 重置定时常数   
  •     TL1 = 0x18;   
  •   
  • }   
  • void delay_ms(uchar ms)       // 延时毫秒@12M,ms最大值255   
  • {   
  •     uchar i;   
  •     while(ms--)   
  •         for(i = 0; i < 124; i++);   
  • }


  • 阅读(8902) | 评论(6)


    版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

    评论

    loading...
    您需要登录后才能评论,请 登录 或者 注册