正文

【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(void) interrupt 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(void) interrupt 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++);    }

阅读(13700) | 评论(6)


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

评论

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