;************************************************************************** ; 标题: 两位数码管对直控按键计数(汇编) ; 作者: wentao http://blog.liuwentao.net ; http://wentao.programfan.com ; 日期: 2007.3.2 ; 软件: Keil A51 V8.00 ; 芯片: AT89X51 ; 说明: 实验板实测通过,数码管为8位共阳 ; 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途! ;************************************************************************** dis_0 equ 30h ;dis_0(30单元)存储个位值 dis_1 equ 31h ;dis_1(31单元)存储十位值 dis_b equ 32h ;dis_b(32单元)作为位码选通数码管 dis_r equ 33h ;dis_r(33单元)为切换dis_0和dis_1的偏移量 count equ 34h ;count(34单元)为计数器 key_v equ 35h ;key_v(35单元)存储键值 key_t equ 36h ;key_t(36单元)检测键值时临时存储键值 org 0000h ajmp start org 000bh ;定时器0的中断入口地址 ajmp time0 ;跳到定时器0的中断服务程序处 org 0030h start: mov count,#0 ;计数器清0 mov p2,#0xff ;关所有数码管 mov dis_b,#0x7f ;初始选通P2.7口数码管 mov dis_r,#0 ;初始化偏移量为0 mov tmod,#00000001b ;定时/计数器0工作于方式1 mov th0,#0xfc ;预置定时常数64536(fc18) mov tl0,#0x18 setb ea ;开总中断 setb et0 ;定时/计数器0允许中断 setb tr0 ;启动定时/计数器0 lop: lcall key_scan ;调用键扫描子程序 lcall key_to ;调用键处理子程序 ajmp lop ;循环 ;------------------------------------------------------------------------- key_scan: ;键扫描子程序 mov a,p1 ;当前键值送入a mov key_t,a ;存储到临时变量中 xrl a,key_v ;检测键值是否改变 jz key_scan ;未改变则继续扫描 lcall d_10ms ;有键按下则延时10ms消抖 mov a,p1 ;再次读入键值 mov key_t,a ;键值存储到临时变量中 xrl a,key_v ;检测键值是否改变 jz key_scan ;未改变则继续扫描 mov key_v,key_t ;将最终读到的键值存入key_v ret key_to: ;按键处理子程序 mov a,key_v ;读入键值 cjne a,#0xef,next ;不是P1.4口键值则查下一个 ajmp key_1 ;是P1.4口键则转到键处理部分 next: cjne a,#0xdf,back ;也不是P1.5口键值则结束 ajmp key_2 ;是P1.5口键则转到键处理部分 back: ret ;结束 key_1: ;P1.4口键处理部分 inc count ;计数器加1 mov a,count ;计数器值送入a cjne a,#100,over_1 ;未计到100不处理 mov count,#0 ;计到100则清零 over_1: ret key_2: ;P1.5口键处理部分 mov a,count ;计数器值送入a cjne a,#0,over_2 ;计数值不为0 mov count,#99 ;若计数值为0则置为99 ret over_2: dec count ;计数值不为0则减1 ret ;------------------------------------------------------------------------- time0: ;定时器0中断服务程序,用于数码管动态显示(1ms) mov dptr,#table ;段码表首址送入dptr mov a,count ;计数器值送入a(被除数) mov b,#10 ;除数10送入b div ab ;a除以b mov dis_0,b ;余数b(个位值)送入个位存储单元 mov dis_1,a ;商a(十位值)送入十位存储单元 ;以上是将计数值个位十位分开 ;以下是将分开的个位十位分别在两个数码管上显示 mov a,#dis_0 ;个位值的地址送入a add a,dis_r ;基址+偏移量 mov r0,a ;r0为欲显示值的地址 mov a,@r0 ;欲显示值送入a ;(dis_t=0时为dis_0值,dis_t=1时为dis_1值) movc a,@a+dptr ;对应的段码送入a中 mov p0,a ;段码送入P0口 mov p2,dis_b ;位码送入P2口 xrl dis_r,#0x01 ;异或01使偏移量在0和1间切换 xrl dis_b,#0xc0 ;异或c0使位码在7f(P2.7)和bf(P2.6)间循环 mov th0,#0xfc ;重置定时常数64536(fc18) mov tl0,#0x18 reti d_10ms: mov r5,#20 ;1+(1+2*255)*20+2*20=10.261ms@12M temp: mov r6,#255 ;1+2*255 djnz r6,$ djnz r5,temp ret table: db 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90 ;段码表 ; 0 1 2 3 4 5 6 7 8 9 对应内容 end /************************************************************************** * 标题: 两位数码管对直控按键计数(C51) * 作者: wentao http://blog.liuwentao.net http://wentao.programfan.com * 日期: 2007.3.2 * 软件: Keil C51 V8.02 * 芯片: AT89X51 * 说明: 实验板实测通过,数码管为8位共阳 * 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途! **************************************************************************/ #include <reg51.h> #define uchar unsigned char void delay_ms(uchar ms); // 延时毫秒@12M,ms最大值255 void key_scan(); // 按键扫描 void key_to(uchar key_v); // 按键处理 uchar code dis_code[10] = {0xc0,0xf9,0xa4,0xb0,0x99, //段码表 // 0 1 2 3 4 对应内容 0x92,0x82,0xf8,0x80,0x90}; // 5 6 7 8 9 uchar data dis[2]; // dis[0]为个位值,dis[1]为十位值 uchar data dis_b; // 选通数码管的位码 uchar data dis_r; // 个位十位段码切换的偏移量 uchar data count; // 计数器 uchar data key_v; // 存储键值 uchar data key_t; // 扫描按键时临时存储键值 void main() { count = 0; // 计数器清零 P2 = 0xff; // 关所有数码管 dis_b = 0x7f; // 初始选通P2.7口数码管 dis_r = 0; // 初始化偏移量为0 TMOD = 0x01; // 定时/计数器0工作于方式1 TH0 = 0xfc; // 装载定时常数64536(fc18) TL0 = 0x18; EA = 1; // 开总中断 ET0 = 1; // 定时/计数器0允许中断 TR0 = 1; // 启动定时/计数器0 while(1) // 执行主程序,等待中断 { key_scan(); // 扫描按键 key_to(key_v); // 处理按键 } } void key_scan() // 按键扫描 { 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; // 保存键值 break; // 跳出循环结束扫描 } } } } void key_to(uchar key_v) // 按键处理 { if(key_v == 0xef) // 若为P1.4口按键 { count++; // 计数器加1 if(count == 100) // 计到100后清零 count = 0; } else { if(key_v == 0xdf) // 若为P1.5口按键 { if(count == 0) // 若计数器为0则置为99 count = 99; else // 不为0则减1 count--; } } } void time0(void) interrupt 1 // T/C0中断服务程序(延时1ms数码管动态显示) { dis[1] = count / 10; // 计数器十位分离出来赋绐dis[1] dis[0] = count % 10; // 计数器个位分离出来赋绐dis[0] P0 = dis_code[dis[dis_r]]; // 段码送P0口,dis_r=0时为个位dis[0]的值 // dis_r=1时为十位dis[1]的值 P2 = dis_b; // 位码送P2口 dis_r ^= 0x01; // 异或01使偏移量在0和1间切换 dis_b ^= 0xc0; // 异或c0使位码在7f(P2.7)和bf(P2.6)间循环 TH0 = 0xfc; // 重置定时常数 TL0 = 0x18; } void delay_ms(uchar ms) // 延时毫秒@12M,ms最大值255 { uchar i; while(ms--) for(i = 0; i < 124; i++); }

评论