




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、§8.3键盘接口技术一、 键盘输入应解决的问题键盘是一组按键的集合,它是最常用的单片机输入设备操作人员可以通过键盘输入数据或命令,实现简单的人机通讯。键是一种常开型按钮开关,平时(常态)键的二个触点处于断开状态,按下键时它们才闭合(短路)。键盘分编码键盘和非编码键盘。键盘上闭合键的识别由专用的硬件译码器实现并产生编号或键值的称为编码键盘,如:ASC码键盘、BCD码键盘等;靠软件识别的称为非编码键盘。在单片机组成的测控系统及智能化仪器中用得最多的是非编码键盘。本节着重讨论非编码键盘的原理、接口技术和程序设计。键盘中每个按键都是个常开关电路,如图所示。1. 按键的确认: P1.7=1 无
2、按键; P1.7=0 有按键;2. 去抖动 去抖动的方法: 硬件去抖动 采用RS触发器:优点: 速度快,实时, 缺点: 增加了硬件成本 软件去抖动 采用延时方法 延时510ms 延时510ms P1.7=0 确认P1.7=0 P1.7=1(去前沿抖动) (去后沿抖动) 二、 独立式键盘 每个I/O口连接一个按,S1 P1.0S2 P1.1.S8 P1.7 软件: START: MOV P1,#0FFH ;置P1口为高电平JNB P1.0, RS1 ; S1按下,程序去执行RS1JNB P1.1, RS2 ; S2按下,程序去执行RS2JNB P1.2, RS3 ; S3按下,程序去执行RS3J
3、NB P1.3, RS4 ; S4按下,程序去执行RS4JNB P1.4, RS5 ; S5按下,程序去执行RS5JNB P1.5, RS6 ; S6按下,程序去执行RS6JNB P1.6, RS7 ; S7按下,程序去执行RS7JNB P1.7, RS8 ; S8按下,程序去执行RS8AJMPSTART ; 继续扫描按键.RS1:AJMP PK1 ;RS2:AJMP PK2;RS3:AJMP PK3;RS4:AJMP PK4;RS5:AJMP PK5;RS6:AJMP PK6;RS7:AJMP PK7;RS8:AJMP PK8;AJMP START ; 无键按下,继续扫描PK1:. ; 按键
4、S1功能处理程序 AJMP START ; 处理S1按键后, 继续扫描PK2:. ; 按键S2功能处理程序 AJMP START.PK8: ; 按键S8功能处理程序 AJMP START ; 处理S8按键后, 继续扫描优点: 连线简单,程序容易.缺点: 太浪费资源适用于按键较少、I/O口空闲的场合。三、行列式非编码键盘接口方法按键较多时,一般采用行列式键盘.采用扫描方式,软件扫描方式有三种: 程序扫描方式: 当CPU空闲时,扫描键盘,判断有无键按下. 定时扫描方式: 利用CPU的定时器,每隔一定时间扫描一次键盘. 中断扫描方式: 在硬件上采用中断,有键按下时,产生中断, 由中断服务程序来处理.
5、下面是16个按键,构成的4×4键盘行线: 四根,接P1.0-P1.3 列线: 四根,接P1.4-P1.7 程序扫描法原理: P1.0-P1.3输出低电平,读P1.4P1.7,若全为1,无键按下若不全为1,有键按下 在有键按下的情况下,进一步判断是那个键按下判断有无键按下子程序, 程序名: KAP键盘查询子程序KAP:MOV P1,#0F0H ;行线输出低电平,列线输出高电平 MOVA,P1 ;P1口读入ACPL A ;取反ANL A,#0F0H ;RET程序出口: A=0, 则无键按下. A0 则有键按下.去抖动-延时10ms子程序: 程序名D10MSD10MS:MOVR6, #14
6、H;DL:MOV R7,#0FFH; DJNZ R7,$DJNZ R6,DLRETKINP:LCALLKAP; 调键盘查询子程序,JNZKP1; A0,有键按下SJMP END_KINP ; A=0,无键按下,退出按键查询程序KP1:LCALLD10MS;延时10MS,去抖动LCALLKAP;再次查询键盘,JNZKP2; A0,确认有键按下SJMPEND_KINP; A=0,误操作,重新查询KP2为取键值子程序KP2:MOVR2,#0FEH; R2为行扫描值MOVR4,#00H; R4初值为第0行行首键号CLRF0; F0=0表示正在扫描键盘KP4:MOV P1,R2; 扫描行为低MOV A,
7、P1; 读P1JBACC.4, L1; 第0列不为低,则检查第1列MOVA,#00H; 为低,则行首键值送入AAJMPKP5; KP5L1:JB ACC.5,L2; 检查第一列MOVA,#04H; 第一列行首键值送入AAJMPKP5L2:JB ACC.6 ,L3; 检查第二列MOVA,#08H; 第二列行首键值送入AAJMPKP5L3:JB ACC.7 , NEXT; 检查第三列,若为1,则检查下一行MOVA,#0CH; 第三列行首键值送入AKP5:ADDA , R4; A A+R4,键值调整PUSHA; KP3:LCALLD10MS; 后沿去抖动LCALLKAP; 查询按键是否释放JNZKP
8、3; A0 未释放,继续查询POPA; 键已释放,弹出键值RETNEXT:INCR4; 下一列,行键值加1MOV A ,R2; 取扫描值JNB ACC.3,END_KINP; 判断扫描是否结束?RLA; 下一个扫描值MOVR2,A;AJMP KP4 ; END_KINP:SETB F0RET51单片机电子日历(电子时钟)程序 2007-08-03 21:01:05| 分类: 默认分类|字号 订阅程序代码:/*/* 电子日历,有时间显示、闹铃、日期、秒表及键盘设
9、置功能 */* 功能键A: 设置位数字+1 闹钟模式下为闹钟开关 秒表模式下为记时开关 */* 功能键B: 设置位数字-1 闹钟模式下为闹钟开关
10、 */* 功能键C:设置模式及设置位选择 秒表模式下为清零键 */
11、60; /* 功能键D:在四种工作模式下切换 设置闹钟开关
12、160; */ /*/#include#include/*这里设置程序初始化时显示的时间*/#define SET_HOUR 12 /*设置初始化小时*/#define SET_MINUTE 00 /*设置初始化分钟*/#define SET_SECOND 00 /*设置初始化秒数*/*系统地址*/#define BASE_PORT 0x8000 /*选通基地址*/#define
13、 KEY_LINE BASE_PORT+1 /*键盘行线地址*/#define KEY_COLUMN BASE_PORT+2 /*键盘列线地址*/#define LED_SEG BASE_PORT+4 /*数码管段选地址*/#define LED_BIT BASE_PORT+2 /*数码管位选地址*/#define LED_ON(x) XBYTELED_BIT=(0x01<<x) style="line-height: 25px; ">#define LED_OFF XBYTELED_SEG=0x00
14、160; /*LED显示空*/</x) >/*在设置模式下对秒分时的宏定义*/#define SECOND 0 /*对应数码管右边两位*/#define MINUTE 1 /*对应数码管中间两位*/#define HOUR 2 /*对应数码管左边两位*/*定义四种工作模式*/#define CLOCK clockstr /*时钟模式*/#define ALART alartstr /*闹钟模式*/#define DATE datestr /*日
15、期模式*/#define TIMER timerstr /*秒表模式*/*以下是所有子函数的声明*/void sys_init(void); /*系统的初始化程序*/void display(void); /*动态刷新一次数码管子程序*/void clockplus(void); /*时间加1S的子程序
16、*/void update_clockstr(void); /*更新时间显示编码*/void update_alartstr(void); /*更新闹钟时间的显示编码*/void update_datestr(void); /*更新日期显示编码*/void update_timerstr(void); &
17、#160; /*更新秒表时间的显示编码*/void deley(int); /*延时子程序*/void update_dispbuf(unsigned char *); /*更新显示缓冲区*/unsigned char getkeycode(void); /*获取键值子程序*/void keyprocess(unsigned char); /*键值处理子程序*/unsigned char getmonthdays(unsigned int,unsigned char);/*计算某
18、月的天数子程序*/*功能键功能子函数*/void Akey(void); /*当前设置位+1 开关闹钟 开关秒表*/void Bkey(void); /*当前设置位-1 开关闹钟 */void Ckey(void); /*设置位选择 秒表清零*/void Dkey(void); /*切换四种工作模式*/*全局变量声明部分*/unsigned char led10=0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07
19、,0x7F,0x6F;/*从09的LED编码*/unsigned char ledchar3=0x5c,0x54,0x71;/*o n f*/unsigned char key24= /* 键值代码数组 对应键位:*/ 0x70,0x71,0x72,0x73,0x74,0x75, /* 7 8 9 A TRACE RESET*/ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5, /* 4 5 6 B STEP
20、60; MON */ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5, /* 1 2 3 C HERE LAST */ 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5; /* 0 F E D EXEC NEXT */struct /*时间结构体变量*/ unsigned char s; unsigned cha
21、r m; unsigned char h; clock=SET_SECOND,SET_MINUTE,SET_HOUR;struct /*闹铃时间结构体变量*/ unsigne
22、d char m; unsigned char h; alart=SET_MINUTE,SET_HOUR;struct /*日期结构体变量*/
23、60; unsigned int year; unsigned char month; unsigned char day; date=6,1,1;struct
24、0; /*秒表时间结构体变量*/ unsigned char ms; unsigned char s; unsigned char
25、m; timer=0,0,0;unsigned char dispbuf6; /*显示缓冲区数组*/unsigned char clockstr6; /*时间显示的数码管编码数组*/unsigned char alartstr6; /*闹钟显示的数码管编码数组*/unsigned char datestr6; /*日期显示的数码管编码数组*/unsigned char timerstr6; /*秒表显示的数码管编
26、码数组*/unsigned int itime=0,idot; /*定时器0中断计数*/unsigned char itime1=0; /*定时器1中断计数*/sbit P3_1=P31; /*外接蜂鸣器的管脚*/bdata bit IsSet=0; /*设置模式标志位:正常走时 :设置模式*/bdata bit Alart_EN=0; /*闹铃功能允许位 :禁止闹铃 :允许闹铃*/bdata bit IsBeep=0;
27、160; /*响铃标志位 :未响铃 :正在响铃*/unsigned char SetSelect=0; /*在设置模式IsSet=1时,正在被设置的位,对应上面的宏*/unsigned char *CurrentMode; /*标志当前正设置的功能,如CurrentMode=CLOCK或CurrentMode=ALART等*/void timerplus(void);/*函数部分*/void main(void)
28、60; sys_init(); while(1) XBYTEKEY_COLUMN,0x00; /*给键盘列线赋全零扫描码,判断是否有键按下 */ while(XBYTEKEY_LINE&0x0f)=0x0f) /*检测是否有键按下,无则一直进行LED的刷新显示*/
29、 if(Alart_EN&&(clock.h=alart.h)&&(clock.m=alart.m) IsBeep=1; &
30、#160; else IsBeep=0; P3_1=0;
31、160; display(); keyprocess(getkeycode(); /*有键按下时得到键值,并送入键值处理程序*/ display();
32、0; /*可要可不要*/ void sys_init(void) TMOD=0x22; /*定时器0和1都设置为工作方式2,基准定时250×2500us=0.5ms*/ TH0=6; /*定时器0中断服务用来产生1秒时钟定时及闹钟蜂鸣器蜂鸣脉冲*/ TL0=6; /*定时器1中断服务留给
33、秒表使用,产生1/100秒定时*/ TH1=6; TL1=6; ET0=1; ET1=1; EA=1; TR0=1;
34、60; update_clockstr(); /*初始化时钟显示编码数组*/ update_alartstr(); /*初始化闹钟显示编码数组*/ update_datestr(); /*初始化日期显示编码数组*/ &
35、#160; update_timerstr(); /*初始化秒表显示编码数组*/ update_dispbuf(clockstr);/*初始化显示缓冲数组*/ CurrentMode=CLOCK; /*默认的显示摸式为时钟*/ &
36、#160; P3_1=0; /*蜂鸣器接线引脚复位*/void timer0(void) interrupt 1 using 1 /*定时器0中断服务器,用来产生1秒定时*/ itime+; if(itime=1000)
37、 if(IsSet) /*在设置模式下,对正在设置的位闪烁显示*/ dispbufSetSelect*2=0; /*对正在设置的位所对应的显示缓冲区元素赋0,使LED灭
38、*/ dispbufSetSelect*2+1=0; if(IsBeep) P3_1=!P3_1; /*闹钟模式时,产生
39、峰鸣器响脉冲*/ if(CurrentMode=CLOCK)
40、; dispbuf2=dispbuf2&0x7f; dispbuf4=dispbuf4&0x7f;
41、60; if(itime=2000) /*两千次计数为1S 2000×0.5ms=1s*/ itime=0; /*定时1s时间到,软计数清零*/ clockplus(); /*时间结构体变量秒数加1 */ update_clockstr(); /* 更新时间显示编码数组 */
42、; if(CurrentMode!=TIMER) update_dispbuf(CurrentMode); /* 用时间编码数组更新显示缓冲区 */ void timer1(void) interrupt 3 using 2 /*定时器1中断服务器,用来产生1/100秒定时*/ idot+; if(+itime1=20) /*20*0.5ms=10ms*
43、/ itime1=0; timerplus(); update_timerstr(); if(CurrentMode=TIMER)
44、 update_dispbuf(timerstr); dispbuf2=dispbuf2&0x7f; /*关闭小数点的显示*/ dispbuf4=dispbuf4&0x7f; if(idot<1
45、000) /*闪烁显示小数点*/ dispbuf2=dispbuf2|0x80; &
46、#160; dispbuf4=dispbuf4|0x80; else dispbuf2=dispbuf2&0x7f;
47、0; dispbuf4=dispbuf4&0x7f; if(idot=2000) idot=0;/*功能模块子函数*/vo
48、id clockplus(void) /*时间加1s判断分,时子函数*/ if(+clock.s=60) /*秒位判断*/ clock.s=0; if(+clock.m=60) /*分位判断*/ clock.m=0; if(+clock.h=24) /*时位判断*/ clock.h=0;
49、 if(+date.day=(getmonthdays(date.year,date.month)+1) date.day=1; if(+date.month=13) date.
50、month=1; void timerplus() /*秒表1/100秒位加1,判断秒、分子程序*/ if(+timer.ms=100) timer.ms=0;
51、0; if(+timer.s=60) timer.s=0; if(+timer.m=60) &
52、#160; timer.m=0; void update_clockstr(void) /*更新时钟显示代码数组clockstr*/ clockstr0=ledclock.s%10;
53、; /*给元素0赋相应数码管显示编码,编码序号是秒数的个位*/ clockstr1=led(int)(clock.s/10); /*给元素1赋相应数码管显示编码,编码序号是秒数的十位*/ clockstr2=ledclock.m%10; /*以下类推*/ clockstr3=led(int)(clock.m/10); clockstr4=ledclock.h%10; clockstr5=led(int)(clock.h/10);void update_alartstr(void)
54、 /*更新闹钟显示代码数组alartstr*/ /*右边两位显示on:闹钟开启 of:闹钟关闭*/ if(A
55、lart_EN) alartstr0=ledchar1;/*显示字母n*/ else alartstr0=ledchar2; /*显示字母f*/ alartstr1=ledchar0; /*显示字母o*/
56、 alartstr2=ledalart.m%10; alartstr3=led(int)(alart.m/10); alartstr4=ledalart.h%10; alartstr5=led(int)(alart.h/10);void update_datest
57、r(void) /*更新日期显示代码数组datestr*/ datestr0=leddate.day%10; datestr1=led(int)(date.day/10); datestr2=leddate.month%10; &
58、#160; datestr3=led(int)(date.month/10); datestr4=leddate.year%10; datestr5=led(int)(date.year/10);void update_timerstr(void) /*更新秒表显示代码数组timerstr*/
59、60; timerstr0=ledtimer.ms%10; timerstr1=led(int)(timer.ms/10); timerstr2=ledtimer.s%10; timerstr3=led(int)(timer.s/10);
60、timerstr4=ledtimer.m%10; timerstr5=led(int)(timer.m/10);void display(void) /*刷新显示六位LED一次*/ unsigned char i; for(i=0;i<6;i+) LED_ON(i); /*选通相应位*/ XBYTELED_SEG=
61、dispbufi; /*写显示段码*/ deley(50); /*延时显示*/ LED_OFF; /*写LED全灭段码*/ void update_dispbuf(unsigned char *str) /*更新显示缓冲区子函数,参数为要用来更新缓冲区的源字符数组的首地址*
62、/ dispbuf0=str0; /*将要更新的源字符数组内容COPY至dispbuf数组,用作显示缓冲区*/ dispbuf1=str1; dispbuf2=str2|0x80; /*默认把时位和分位后面的小数点显示出来,根据需要再取舍*/ dispb
63、uf3=str3; dispbuf4=str4|0x80; dispbuf5=str5;void deley(int i) /*延时子函数*/ while(i-);unsigned char getkeycode(void) /*键盘扫描子程序,返回获得的键码*/ unsigned char keycode; /*键码变量,一开始存行码*/ u
64、nsigned char scancode=0x20; /*列扫描码*/ unsigned char icolumn=0; /*键的列号*/ display(); /*用刷新数码管显示的时间去抖*/
65、; XBYTEKEY_COLUMN=0x00; keycode=XBYTEKEY_LINE&0x0f; /*从行端口读入四位行码*/ while(scancode&0x3f)!=0) /*取scancode的低六位,只要没变为全0,则执行循环*/ XBYTEKEY_COLUMN=(scancode)&0x3f; /*给列赋扫描码,第一次为011111*/ if(XBYTEKEY_LINE&0x0f)=keyco
66、de) break; /*检测按键所在的列跳出循环*/ scancode=scancode>>1; /*列扫描码右移一位*/ icolumn+; /*列号加1*/ keycode=keycode<<4; /*把行码
67、移到高四位*/ keycode=keycode|icolumn; /*由行码和列码组成键码*/ /等待按键放开 XBYTEKEY_COLUMN=0x00; while(XBYTEKEY_LINE&0x0f)!=0x0f) display(); return keycode;void keyprocess(unsigned char keycode) /*键值处理函数*/ switch (keycode) case 0x73: Akey();
68、; break; case 0xB3: Bkey(); break; case 0xD3: Ckey(); break; case 0xE3: Dk
69、ey(); break; default: break; update_dispbuf(CurrentMode);unsigned char ge
70、tmonthdays(unsigned int year,unsigned char month)/*得到某月的天数*/ unsigned char days; switch (month) case 4: case 6: case 9: case 11:days=30; break; case 2: if(year%4=0) days=29; else days=28;&
71、#160; break; default:days=31; break; return days;/*功能键子函数部分*/void Akey(void) /*对当前设置位进行加一操作,如果设置秒位,则给秒位清零*/ if(CurrentMode=TIMER)
72、; /*秒表模式下启闭走时*/ TR1=!TR1; return; if(!IsSet) return; /*如果不是设置模式退出*/ switch (SetSelect)
73、0; case SECOND:if(CurrentMode=CLOCK)
74、 clock.s=0; /*如果当前被设置位是秒位,则清零秒位*/ update_clockstr();
75、60; if(CurrentMode=ALART)
76、0; Alart_EN=!Alart_EN;&
77、#160; update_alartstr();
78、 if(CurrentMode=DATE)
79、160; if(+date.day=(getmonthdays(date.year
80、,date.month)+1) date.day=1; update_datestr();
81、60; if(CurrentMode=TIMER)
82、0; TR1=!TR1
83、;
84、0; break; case MINUTE:if(CurrentMode=CLOCK)
85、; if(+clock.m=60) clock.m=0; /*如果当前被设置分位,则分位加1*/ update_clockstr();
86、 if(CurrentMode=ALART) &
87、#160;
88、 if(+alart.m=60) alart.m=0; update_alartstr();
89、160; if(CurrentMode=DATE)
90、0; if(+date
91、.month=13) date.month=1; update_datestr();
92、 break; case HOUR: if(CurrentMode=CLOCK)
93、160; &
94、#160; if(+clock.h=24) clock.h=0; /*如果当前被设置时位,则时位加1*/ update_clockstr(); &
95、#160; if(CurrentMode=ALART)
96、60; if(+alart.h=24) alart.h=0;
97、; update_alartstr();
98、60; if(CurrentMode=DATE)
99、 if(+date.year=100) date.year=0;
100、60; update_datestr();
101、160; break; default: break; update_dispbuf(CurrentMode);void Bkey(void) /*对当前
102、设置位进行减一操作,如果设置秒分,则给秒位清零,类比Akey()函数*/ if(!IsSet) return; switch (SetSelect) case SECOND:if(CurrentMode=CLOCK)
103、160; clock.s=0; update_clockstr(); &
104、#160;
105、 if(CurrentMode=ALART) &
106、#160; Alart_EN=!Alart_EN; update_alartstr();
107、0; if(CurrentMode
108、=DATE)
109、; if(-date.day=0x00) date.day=getmonthdays(date.year,date.month); update_datestr(); &
110、#160; break; case MINUTE:if(CurrentMode=CLOCK)
111、160; if(-clock.m=0xff) clock.m=59;&
112、#160; update_clockstr();
113、; if(CurrentMode=ALART)
114、 if(-alart.m=0xff) alart.m=59;
115、 update_alartstr();
116、0; if(CurrentMode=DATE)
117、 if(-date.month=0x00) date.month=12;
118、 update_datestr(); break; case HOUR: if(CurrentM
119、ode=CLOCK) &
120、#160; if(-clock.h=0xff) clock.h=23; update_clockstr();
121、; if(CurrentMode=ALART)
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 大学生创业火锅店实施流程
- 补漏保温合同协议书
- 养老院内部承包协议书
- 钢架焊接技术协议书
- 酒后损坏和解协议书
- 农村安置房包销协议书
- 金矿合伙投资协议书
- 呼吸道慢病管理
- 健身俱乐部转让协议书
- 酒店结婚转让协议书
- 环卫承包协议
- 运输企业安全生产责任制制度
- 医院护理培训课件:《安全注射》
- 医疗器械劳动合同范本
- 数字华容道-1课时
- 2024-2029年中国醇类燃料行业深度调研及投资前景预测研究报告
- 相约劳动智慧树知到期末考试答案章节答案2024年陕西铁路工程职业技术学院
- 小儿手术患者的心理护理
- MOOC 人工智能:模型与算法-浙江大学 中国大学慕课答案
- 奇异的仿生学智慧树知到期末考试答案2024年
- 2024年国家义务教育质量监测心理健康和德育考试试题及答案
评论
0/150
提交评论