一般键盘结构如图所示.
图中的每个行列交叉处为一个按键。当键盘上没有任何按键动作,整个行列线均处于断开状态,此时列线输出为高电平,当某个按键被按下,则与此按键相连的行线被连通,此时对应列线电平输出则取决于行线的电平。如果将所有列线设置为输出,对应行线设置为输入,则可通过程序控制行线的电平状态,如,首先将第一行设置为低电平,其余行为高电平,此时依次检测列线电平输出状态,若第一列电平输出为低电平,表明第一列与第一行交叉处按键被按下,若第二列电平输出为低电平,则相应的第二列与第一行交叉处按键被按下,依次类推;判定为第一行后,将第一行与第三行设置为高电平,第二行设置为低电平。然后按照判定第一行的方法判定第二行,最后判定第三行。这种逐行逐列检测键盘电平状态的过程即为键盘的一次完整扫描。
CPU对键盘的扫描可采用轮询方式也可采用中断方式。中断实现的方式为:每当有按键被按下,则产生中断传递给CPU,CPU转入中断处理程序从而完成键值的判定及后续动作。键值的判定工作可由程序实现,也可由制定的行线、列线的状态表查询获取。
具体实现方面,在按键的断开和闭合过程中一般会产生抖动,具体的抖动时间和开关的机械特性有关,一般为5ms-10ms。为保证CPU对键值处理的可靠性,可在程序中添加适当的延时,消除抖动可能产生的错误。也可将行线和列线通过74AC245收发器与一个与非门相连,然后连接到IRQ0中断引脚,这样一旦键盘上有按键被按下,则产生中断信号,从而进入中断服务程序进行减值的判定及后续处理。收发器一般可将按键产生的抖动消除,避免CPU判断错误。
程序代码实现如下:
void IRQ_Keyboard_Handler (void) __irq
{
unsignedint i;
unsigned int PA_ROW_Status;
AT91PS_AIC AIC0 =AT91C_BASE_AIC;
AT91F_AIC_DisableIt(AIC0,AT91C_ID_IRQ0); //通过IRQ0引脚触发CPU中断
PA_ROW_Status = (unsignedchar)((AT91F_PIO_GetInput(AT91C_BASE_PIOA)>>25)&0x1F); //此处偏移地址与硬件设计引脚有关
if(PA_ROW_Status==0x1E) //判定键值
{
AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, PIN_COL_1); //置低电平
AT91F_PIO_SetOutput(AT91C_BASE_PIOA,PIN_COL_2|PIN_COL_3); //置高电平
for (i=0;i<100;i++); //让引脚电平趋于稳定
PA_ROW_Status = (unsignedchar)((AT91F_PIO_GetInput(AT91C_BASE_PIOA)>>25)&0x1F);
if(PA_ROW_Status==0x1E)
{
Button_Pressed_Value=0x00; //表明按钮被按下
KEY0_PRESSED_MARK=True;
}
AT91F_PIO_ClearOutput(AT91C_BASE_PIOA,PIN_COL_2);
AT91F_PIO_SetOutput(AT91C_BASE_PIOA,PIN_COL_1|PIN_COL_3);
for (i=0;i<100;i++);
PA_ROW_Status = (unsignedchar)((AT91F_PIO_GetInput(AT91C_BASE_PIOA)>>25)&0x1F);
if(PA_ROW_Status==0x1E)
{
Button_Pressed_Value=0x01;
KEY1_PRESSED_MARK=True;
}
AT91F_PIO_ClearOutput(AT91C_BASE_PIOA,PIN_COL_3);
AT91F_PIO_SetOutput(AT91C_BASE_PIOA,PIN_COL_1|PIN_COL_2);
for (i=0;i<100;i++);
PA_ROW_Status=(unsigned char)((AT91F_PIO_GetInput(AT91C_BASE_PIOA)>>25)&0x1F);
if(PA_ROW_Status==0x1E)
{
Button_Pressed_Value=0x02;
KEY2_PRESSED_MARK=True;
}
}
//此处可依次添加判定代码。
AT91F_PIO_ClearOutput(AT91C_BASE_PIOA,PIN_COL_1|PIN_COL_2|PIN_COL_3); //全部置低电平
for(i=0;i<100;i++);
PA_ROW_Status = (unsignedchar)((AT91F_PIO_GetInput(AT91C_BASE_PIOA)>>25)&0x1F);
while(PA_ROW_Status!=0x1F) //等到按键抬起再退出中断
{
PA_ROW_Status = (unsignedchar)((AT91F_PIO_GetInput(AT91C_BASE_PIOA)>>25)&0x1F);
}
AT91F_AIC_AcknowledgeIt(AIC0); //End of Interrupt
AT91F_AIC_ClearIt(AIC0,AT91C_ID_IRQ0); //Clear the Interrupt
AT91F_AIC_EnableIt(AIC0,AT91C_ID_IRQ0); //Enable ENDRX Interrupt
}
void IRQ_Init(void) //config the AIC
{
AT91F_AIC_ConfigureIt(AT91C_BASE_AIC,AT91C_ID_IRQ0,6,
AT91C_AIC_SRCTYPE_EXT_NEGATIVE_EDGE,(void(*)())IRQ_Keyboard_Handler); //配置为边沿触发。
AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_IRQ0); //Enable IRQ Interrupt
}
void main(void)
{
PMC_Init(); //使能外设引脚
Config_Pio(); //引脚配置初始化
IRQ_Init();
While(1)
{
;
}
}
(文章原创,转载请声明)