前阵子做的是一个叫精密电压源的项目,使用了4*4的键盘,使用了8个GPIO,是比较简单的做法了,之前在网上看到一个老外已经能用3个GPIO实现多达25个按键的控制了,对应的接线图如下
使用的是新塘某Cortex-M0单片机,(讲真,单片机这部分虽然我水平不行但是我是写腻了),从网上找了些按键扫描程序又结合当前的项目写了一个按键扫描的程序,不用延迟来去抖,也可以添加长按功能,废话不多说,直接上代码
uint8_t b_key_scan;
uint8_t b_key_debounce;
uint8_t b_key_release;
unsigned char key_scan_1() { unsigned char pb; unsigned char n,m; if(b_key_scan==0) return 0;//Timer 定时将b_key_scan置1,为了去抖 b_key_scan = 0; P20 = P21 = P22 = P23 = 0; P24 = P25 = P26 = P27 = 1; pb = P27 << 7 | P26 << 6 | P25 << 5 | P24 << 4; n = pb & 0xf0; P20 = P21 = P22 = P23 = 1; P24 = P25 = P26 = P27 = 0; pb = P23 << 3 | P22 << 2 | P21 << 1 | P20; m = pb & 0x0f; if((m!=0x0f)||(n!=0xf0)) { x=n|m; if(b_key_release == 1) { b_key_debounce = 0; count_time++; if(count_time % 30 == 0) { // printf("continue_press=%x ",x);//长按功能检测 count_time = 1; key_continue = 1; return x; } return 0; } if(b_key_debounce == 0) { r_key_pre = x; b_key_debounce = 1; return 0; } b_key_debounce = 0; //compare twice key value if(r_key_pre != x) return 0; b_key_release = 1;//set key not release return x; } b_key_release = 0; key_continue = 0; return 0; } unsigned char key_scan(void) { unsigned char num = 0xff; unsigned char key_value; key_value = key_scan_1(); if(key_value) { Beep(); // printf("key_in = %x ",key_value); switch(key_value) { case 0xee:num='0';break; case 0xed:num='1';break; case 0xeb:num='4';break; case 0xe7:num='7';break; case 0xde:num='.';break; case 0xdd:num='2';break; case 0xdb:num='5';break; case 0xd7:num='8';break; case 0xbe:num='+';break; case 0xbd:num='3';break; case 0xbb:num='6';break; case 0xb7:num='9';break; case 0x7e:num='-';break; case 0x7d:num='c';break;//confirm case 0x7b:num='s';break;//setup case 0x77:num='o';break;//output default:break; } } return num; }
代码实现也很简单,按键扫描这一部分首先是先将GPIO 设为准双向模式,然后横坐标GPIO置0,纵坐标全部置1,,按键按下的时候,横坐标的GPIO 值会变0,就获取到横坐标的值,随后再将横坐标置1,纵坐标置0,按键按下的时候获取到纵坐标,有了横坐标和纵坐标就能确定是哪个按键被按下了。另外起一个定时器,每20ms或者30ms去执行一下扫描程序。人手按按键一般停留时间至少为100ms,所以扫描和去抖都没问题。简单记录一下,有不对的请告知