;************************************************************************** ; 标题: 秒表-六位数码管有效显示(汇编) ; 作者: wentao http://blog.liuwentao.net ; http://wentao.programfan.com ; 日期: 2007.3.2 ; 软件: Keil A51 V8.00 ; 芯片: AT89X51 ; 说明: 实验板实测通过,数码管为8位共阳 ; 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途! ;************************************************************************** dot_l equ 30h ;30单元存储百分之一秒值 dot_h equ 31h ;31单元存储十分之一秒值 bar_2 equ 32h ;32单元存储"-"段码的偏移量 sec_l equ 33h ;33单元存储秒个位值 sec_h equ 34h ;34单元存储秒十位值 bar_5 equ 35h ;35单元存储"-"段码的偏移量 min_l equ 36h ;36单元存储分个位值 min_h equ 37h ;37单元存储分十位值 dot equ 38h ;38单元为百分之一秒计数器(0.00s-0.99s) sec equ 39h ;39单元为秒计数器(00s-59s) min equ 40h ;40单元为分计数器(00m-99m) dis_b equ 41h ;dis_b(41单元)作为位码选通数码管 dis_r equ 42h ;dis_r(42单元)为取段码时的偏移量 key_t equ 43h ;43单元为键按下的次数标记 K bit p1.4 ;K键与P1.4相连 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 bar_2,#10 ;'-'段码偏移量为10 mov bar_5,#10 ;'-'段码偏移量为10 mov dis_b,#0x7f ;初始选通P2.7口数码管 mov dis_r,#0 ;初始化偏移量为0 mov dot,#0 ;百分之一秒计数器清零 mov sec,#0 ;秒计数清零 mov min,#0 ;分计数清零 mov key_t,#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允许中断 clr tr0 ;关定时/计数器0 setb tr1 ;开定时/计数器1 lop: jb K,lop ;键(P1.4)未按下则返回 lcall d_10ms ;延时10ms消抖 jb K,lop ;是抖动则返回重新扫描 jnb K,$ ;等待键松开 lcall key_to ;调用键处理部分 ajmp lop ;循环显示 key_to: ;键处理子程序 inc key_t ;键按下次数加1 mov a,key_t ;按下次数送入a cjne a,#1,key_2 ;不是1次继续检测是否是第2次 setb tr0 ;第1次按下启动定时器0 ret key_2: cjne a,#2,key_3 ;也不是2次继续检测是否是第3次 clr tr0 ;第2次按下关闭定时器0 ret key_3: cjne a,#3,back ;也不为3则结束 mov dot,#0 ;第3次按下将三个计数器清零 mov sec,#0 mov min,#0 mov key_t,#0 ;按键次数清零 back: ret ;-------------------------------------------------------------------------------- time0: ;定时器0中断服务程序 push psw ;保护现场 push acc inc dot ;百分之一秒计数器加1 mov a,dot ;计数器值送入a cjne a,#100,over ;未计到100则返回继续计数 mov dot,#0 ;计到100后清零 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,#100,over ;未计到100则返回继续计数 mov min,#0 ;计到100后分计数器清零,重新计时 over: mov th0,#0xd8 ;重置定时常数 mov tl0,#0xf0 pop acc ;恢复现场 pop psw reti ;中断返回 ;-------------------------------------------------------------------------------- time1: ;定时器1中断服务程序 push psw ;保护现场 push acc push b ;以下是百分之一秒计数器值个位十位分开 mov a,dot ;百分之一秒计数器值送入a(被除数) mov b,#10 ;除数10送入b div ab ;a除以b mov dot_l,b ;余数b(百分之一秒值)送入百分之一秒存储单元 mov dot_h,a ;商a(十分之一秒值)送入十分之一秒存储单元 ;以下是秒计数器值个位十位分开 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 dptr,#table ;数码管段码表首址送入dptr mov a,#dot_l ;取百分之一秒值的地址 add a,dis_r ;基址+偏移量 mov r0,a ;R0为欲显示值的地址 mov a,@r0 ;取欲显示值送入a ; dis_r : 0 1 2 3 4 5 6 7 ;对应单元: dot_l dot_h bar_2 sec_l sec_h bar_5 min_l min_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 /************************************************************************** * 标题: 秒表-六位数码管有效显示(C51) * 作者: 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 dot = 0; // 百分之一秒计数器(0.00s-0.99s) uchar data sec = 0; // 秒计数器(00s-59s) uchar data min = 0; // 分计数器(00m-99m) uchar data dis_b; // dis_b为位码选通数码管 uchar data dis_r; // dis_r为取段码时的偏移量 uchar data key_t = 0; // 按键次数,初始为0 sbit K = P1^4; // K键与P1.4相连 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 = 0; // 关闭定时/计数器0 TR1 = 1; // 启动定时/计数器1 while(1) { if(K != 1) // 有键按下 { delay_ms(10); // 延时10ms去抖 if(K != 1) // 确定是有键按下 { while(K != 1); // 等待键松开 key_to(); // 按键处理 } } } } void key_to() // 按键处理子程序 { key_t++; // 按键次数加1 if(key_t == 1) // 第一次按下 TR0 = 1; // 启动定时器0 else { if(key_t == 2) // 第二次按下 TR0 = 0; // 关闭定时器0 else { if(key_t == 3) // 第三次按下 { dot = 0; // 三个计数器清零 sec = 0; min = 0; key_t = 0; // 按键次数清零 } } } } void tiem0(void) interrupt 1 // T/C0中断服务程序(产生10ms时基信号) { dot++; // 百分之一秒计数器加1 if(dot == 100) // 计数值到100 { dot = 0; // 清零 sec++; // 秒计数器加1(进位10ms*100=1s) if(sec == 60) // 秒计数值到60 { sec = 0; // 秒计数器清零 min++; // 分计数器加1(进位60s=1m) if(min == 100) // 分计数到100 min = 0; // 分计数器清零 } } TH0 = 0xd8; // 重置定时常数 TL0 = 0xf0; } void time1(void) interrupt 3 // T/C1中断服务程序(延时1ms数码管动态显示) { dis[0] = dot % 10; // 百分之一秒计数器个位分离出来赋绐dis[0] dis[1] = dot / 10; // 百分之一秒计数器十位分离出来赋绐dis[1] dis[3] = sec % 10; // 秒计数器个位赋绐dis[3] dis[4] = sec / 10; // 秒计数器十位赋绐dis[4] dis[6] = min % 10; // 分计数器个位赋绐dis[6] dis[7] = min / 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++); }

评论