ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

【51单片机】1.2 如何实现按键?

【51单片机】1.2 如何实现按键? 目录一、独立/矩阵按键二、定时器原理一、独立/矩阵按键单片机往往是检测状态而不是检测过程按键消抖1.延时10ms不建议这种方法2.定时器消抖定时2ms检测如下红色部分独立按键主循环while(1处理按键事件中断用于确定按键状态一个2ms定时器不断读key电平消抖用一个变量0xff进一次定时器中断2ms0xff左移一位或上key最终判断此变量是否为0xff或0x0 // 这里用的是定时器中断定时一直读按键状态其实有点冗余一直在检测。#include reg52.h sbit ADDR0 P1^0; sbit ADDR1 P1^1; sbit ADDR2 P1^2; sbit ADDR3 P1^3; sbit ENLED P1^4; //按键一定要仔细对照原理图这里KEY1P2^4……按下键KEY1会变为0然后给P2^4。这里定义就是因为可以检测 对应矩阵按键电路就是单片机的P2口资源 sbit KEY1 P2^4; sbit KEY2 P2^5; sbit KEY3 P2^6; sbit KEY4 P2^7; bit KeySta 1; //当前按键状态 void main() { bit backup 1; //按键值备份保存前一次的扫描值 unsigned char cnt 0; //按键计数 EA 1; //使能总中断 ENLED 0; //选择数码管DS1进行显示 ADDR3 1; ADDR2 0; ADDR1 0; ADDR0 0; TMOD 0x01; //设置T0为模式1 TH0 0xF8; //为T0赋初值0xF8CD定时2ms TL0 0xCD; ET0 1; //使能T0中断 TR0 1; //启动T0 P2 0xF7; //P2.3置0即KeyOut1输出低电平, 读外部按键自己必须是高电平Keyin置高电平读取Keyin的情况就独立的一排按键通过输入来判断按键是否变这里要仔细看截图和原理图 P0 LedChar[cnt]; //显示按键次数初值 while (1) { if (KeySta ! backup) //不相等说明此时按键有动作KeySta是在中断中实时检测的。 中断nb { if (backup 0) //弹起动作 KeySta的0给了backup 然后前面KeySta在中断中检测到弹起变为1满足条件进入第一个和第二个if。 { cnt; //按键次数1 if (cnt 10) { //只用1个数码管显示所以加到10就清零重新开始 cnt 0; } //P0 LedChar[cnt]; //计数值显示到数码管上 } backup KeySta; //更新备份为当前值以备进行下次比较 } } } void InterruptTimer0() interrupt 1 { static unsigned char keybuf 0xFF; //扫描缓冲区保存一段时间内的扫描值。给初值 疑问怎么个扫描法 哦就是连续判断再加一个key TH0 0xF8; //重新加载初值 TL0 0xCD; //下面这条语句很好 keybuf (keybuf1) | KEY4; // key4会强制类型转换 // keybuf左移后xxxxxxx0 | xxxxxxxKEY4 //缓冲区左移一位并将当前扫描值移入最低位。一次只移动一个bit if (keybuf 0x00) { //连续8次扫描值都为0即16ms内都只检测到按下状态时可认为按键已按下 KeySta 0; } else if (keybuf 0xFF) { //连续8次扫描值都为1即16ms定时的2ms) 内都只检测到弹起状态时可认为按键已弹起 KeySta 1; } else { } //其它情况则说明按键状态尚未稳定则不对KeySta变量值进行更新 }矩阵按键与上面的独立按键很类似主循环依旧处理按键事件while(1)中断也很类似独立按键但要注意一些代码的执行顺序。//按键一般会保持100ms以上#include reg52.h sbit ADDR0 P1^0; sbit ADDR1 P1^1; sbit ADDR2 P1^2; sbit ADDR3 P1^3; sbit ENLED P1^4; sbit KEY_IN_1 P2^4; sbit KEY_IN_2 P2^5; sbit KEY_IN_3 P2^6; sbit KEY_IN_4 P2^7; sbit KEY_OUT_1 P2^3; sbit KEY_OUT_2 P2^2; sbit KEY_OUT_3 P2^1; sbit KEY_OUT_4 P2^0; unsigned char code LedChar[] { //数码管显示字符转换表0-F 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E }; unsigned char KeySta[4][4] { //全部矩阵按键的当前状态 断开 {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1} }; void main() { unsigned char i, j; // i 行 j 列 unsigned char backup[4][4] { //按键值备份保存前一次的值 {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1} }; EA 1; //使能总中断 ENLED 0; //选择数码管DS1进行显示 ADDR3 1; ADDR2 0; ADDR1 0; ADDR0 0; TMOD 0x01; TH0 0xFC; //定时1ms TL0 0x67; ET0 1; //使能T0中断 TR0 1; //启动T0 P0 LedChar[0]; //默认显示0 while (1) { for (i0; i4; i) //循环检测4*4的矩阵按键 { for (j0; j4; j) { if ( KeySta[i][j] !backup[i][j] ) //检测按键动作 { if (backup[i][j] ! 0) //按键按下时又马上松开就是松开才会显示字符 { P0 LedChar[i*4j]; //将编号显示到数码管没错 } backup[i][j] KeySta[i][j]; //更新前一次的备份值KeySta[i][j]实时变化 } } } } } void InterruptTimer0() interrupt 1 { unsigned char i; static unsigned char keyout 0; //注意赋初值 0 static unsigned char keybuf[4][4] { //矩阵按键扫描缓冲区全部是高位 {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF} }; TH0 0xFC; //重新加载初值 TL0 0x67; //将一行的4个按键值移入缓冲区!!!!! keybuf[keyout][0] (keybuf[keyout][0] 1) | KEY_IN_1; keybuf[keyout][1] (keybuf[keyout][1] 1) | KEY_IN_2; keybuf[keyout][2] (keybuf[keyout][2] 1) | KEY_IN_3; keybuf[keyout][3] (keybuf[keyout][3] 1) | KEY_IN_4; //消抖后更新按键状态 for (i0; i4; i) //每行4个按键所以循环4次 { if ((keybuf[keyout][i] 0x0F) 0x00) //这里是要 按位与 { //连续4次扫描值为0即4*4ms内都是按下状态时可认为按键已稳定的按下是4*4 ms KeySta[keyout][i] 0; } else if ((keybuf[keyout][i] 0x0F) 0x0F) { //连续4次扫描值为1即4*4ms内都是弹起状态时可认为按键已稳定的弹起 KeySta[keyout][i] 1; } } //执行下一次的扫描输出 keyout; //输出索引递增 keyout keyout 0x03; //加到4即归零这个 很6 switch (keyout) //根据索引释放当前输出引脚 { //case 3: KEY_OUT_4 0; KEY_OUT_3 1; KEY_OUT_2 1;KEY_OUT_1 1; 这里可以省略是因为前面那个值就是1 case 0: KEY_OUT_4 1; KEY_OUT_1 0; break; //发现没有是先case1 2 3 0的顺序如果是这样那case 1中就不能省略其余KEY_OUT因为没有赋初值呀中断多次就在switch里面初始化了注意顺序注意吧拉高电平放到前面 case 1: KEY_OUT_1 1; KEY_OUT_2 0; break; case 2: KEY_OUT_2 1; KEY_OUT_3 0; break; case 3: KEY_OUT_3 1; KEY_OUT_4 0; break; default: break; //注意是先对按键进行读取然后进行判断/切换KEY_OUT为什么要这样呢如果先切换可能1还没变成0就被读取了执行速度比较慢 } }二、定时器原理简单的示意图
返回列表