键盘外观
键盘外观一般是这个样子的,淘宝上常见的有4x4和4x3的,也有不是薄膜而是按键矩阵的键盘,但是原理都大同小异。
一个普普通通的4x4键盘
键盘原理图
键盘的原理图
一般来说,键盘有多少行多少列,就有行数+列数这么多的管脚。当按钮按下后,按钮所在行列开关合上,行列之间的管脚就连通了。
单片机实现
4x3键盘
根据键盘的原理图,不难想到我们要用管脚扫描的方式来检测哪个键按下。
将行管脚设为输入,列管脚设为输出(当然也可以反着来),每次只让一个列管脚为高电平,再检测行管脚的电平高低情况,即可检测键盘是哪个键按下了。
初始化管脚
void keyboard_init(){
//设置行管脚为输入
P3DIR &= ~BIT6; //P3.6端口设为输入
P3REN |= BIT6; //使P3.6能上拉/下拉电阻
P3OUT &= ~BIT6; //置P3.6为下拉电阻模式
P3SEL &= ~BIT6; //P3.6为I/O接口
P7DIR &= ~BIT0; //P7.0端口设为输入
P7REN |= BIT0; //使P7.0能上拉/下拉电阻
P7OUT &= ~BIT0; //置P7.0为下拉电阻模式
P7SEL &= ~BIT0; //P7.0为I/O接口
P6DIR &= ~BIT4; //P6.4端口设为输入
P6REN |= BIT4; //使P6.4能上拉/下拉电阻
P6OUT &= ~BIT4; //置P6.4为下拉电阻模式
P6SEL &= ~BIT4; //P6.4为I/O接口
P6DIR &= ~BIT3; //P6.3端口设为输入
P6REN |= BIT3; //使6.3能上拉/下拉电阻
P6OUT &= ~BIT3; //置P6.3为下拉电阻模式
P6SEL &= ~BIT3; //P6.3为I/O接口
//设置列管脚为输出
P6DIR |= BIT2+BIT1+BIT0; //P6.2,1,0端口设为输出
P6OUT &=~(BIT2+BIT1+BIT0);
}
扫描管脚
思路是在一个do-while循环里面,依次设置第一列、第二列……为高电平,然后检测第一行、第二行……的电平是否为高,如果为高则说明有按键按下,行列导通,跳出循环,返回按键值。
char scanKey(){
//扫描列
char key_value=0;
unsigned char state=0;
do{
key_value=0;
if(state==0){
P6OUT |= BIT0;
P6OUT &=~ (BIT1+BIT2);
}else if(state==1){
P6OUT |= BIT1;
P6OUT &=~ (BIT0+BIT2);
}else if(state==2){
P6OUT |= BIT2;
P6OUT &=~ (BIT0+BIT1);
}
if(++state==3) state=0;
if(P6OUT & BIT0)
key_value = BIT5;
if(P6OUT & BIT1)
key_value = BIT6;
if(P6OUT & BIT2)
key_value = BIT7;
if(P3IN & BIT6) key_value |= BIT0;
else key_value &= ~BIT0;
if(P7IN & BIT0) key_value |= BIT1;
else key_value &= ~BIT1;
if(P6IN & BIT4) key_value |= BIT2;
else key_value &= ~BIT2;
if(P6IN & BIT3) key_value |= BIT3;
else key_value &= ~BIT3;
}while((key_value&0x0f)==0);//直到有行被按下
switch(key_value){//返回按下的字符
case 129: return '1';
case 65: return '2';
case 33: return '3';
case 130: return '4';
case 66: return '5';
case 34: return '6';
case 132: return '7';
case 68: return '8';
case 36: return '9';
case 136: return '*';
case 72: return '0';
case 40: return '#';
default: return 0;
}
}
4x4的键盘
同样,4x4的键盘也是通过行列扫描的方式检测按下的按钮是哪个。读者可以自行修改程序实现。
以下为参考代码:
初始化端口
void keyboard_init(){
//设置行管脚为输入
P3DIR &= ~BIT5; //P3.5端口设为输入
P3REN |= BIT5; //使3.5能上拉/下拉电阻
P3OUT &=~ BIT5; //置P3.5为下拉电阻模式
P3SEL &= ~BIT5; //P3.5为I/O接口
P3DIR &= ~BIT6; //P3.6端口设为输入
P3REN |= BIT6; //使P3.6能上拉/下拉电阻
P3OUT &=~ BIT6; //置P3.6为下拉电阻模式
P3SEL &= ~BIT6; //P3.6为I/O接口
P7DIR &= ~BIT0; //P7.0端口设为输入
P7REN |= BIT0; //使P7.0能上拉/下拉电阻
P7OUT &=~ BIT0; //置P7.0为下拉电阻模式
P7SEL &= ~BIT0; //P7.0为I/O接口
P6DIR &= ~BIT4; //P6.4端口设为输入
P6REN |= BIT4; //使P6.4能上拉/下拉电阻
P6OUT &=~ BIT4; //置P6.4为下拉电阻模式
P6SEL &=~ BIT4; //P6.4为I/O接口
//设置列管脚为输出
P6DIR |= BIT3+BIT2+BIT1+BIT0; //P6.3,2,1,0端口设为输出
P6OUT &=~(BIT3+BIT2+BIT1+BIT0);
}
扫描管脚
char scanKey(){
//扫描列
char key_value=0;
unsigned char state=0;
do{
key_value=0;
if(state==0){
P6OUT |= BIT0;
P6OUT &=~ (BIT1+BIT2+BIT3);
}else if(state==1){
P6OUT |= BIT1;
P6OUT &=~ (BIT0+BIT2+BIT3);
}else if(state==2){
P6OUT |= BIT2;
P6OUT &=~ (BIT0+BIT1+BIT3);
}else if(state==3){
P6OUT |= BIT3;
P6OUT &=~ (BIT0+BIT1+BIT2);
}
if(++state==4) state=0;
if(P6OUT & BIT0)
key_value = BIT4;
if(P6OUT & BIT1)
key_value = BIT5;
if(P6OUT & BIT2)
key_value = BIT6;
if(P6OUT & BIT3)
key_value = BIT7;
if(P3IN & BIT5) key_value |= BIT0;
else key_value &=~ BIT0;
if(P3IN & BIT6) key_value |= BIT1;
else key_value &=~ BIT1;
if(P7IN & BIT0) key_value |= BIT2;
else key_value &=~ BIT2;
if(P6IN & BIT4) key_value |= BIT3;
else key_value &=~ BIT3;
}while((key_value&0x0f)==0);//直到有行被按下
switch(key_value){//返回按下的字符
case 129: return '1';
case 65: return '4';
case 33: return '7';
case 17: return '*';
case 130: return '2';
case 66: return '5';
case 34: return '8';
case 18: return '0';
case 132: return '3';
case 68: return '6';
case 36: return '9';
case 20: return '#';
case 136: return 'A';
case 72: return 'B';
case 40: return 'C';
case 24: return 'D';
default: return 0;
}
}
结语
键盘是MSP430F5529最简单的外设之一,只要掌握了扫描行/列的方式,面对各种各样不同的键盘也能得心应手~
文中的scanKey()函数用的是循环的方式来检测按键,MSP430F5529的PORT1和PORT2是支持中断功能的,大家也可以把键盘插到PORT1或者PORT2,用中断方式来检测按键是否按下。
|