完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一般的按键查询法有2种:
(1)把键盘程序放在主程序的while(1)循环里不停的查询。 (2)为防漏键,将按键程序放在定时器0的中断服务程序里,约每10ms中断一次;其返回键值赋给一个全局变量key_value,然后在主函数里将根据key_value的值来做出相应的动作! 分析上述两种方法:对于第一种方法,如果主程序特别长且很消耗时间,那么很可能出现按键漏扫的情况,不可靠。第二种情况是每隔段时间就去扫描下按键,理论上和主程序的while(1)循环里代码是否长和消耗时间应该无关,应该是很可靠的一种按键扫描方法!但事实就不是这样,下面请看代码,很简单的哦~ //用定时器中断扫描矩阵键盘程序 #include #define s8 signed char #define u8 unsigned char #define u16 unsigned int #define u32 unsigned long int //#define PORT P1 //共阳极不带小数点 u8 code segment[] = {0XC0, 0XF9, 0XA4, 0XB0, 0X99, 0X92, 0X82, 0XF8, 0X80, 0X90, 0X88, 0X83, 0XC6, 0XA1, 0X86, 0X8E}; u8 code position[] = {0XFE,0XFD,0XFB,0XF7,0XEF,0XDF,0XBF,0X7F,0X00,0XFF};u8 key_value = 20u;//u表示无符号整型 u16 tmr0_value = 10000u; void rough_delay_1ms(u16); void digitron_static_display(u8, u8); void init_tmr0(void); u8 scan_MatrixKey(void); int main(void) { init_tmr0();//初始化定时器0 while (1) { //用7段数码管将矩阵键盘的键值显示出来 digitron_static_display(key_value, 8);//8表示位选全开 //此处延时后按键就不灵敏了,注销延时则按键很灵敏 rough_delay_1ms(20);// } return 0; } //翻转扫描法 u8 scan_MatrixKey(void) { //为了不分散大家注意力,此处的代码就省略了! } //初始化定时器0 void init_tmr0(void) { TMOD = 0x01;//设置tmr0为工作方式1 EA = 1;//开总中断 ET0 = 1;//开定时器0中断 TH0 = (65535u - tmr0_value) >> 8;//得到高8位 TL0 = (65536u - tmr0_value) & 0x00ff;//得到低8位 TR0 = 1;//启动定时器0 return; } //注:定时器溢出后若没重装初值就重新从0开始计数(0—65535) //计数到65536就溢出! void tmr0(void) interrupt 1//定时器0中断 { TR0 = 0;//关闭定时器0 //重新给定时器0赋初值 TH0 = (65536u - tmr0_value) >> 8; TL0 = (65536u - tmr0_value) & 0x00ff; key_value = scan_MatrixKey();//扫描矩阵键盘 TR0 = 1;//启动定时器0 return; } //数码管静态显示函数(i对应段选,j对应位选) void digitron_static_display(u8 i, u8 j) { if (i>=0 && i<=15u)//过滤除键值以外的数值 { P0 = segment; P2 = position[j]; } return; } void rough_delay_1ms(u16 t)//粗略延时t毫秒 { u16 i; for (; t>0; --t) { for (i=115u; i>0; --i); } return; } 现象:注销主程序里的while(1)循环里的延时后,按键非常灵敏,很难出错!但延时20ms后,按 按键 就经常没反应,有时要按好几次才有反应;延时100ms的话,按键几乎就很难有反应了,按半天都没动静! 困惑:理论上,用定时器定期扫描的方法应该和主程 while(1)循环里的代码无关呀,这种异常现象是怎么回事呀?急求高人解答啊! |
|
相关推荐
16个回答
|
|
给的程序不全,没办法分析
我现假设scan_MatrixKey()这个函数返回值在没有按键按下去时返回0,或者其他一个固定值,当你在WHILE(1)中加延时超过或接近定时器刷新按键时间时,按键就会不灵敏,这是正常现像, 假设你在WHILE(1)中延时100ms,则在延时这100ms过程中,定时器中断了10次左右。假设在没有按键按下去时scan_MatrixKey()返回值为20,则除非在最后一次中断你按下按键,在其他时间按下按键都回返回20, 不知我写的你看明白了没。 |
|
|
|
//行(列)扫描法
u8 scan_MatrixKey(void) { #define ORT 1//可以增强程序的可移植性 u8 row; u8 column = 20;//初始值不能为0到15(因为0到15为键值) u8 temp; u8 MatrixKey_value = 20; //使矩阵键盘的四行键依次置0时的P1口值 u8 code set_key_row[] = {0XF7,0XFB,0XFD,0XFE}; //0到15号键依次被按下时P1口分别对应的值 u8 code scan_key_column[] = {0XE7,0XD7,0XB7,0X77,0XEB,0XDB,0XBB,0X7B, 0XED,0XDD,0XBD,0X7D,0XEE,0XDE,0XBE,0X7E}; for (row=0; row<4; ++row)//使矩阵键盘的四行键依次置0 { PORT = set_key_row[row]; temp = ORT;//row为0时若键0所在行有键按下,则PORT口的值会发生变化 temp = temp & 0XF0;//可以判断PORT口的值是否发生变化 if (temp != 0XF0) { rough_delay_1ms(10);//按下去抖延时(可调) //temp在上次被赋PORT的值后就始终存的上次PORT的值 //故要判断PORT值是否变化就得对temp再次赋PORT的值 temp = ORT; temp = temp & 0XF0; if (temp != 0XF0) { //此时就得检测具体是哪个键被按下了 //每行按键置0一次都得对4列按键各扫描一次,共4行故得扫描16次 for (column=0; column<16; ++column) { //任意键被按下都会使PORT对应scan_key_column[]中的某个值 //例如按下某键时PORT=0XE7,则column必为0,则按下的是0号键 if (scan_key_column[column] == ORT) { while (scan_key_column[column] == ORT);//按键的松手检测 rough_delay_1ms(5);//松手去抖延时(可调) while (scan_key_column[column] == ORT);//再次确认是否松手 MatrixKey_value = column;//此时的column为按键键值 break; } } } } } return MatrixKey_value; } |
|
|
|
你看 我的键盘程序在没有按键按下时 返回的是20
|
|
|
|
那就对了呀,所以你会发现按键不灵敏!你可以把返回值20改为返回0-15之间的任意值,烧进去再看看,是不是当发现不灵敏时显示的是一个固定值,或两个值闪一下。
|
|
|
|
嗯 你回答的太好了,就是你说的意思,如果延时过长的话,定时器的多次中断重新刷新了key_value的值,导致那次按键无效!
看来你的基本功很扎实啊 呵呵 !顺便问下 你对用lcd12864做多级菜单了解不?或者了解ucgui不? |
|
|
|
“你可以把返回值20改为返回0-15之间的任意值,烧进去再看看” 不是这样的,只需要把u8 MatrixKey_value = 20;前加个static就好了哦 呵呵!这样就避免了被多次的中断更新了key_value的值 哈哈
|
|
|
|
多级菜单了解,UCGUI也会用,不过也有很长时间没有用了,主要是工作中不常用,有点生疏了。
|
|
|
|
能加你QQ吗?诚心向你学习!可以短息告诉我 呵呵
|
|
|
|
我的QQ1982211588
|
|
|
|
|
|
|
|
|
|
|
|
不灵 是因为主函数的延时时间大于键盘的扫描时间,当此次按键的键值还未发生作用,又迎来了下次扫描,就将键值改成了初始值,这样此次按键 就白按了,故只需将存放键值的变量改为静态或全局的 就可以保存此次的键值直到下次按键被按下才能更新键值
|
|
|
|
我一般是把按键扫描放到while里,显示放到中断
|
|
|
|
|
|
|
|
各位 写个队列 就可以很好的解决问题了啊
|
|
|
|
其实感觉按键扫描不应该放在中断里,因为按键扫描涉及到按键的检测,按键的消抖,以及按键的释放,这里都有延时的操作,这样会降低中断的效率,也有可能会影响到其他的程序,所以按键扫描应该放到主程序的循环,动态数码管的扫描显示需要高的实时能力,所以数码管的显示应该放在定时器中断里。
|
|
|
|
只有小组成员才能发言,加入小组>>
3288 浏览 9 评论
2962 浏览 16 评论
3465 浏览 1 评论
9010 浏览 16 评论
4054 浏览 18 评论
1127浏览 3评论
579浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
573浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2306浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1864浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-30 15:30 , Processed in 1.751995 second(s), Total 110, Slave 91 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号