说到单片机入门,很多小伙伴都是从郭天祥的《新概念51单片机C语言教程--入门提高开发拓展全攻略》这本书入门,郭天祥书中的按键扫描程序是用延时来进行软件消抖,后面在网络上学习了“MCU起航”的按键扫描程序的正规用法后,将状态机与按键扫描给融合进来进行使用。总结一下,日后可以方便回顾知识和能给一些需要的朋友提供思路参考一下。
if(KEY == 0) //如果按键被按下 { delay_ms(10); //延时一段时间 if(KEY == 0) { LED = ~LED; //LED状态翻转 while(KEY == 0); //key被按下低电平,一直在这儿等待,等再次按下再退出这个状态 } 郭天祥书中的按键检测程序基本流程是
1.检测按键是否被触发
2.延时消抖
3.再次检测确实被触发
4执行功能
5.等待按键释放
先给大家介绍一下什么是状态机?
简单讲就是一组状态,各个状态之间,依据一定的条件,(如输入一个1 或者是 0)存在一定的转换,(从状态X转换到状态Y)。
接下来按键检测这个程序来结合状态机实际程序来说明
/*************************************************** * 定时器0初始化函数,16位定时器 * 约2ms溢出一次,开启溢出中断 ****************************************************/ void timer0_init(void) { TMOD = 0x01; //模式设置,0b0000 0001,定时器0,工作于模式1 16位(M1=0,M0=1) ET0 = 1; //开定时器0中断 TH0 = 0xf8; //定时器溢出值设置,每隔2ms发起一次中断。 TL0 = 0xcb; TR0 = 1; //定时器0开始计时 EA = 1; //开总中断 } 先初始化化定时器的配置,设置成2ms作为系统的时钟节拍。
如果其他程序也需要计时,判断进入2ms中断的累计次数就可以获取时间;
/*************************************************** * 中断子程序,每2ms中断一次 * cnt_2ms加一,同时给TH0和TL0赋初值 ****************************************************/ void time0() interrupt 1 { static unsigned char cnt_2ms = 0; TH0 = 0xf8; //定时器溢出值设置,每隔2ms发起一次中断。 TL0 = 0Xcb; cnt_2ms++;; //该计数单元数值加一 if(cnt_2ms == 5) //调用按键扫描子函数 { cnt_2ms = 0; key_scan(); } } 中断函数,每2ms进入一次中断,按键扫描函数10ms扫描一次,即累计5次进入一次扫描 /*************************************************** * 按键扫描子函数,状态机方式 * 约10ms调用一次本函数,10ms的间隔起到去抖的效果 ****************************************************/ void key_scan(void) { static unsigned char state_cnt = 0; //switch语句的状态变量,局部静态变量 switch(state_cnt) { case 0x00: if(KEY == 0) //有按键被按下 { state_cnt = 0x01; break; } case 0x01: if(KEY == 0) //确实被按下 { state_cnt = 0x02; LED =~LED; //执行按键对应的操作 break; } else //毛刺 { state_cnt = 0x00; break; } case 0x02: if(KEY == 1) //按键被释放 { state_cnt = 0x00; //一个完整的按键触发、执行、释放的过程完成 break; } default: break; } }
首先是无按键按下状态,10ms扫描一次目前的状态,如果还是没有被按下,继续保持无按键被按下状态,break退出扫描函数。
10ms后再次扫描一下按键,如果确实按键被按下,改变状态为等待释放状态,如果没有被按下则回到开始的无按键按下状态break退出扫描函数。
10ms后再次扫描按键,如果检测到按键被释放,则状态跳转到一开始的无按键按下状态,break退出扫描函数。
注意:
static unsigned char state_cnt = 0;
switch语句的状态变量,局部静态变量
如果默认设置为auto的局部变量在跳出函数后再次进入key_scan()后,state_cnt 的值为0,不能保持之前推出时state_cnt的值
设置成static,局部静态变量,在跳出函数后,再次进入key_scan(),state_cnt任然保持之前的值,即保存住了状态。
记第一篇博客
之前一直对电子这方面感兴趣,说要学单片机,结果懒癌加上拖延症一直没有开始学习,今年开学后买了开发板和书便下定决心学习单片机,从郭天祥的书入的门,刚开始只是跟着书上的例程在开发板上跑一跑,在笔记本上记上一点笔记,后面遇见问题时在网上搜索,一些前辈把自己遇见的问题和一些经验总结在博客上,在我遇见问题时起了很大的帮助。
后面又学习了刘平老师的教程,推荐我们可以多写写博客,把我们自己的读书笔记,学习笔记,项目笔记,或者电路的调试总结,知识归纳,也可以把自己生活,工作的点点滴滴,经验,感悟拿出来和大家分享。
因为这样的文章不仅自己受益,同样也能让他人受益。假如我有一个苹果,与N个人交换,我还是只有一个苹果,假如我有的是一份资料,与N个人交换,我将有N+1份资料。
负责我们的老师也让我们做完一个小项目后,写一篇文档总结一下,锻炼了我们制作文档的能力,也让我们再次梳理了一下这段时间的学习成果。
最后再次感谢在网络上把自己遇到的问题错误和经验总结的前辈们,感谢你们。