用Delay消抖会阻碍程序进程
改用定时器扫描会好很多~
上一篇文章已经发过用延时函数写的矩阵按键了,稍加修改即可。
本次矩阵键盘要写三个函数,建议封装一下哈,这里我命名的是MatrixKeyT
在main.c里声明一下 #include "MatrixKeyT.h"
第一个函数是读取按键键码,仍然采用逐列扫描,把之前的延时都去掉
这里if判断 多了后面的条件,两个条件同时满足,相当于找到对应按键的坐标,这样按键更加稳定,不会出现按键失灵的情况,咱也可以去掉试试,反正电脑又不会爆炸~
1. /** 2. *@brief 名称:矩阵键盘读取按键键码, 内部函数 3. *@param 参数:无 4. *@retval返回值:KeyNumber 0代表无按键按下,1~16代表键码 5. */ 6. unsigned char MatrixKey_GetState() 7. { 8. unsigned char KeyNumber=0; 9. 10. P1=0xFF; 11. P1_3=0; 12. if(P1_7==0 && P1_3==0){KeyNumber=1;} 13. if(P1_6==0 && P1_3==0){KeyNumber=5;} 14. if(P1_5==0 && P1_3==0){KeyNumber=9;} 15. if(P1_4==0 && P1_3==0){KeyNumber=13;} 16. 17. P1=0xFF; 18. P1_2=0; 19. if(P1_7==0 && P1_2==0){KeyNumber=2;} 20. if(P1_6==0 && P1_2==0){KeyNumber=6;} 21. if(P1_5==0 && P1_2==0){KeyNumber=10;} 22. if(P1_4==0 && P1_2==0){KeyNumber=14;} 23. 24. P1=0xFF; 25. P1_1=0; 26. if(P1_7==0 && P1_1==0){KeyNumber=3;} 27. if(P1_6==0 && P1_1==0){KeyNumber=7;} 28. if(P1_5==0 && P1_1==0){KeyNumber=11;} 29. if(P1_4==0 && P1_1==0){KeyNumber=15;} 30. 31. P1=0xFF; 32. P1_0=0; 33. if(P1_7==0 && P1_0==0){KeyNumber=4;} 34. if(P1_6==0 && P1_0==0){KeyNumber=8;} 35. if(P1_5==0 && P1_0==0){KeyNumber=12;} 36. if(P1_4==0 && P1_0==0){KeyNumber=16;} 37. 38. return KeyNumber; 39. }
第二个函数是放在定时器里10ms循环一次的
定义两个静态局部变量,用来存储10ms前后按键键码数值,每10ms这两个变量更新一次,这样代替Delay消抖
在这个MatrixKeyT.c里定义一个全局变量,用来接受显示按键键码数值。
unsigned char Key_KeyNumber;
1. void MatrixKey_Loop(void) 2. { 3. static unsigned char NowState,LastState; 4. LastState = NowState; //按键状态更新 5. NowState = MatrixKey_GetState(); //获取当前按键状态 6. if(LastState == 1 && NowState == 0) {Key_KeyNumber=1;} 7. if(LastState == 2 && NowState == 0) {Key_KeyNumber=2;} 8. if(LastState == 3 && NowState == 0) {Key_KeyNumber=3;} 9. if(LastState == 4 && NowState == 0) {Key_KeyNumber=4;} 10. if(LastState == 5 && NowState == 0) {Key_KeyNumber=5;} 11. if(LastState == 6 && NowState == 0) {Key_KeyNumber=6;} 12. if(LastState == 7 && NowState == 0) {Key_KeyNumber=7;} 13. if(LastState == 8 && NowState == 0) {Key_KeyNumber=8;} 14. if(LastState == 9 && NowState == 0) {Key_KeyNumber=9;} 15. if(LastState ==10 && NowState == 0) {Key_KeyNumber=10;} 16. if(LastState ==11 && NowState == 0) {Key_KeyNumber=11;} 17. if(LastState ==12 && NowState == 0) {Key_KeyNumber=12;} 18. if(LastState ==13 && NowState == 0) {Key_KeyNumber=13;} 19. if(LastState ==14 && NowState == 0) {Key_KeyNumber=14;} 20. if(LastState ==15 && NowState == 0) {Key_KeyNumber=15;} 21. if(LastState ==16 && NowState == 0) {Key_KeyNumber=16;}//如果10ms前按下按键16,并且现在已经松手,那就认为按键16按下 22. }
这样写的循环按键没有短按长按的功能, 若想加长按短按,可以定义多个计数变量 ,判断条件改成 LastState == 1 && NowState == 1 ,10ms前后都是按键1按下,计数变量++,也就是按下按键 10ms计数变量就会自加1,然后判断阈值,计数变量在10-100以内(100ms-1s)认为是短按,给一个键码数;大于100(大于1s)0认为是长按,给另外一个键码数。
这里没搞明白可以看一下之前写的《独立按键-短按与长按》
最后一个函数把按键键码返回出去
定义一个暂存数据的变量Temp,把按键数值赋值给Temp,把Key_KeyNumber清零(代表未按下),返回值为Temp
1. /** 2. *@brief 名称:矩阵键盘扫描,获取按键键码 3. *@param 参数:无 (放在主函数while里 赋值给一个 代表键码的变量) 4. *@retval返回值:KeyNumber 0代表无按键按下,1~16代表键码 5. */ 6. unsigned char Key(void) 7. { 8. unsigned char Temp = 0; 9. Temp = Key_KeyNumber; //赋值给暂存变量 10. Key_KeyNumber = 0; //清零 11. return Temp; //返回暂存变量 12. }
我把这个MatrixKeyT.c一起放在下边了哈,有需要的直接复制
1. #include <REGX52.H> 2. #include "MatrixKeyT.h" 3. 4. unsigned char Key_KeyNumber; 5. 6. 7. /** 8. *@brief 名称:矩阵键盘扫描,获取按键键码 9. *@param 参数:无 (放在主函数while里 赋值给一个 代表键码的变量) 10. *@retval返回值:KeyNumber 0代表无按键按下,1~16代表键码 11. */ 12. unsigned char Key(void) 13. { 14. unsigned char Temp = 0; 15. Temp = Key_KeyNumber; //赋值给暂存变量 16. Key_KeyNumber = 0; //清零 17. return Temp; //返回暂存变量 18. } 19. 20. 21. /** 22. *@brief 名称:矩阵键盘读取按键键码, 内部函数(不需要外部调用的) 23. *@param 参数:无 24. *@retval返回值:KeyNumber 0代表无按键按下,1~16代表键码 25. */ 26. unsigned char MatrixKey_GetState() 27. { 28. unsigned char KeyNumber=0; 29. 30. P1=0xFF; 31. P1_3=0; 32. if(P1_7==0 && P1_3==0){KeyNumber=1;} 33. if(P1_6==0 && P1_3==0){KeyNumber=5;} 34. if(P1_5==0 && P1_3==0){KeyNumber=9;} 35. if(P1_4==0 && P1_3==0){KeyNumber=13;} 36. 37. P1=0xFF; 38. P1_2=0; 39. if(P1_7==0 && P1_2==0){KeyNumber=2;} 40. if(P1_6==0 && P1_2==0){KeyNumber=6;} 41. if(P1_5==0 && P1_2==0){KeyNumber=10;} 42. if(P1_4==0 && P1_2==0){KeyNumber=14;} 43. 44. P1=0xFF; 45. P1_1=0; 46. if(P1_7==0 && P1_1==0){KeyNumber=3;} 47. if(P1_6==0 && P1_1==0){KeyNumber=7;} 48. if(P1_5==0 && P1_1==0){KeyNumber=11;} 49. if(P1_4==0 && P1_1==0){KeyNumber=15;} 50. 51. P1=0xFF; 52. P1_0=0; 53. if(P1_7==0 && P1_0==0){KeyNumber=4;} 54. if(P1_6==0 && P1_0==0){KeyNumber=8;} 55. if(P1_5==0 && P1_0==0){KeyNumber=12;} 56. if(P1_4==0 && P1_0==0){KeyNumber=16;} 57. 58. return KeyNumber; 59. } 60. 61. 62. void MatrixKey_Loop(void) 63. { 64. static unsigned char NowState,LastState; 65. LastState = NowState; //按键状态更新 66. NowState = MatrixKey_GetState(); //获取当前按键状态 67. if(LastState == 1 && NowState == 0) {Key_KeyNumber=1;} 68. if(LastState == 2 && NowState == 0) {Key_KeyNumber=2;} 69. if(LastState == 3 && NowState == 0) {Key_KeyNumber=3;} 70. if(LastState == 4 && NowState == 0) {Key_KeyNumber=4;} 71. if(LastState == 5 && NowState == 0) {Key_KeyNumber=5;} 72. if(LastState == 6 && NowState == 0) {Key_KeyNumber=6;} 73. if(LastState == 7 && NowState == 0) {Key_KeyNumber=7;} 74. if(LastState == 8 && NowState == 0) {Key_KeyNumber=8;} 75. if(LastState == 9 && NowState == 0) {Key_KeyNumber=9;} 76. if(LastState ==10 && NowState == 0) {Key_KeyNumber=10;} 77. if(LastState ==11 && NowState == 0) {Key_KeyNumber=11;} 78. if(LastState ==12 && NowState == 0) {Key_KeyNumber=12;} 79. if(LastState ==13 && NowState == 0) {Key_KeyNumber=13;} 80. if(LastState ==14 && NowState == 0) {Key_KeyNumber=14;} 81. if(LastState ==15 && NowState == 0) {Key_KeyNumber=15;} 82. if(LastState ==16 && NowState == 0) {Key_KeyNumber=16;} 83. }
再写定时器0初始化函数和定时器0的中断函数
1. //定时器0初始化模板 //1毫秒@11.0592MHz 2. void Timer0_Init(void) //1毫秒@11.0592MHz 3. { 4. TMOD &= 0xF0; //设置定时器模式 5. TMOD |= 0x01; //设置定时器模式 6. TL0 = 0x66; //设置定时初值 7. TH0 = 0xFC; //设置定时初值 8. TF0 = 0; //清除TF0标志 9. TR0 = 1; //定时器0开始计时 10. ET0=1; 11. EA=1; 12. PT0=0; 13. }
main.c也复制一下吧
1. #include <REGX52.H> 2. #include "MatrixKeyT.h" 3. 4. unsigned char KeyNum; 5. 6. 7. //定时器0初始化模板 //1毫秒@11.0592MHz 8. void Timer0_Init(void) //1毫秒@11.0592MHz 9. { 10. TMOD &= 0xF0; //设置定时器模式 11. TMOD |= 0x01; //设置定时器模式 12. TL0 = 0x66; //设置定时初值 13. TH0 = 0xFC; //设置定时初值 14. TF0 = 0; //清除TF0标志 15. TR0 = 1; //定时器0开始计时 16. ET0=1; 17. EA=1; //总中断开启 18. PT0=0; 19. } 20. 21. 22. void main() 23. { 24. Timer0_Init(); 25. 26. while(1) 27. { 28. 29. KeyNum = Key(); //按键返回接口 30. 31. if(KeyNum == 2) //如果按键2按下 32. P2_0=~P2_0; //第一个灯取反 33. if(KeyNum == 7) //如果按键7按下 34. P2_2=~P2_2; //第三个灯取反 35. 36. 37. 38. } 39. 40. } 41. 42. 43. void Timer0_Routine() interrupt 1 //定时器0的中断函数 44. { 45. static unsigned intT0Count; 46. 47. TL0 = 0x66; //设置定时初值//1毫秒@11.0592MHz 48. TH0 = 0xFC; //设置定时初值 49. T0Count++; 50. 51. if(T0Count>=10) //10ms 52. { 53. MatrixKey_Loop(); 54. //清零重记次 55. T0Count=0; 56. 57. } 58. }