再问矩阵键盘的问题
我用STM32写了个矩阵键盘的程序,原来是查询方式,现在改成定时器方式。原理图:
程序:
void KEY_Init(void)
{
GPIO_InitTypeDefGPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); //使能PB,PE端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //开漏输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure);
}/*******************************************************************************
* 函数名: Timer4_Init_Config
* 描述 : Timer4初始化配置
* 输入 : 无
* 输出 : 无
* 返回 : 无
* 说明 : 无
*******************************************************************************/
void Timer4_Init_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //使能Timer1时钟
//设置在下一个更新事件装入活动的自动重装载寄存器周期的值(计数到200为20ms)
TIM_TimeBaseStructure.TIM_Period = 199;
TIM_TimeBaseStructure.TIM_Prescaler = 7199; //设置用来作为TIMx时钟频率除数的预分频值(10KHz的计数频率)
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = TIM_CKD_DIV1
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE ); //使能TIM2指定的中断
TIM_Cmd(TIM4, ENABLE); //使能TIMx外设
}
/*******************************************************************************
* 函数名: TIM4_IRQHandler
* 描述 : 定时器2中断断服务函数
* 输入 : 无
* 输出 : 无
* 返回 : 无
* 说明 : 无
*******************************************************************************/
void TIM4_IRQHandler(void)
{
if(TIM_GetITStatus(TIM4, TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
if(KeyFlag == 1)
{
hangvalue=(GPIO_ReadInputData(GPIOE)&0x07)+((GPIO_ReadInputData(GPIOB)&0x0380)>>4);
if (hangvalue != 0x3f) // 读出的不是0x3f说明有按键被按下
{
keynum = 0;
keyvalue = 0;
KeyFlag = 2;
GPIO_ResetBits(GPIOE,GPIO_Pin_6); //PE.6输出低
GPIO_SetBits(GPIOE,GPIO_Pin_5 | GPIO_Pin_4 | GPIO_Pin_3);
delay_us(XD);
hangvalue=(GPIO_ReadInputData(GPIOE)&0x07)+((GPIO_ReadInputData(GPIOB)&0x0300)>>5);
switch (hangvalue)
{
case 0x0F:
keyvalue=4;
break;
case 0x17:
keyvalue=5;
break;
case 0x1b:
keyvalue=1;
break;
case 0x1d:
keyvalue=2;
break;
case 0x1e:
keyvalue=3;
break;
default: break;
}
if(keyvalue==0)
{
GPIO_ResetBits(GPIOE, GPIO_Pin_5 );
GPIO_SetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_4 | GPIO_Pin_3);
delay_us(XD);
hangvalue=(GPIO_ReadInputData(GPIOE)&0x07)+((GPIO_ReadInputData(GPIOB)&0x0300)>>5);
switch (hangvalue)
{
case 0x0F:
keyvalue=9;
break;
case 0x17:
keyvalue=10;
break;
case 0x1b:
keyvalue=6;
break;
case 0x1d:
keyvalue=7;
break;
case 0x1e:
keyvalue=8;
break;
default: break;
}
}
if(keyvalue==0)
{
GPIO_ResetBits(GPIOE, GPIO_Pin_4 );
GPIO_SetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_3 | GPIO_Pin_5);
delay_us(XD);
hangvalue=(GPIO_ReadInputData(GPIOE)&0x07)+((GPIO_ReadInputData(GPIOB)&0x0380)>>4);
// 第一回合中算出行号
switch (hangvalue)
{
case 0x1F:
keyvalue=14;
break;
case 0x2F:
keyvalue=15;
break;
case 0x37:
keyvalue=16;
break;
case 0x3B:
keyvalue=11;
break;
case 0x3D:
keyvalue=12;
break;
case 0x3E:
keyvalue=13;
break;
default: break;
}
}
if(keyvalue==0)
{
GPIO_SetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_4 | GPIO_Pin_5);
GPIO_ResetBits(GPIOE, GPIO_Pin_3 );
delay_us(XD);
hangvalue=(GPIO_ReadInputData(GPIOE)&0x07)+((GPIO_ReadInputData(GPIOB)&0x0380)>>4);
switch (hangvalue)
{
case 0x1F:
keyvalue=20;
break;
case 0x2F:
keyvalue=21;
break;
case 0x37:
keyvalue=22;
break;
case 0x3B:
keyvalue=17;
break;
case 0x3D:
keyvalue=18;
break;
case 0x3E:
keyvalue=19;
break;
default: break;
}
}
GPIO_ResetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_5 | GPIO_Pin_4 | GPIO_Pin_3); //PE.6,5,4,3 输出低
delay_us(XD);
hangvalue=(GPIO_ReadInputData(GPIOE)&0x07)+((GPIO_ReadInputData(GPIOB)&0x0380)>>4);
while (hangvalue != 0x3f)
{
delay_us(20);
hangvalue=(GPIO_ReadInputData(GPIOE)&0x07)+((GPIO_ReadInputData(GPIOB)&0x0380)>>4);
}
KeyFlag=0;
keynum = keyvalue;
if(S0_State == (S_INIT|S_CONN))
{
S0_Data&=~S_TRANSMITOK;
Write_SOCK_Data_Buffer(0, &keynum, 1);//指定Socket(0~7)发送数据处理,端口0发送23字节数据
}
}
else
KeyFlag = 0;
}
GPIO_ResetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_5 | GPIO_Pin_4 | GPIO_Pin_3); //PE.6,5,4,3 输出低
delay_us(XD);
hangvalue=(GPIO_ReadInputData(GPIOE)&0x07)+((GPIO_ReadInputData(GPIOB)&0x0380)>>4);
if (hangvalue != 0x3f) // 读出的不是0x3f说明有按键被按下
{
KeyFlag = 1;
}
else
KeyFlag = 0;
// led^=0x01;
// GPIO_WriteBit(GPIOE,GPIO_Pin_7,led);
}
}
按下按键测试,通过网口打印出来:
可以看到,有的按键打印两次,实际按下一次。
还有的正确键值后面跟着一个0.
请高手指教,如何解决?谢谢!
中断中等待按键释放,按键时间在几百ms,这样很耗时间,会引起定时中断丢失。如果STM32的中断能够记住多个丢失的中断,会导致快速多次进入中断,在按键释放的抖动阶段,会出现多次按键或奇怪按键。可以在中断中设置标志,表示按键按下,在下次中断中判断按键释放,20mS的中断间隔,可以避开按键抖动阶段。 elife 发表于 2020-7-11 23:36
中断中等待按键释放,按键时间在几百ms,这样很耗时间,会引起定时中断丢失。如果STM32的中断能够记住多个丢 ...
谢谢!我试试 elife 发表于 2020-7-11 23:36
中断中等待按键释放,按键时间在几百ms,这样很耗时间,会引起定时中断丢失。如果STM32的中断能够记住多个丢 ...
我改了一下,没有那种多一个0的情况了,不过还有打印两次相同键值的情况。
程序如下:
/*******************************************************************************
* 函数名: TIM4_IRQHandler
* 描述 : 定时器4中断断服务函数
* 输入 : 无
* 输出 : 无
* 返回 : 无
* 说明 : 无
*******************************************************************************/
void TIM4_IRQHandler(void)
{
if(TIM_GetITStatus(TIM4, TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
if(KeyFlag == 2)
{
GPIO_ResetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_5 | GPIO_Pin_4 | GPIO_Pin_3); //PE.6,5,4,3 输出低
delay_us(XD);
hangvalue=(GPIO_ReadInputData(GPIOE)&0x07)+((GPIO_ReadInputData(GPIOB)&0x0380)>>4);
if(hangvalue == 0x3f)
{
KeyFlag=0;
keynum = keyvalue;
if(S0_State == (S_INIT|S_CONN))
{
S0_Data&=~S_TRANSMITOK;
Write_SOCK_Data_Buffer(0, &keynum, 1);//指定Socket(0~7)发送数据处理,端口0发送23字节数据
}
}
}
if(KeyFlag == 1)
{
GPIO_ResetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_5 | GPIO_Pin_4 | GPIO_Pin_3); //PE.6,5,4,3 输出低
delay_us(XD);
hangvalue=(GPIO_ReadInputData(GPIOE)&0x07)+((GPIO_ReadInputData(GPIOB)&0x0380)>>4);
if (hangvalue != 0x3f) // 读出的不是0x3f说明有按键被按下
{
keynum = 0;
keyvalue = 0;
KeyFlag = 2;
GPIO_ResetBits(GPIOE,GPIO_Pin_6); //PE.6输出低
GPIO_SetBits(GPIOE,GPIO_Pin_5 | GPIO_Pin_4 | GPIO_Pin_3);
delay_us(XD);
hangvalue=(GPIO_ReadInputData(GPIOE)&0x07)+((GPIO_ReadInputData(GPIOB)&0x0300)>>5);
switch (hangvalue)
{
case 0x0F:
keyvalue=4;
break;
case 0x17:
keyvalue=5;
break;
case 0x1b:
keyvalue=1;
break;
case 0x1d:
keyvalue=2;
break;
case 0x1e:
keyvalue=3;
break;
default: break;
}
if(keyvalue==0)
{
GPIO_ResetBits(GPIOE, GPIO_Pin_5 );
GPIO_SetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_4 | GPIO_Pin_3);
delay_us(XD);
hangvalue=(GPIO_ReadInputData(GPIOE)&0x07)+((GPIO_ReadInputData(GPIOB)&0x0300)>>5);
switch (hangvalue)
{
case 0x0F:
keyvalue=9;
break;
case 0x17:
keyvalue=10;
break;
case 0x1b:
keyvalue=6;
break;
case 0x1d:
keyvalue=7;
break;
case 0x1e:
keyvalue=8;
break;
default: break;
}
}
if(keyvalue==0)
{
GPIO_ResetBits(GPIOE, GPIO_Pin_4 );
GPIO_SetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_3 | GPIO_Pin_5);
delay_us(XD);
hangvalue=(GPIO_ReadInputData(GPIOE)&0x07)+((GPIO_ReadInputData(GPIOB)&0x0380)>>4);
// 第一回合中算出行号
switch (hangvalue)
{
case 0x1F:
keyvalue=14;
break;
case 0x2F:
keyvalue=15;
break;
case 0x37:
keyvalue=16;
break;
case 0x3B:
keyvalue=11;
break;
case 0x3D:
keyvalue=12;
break;
case 0x3E:
keyvalue=13;
break;
default: break;
}
}
if(keyvalue==0)
{
GPIO_SetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_4 | GPIO_Pin_5);
GPIO_ResetBits(GPIOE, GPIO_Pin_3 );
delay_us(XD);
hangvalue=(GPIO_ReadInputData(GPIOE)&0x07)+((GPIO_ReadInputData(GPIOB)&0x0380)>>4);
switch (hangvalue)
{
case 0x1F:
keyvalue=20;
break;
case 0x2F:
keyvalue=21;
break;
case 0x37:
keyvalue=22;
break;
case 0x3B:
keyvalue=17;
break;
case 0x3D:
keyvalue=18;
break;
case 0x3E:
keyvalue=19;
break;
default: break;
}
}
}
else
KeyFlag = 0;
}
if(KeyFlag == 0)
{
GPIO_ResetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_5 | GPIO_Pin_4 | GPIO_Pin_3); //PE.6,5,4,3 输出低
delay_us(XD);
hangvalue=(GPIO_ReadInputData(GPIOE)&0x07)+((GPIO_ReadInputData(GPIOB)&0x0380)>>4);
if (hangvalue != 0x3f) // 读出的不是0x3f说明有按键被按下
{
KeyFlag = 1;
}
else
KeyFlag = 0;
}
// led^=0x01;
// GPIO_WriteBit(GPIOE,GPIO_Pin_7,led);
}
}
/*******************************************************************************
* 函数名: TIM4_IRQHandler
* 描述 : 定时器4中断断服务函数
* 输入 : 无
* 输出 : 无
* 返回 : 无
* 说明 : 无
*******************************************************************************/
void TIM4_IRQHandler(void)
{
static uint8_t key_Pace = 0;
static uint32_told_KeyVal;
uint32_t new_KeyVal;
if(TIM_GetITStatus(TIM4, TIM_IT_Update) == SET)
{ //设定4ms中断一次
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
//键盘检测可以做成for循环4次
// PE.6,5,4设施成输入 ,PE3输出L
new_KeyVal = (~(GPIO_ReadInputData(GPIOE) & 7) + (GPIO_ReadInputData(GPIOB) >>4))) & 0x3f ;
//PE.3输入,PE4输出L
new_KeyVal |= ((~(GPIO_ReadInputData(GPIOE) & 7) + (GPIO_ReadInputData(GPIOB) >>4))) & 0x3f) << 6;
//PE.4输入,PE5输出L
new_KeyVal |= ((~(GPIO_ReadInputData(GPIOE) & 7) + (GPIO_ReadInputData(GPIOB) >>4))) & 0x3f) << 12;
//PE.5输入,PE6输出L
new_KeyVal |= ((~(GPIO_ReadInputData(GPIOE) & 7) + (GPIO_ReadInputData(GPIOB) >>4))) & 0x3f ) << 18;
//恢复键盘待机,PE.6,5,4,3全部输出L
key_Pace ++;
if(key_Pace < 6)
{//键盘按下去抖, 时间4ms×6 = 24ms ,也可以设置6~8ms中断一次,响应该值调整
if((new_KeyVal == 0) || new_KeyVal != old_KeyVal)//无键操作或者键值不对应
{old_KeyVal = new_KeyVal;key_Pace = 0;} //返回等待键盘状态
}
else if(key_Pace == 6)
{//键值处理,或启动发送
switch(old_KeyVal)
{//键盘比较离散或允许组合键采用这个方法
case 0x000001: //键盘1
break;
case 0x000002: //键盘2
break;
case 0x000004: //键盘3
break;
case 0x000008: //键盘4
break;
case 0x000010: //键盘5
break;
case 0x000020: //键盘6
break;
case 0x000040: //键盘7
break;
case 0x000080: //键盘8
break;
case 0x000100: //键盘9
break;
case 0x000200: //键盘10
break;
case 0x000400: //键盘11
break;
case 0x000800: //键盘12
break;
case 0x001000: //键盘13
break;
case 0x002000: //键盘14
break;
case 0x004000: //键盘15
break;
case 0x008000: //键盘16
break;
case 0x010000: //键盘17
break;
case 0x020000: //键盘18
break;
case 0x040000: //键盘19
break;
case 0x080000: //键盘20
break;
case 0x100000: //键盘21
break;
case 0x200000: //键盘22
break;
case 0x400000: //键盘23
break;
case 0x800000: //键盘24
break;
case 0xXXXXXX: //其它组合键盘
break;
}
// 可以用统筹方法组合好后统一发送数据到通讯口
old_KeyVal = 0;
}
else if(key_Pace < 20)
{ //键盘释放去抖
if(new_KeyVal != 0)key_Pace = 6; //等待键盘释放
}
else key_Pace = 0; //键盘释放
}
}
参考一下 一事无成就是我 发表于 2020-7-14 16:47
/*******************************************************************************
* 函数名: TIM4_IR ...
谢谢!我试一下。 一般我们不在定时器里做这些事情,只是在中断里设置状态位,而是在主程序里不断扫描状态位,有效则执行,执行后清除,那样不影响多任务实时性 一事无成就是我 发表于 2020-7-14 17:13
一般我们不在定时器里做这些事情,只是在中断里设置状态位,而是在主程序里不断扫描状态位,有效则执行,执 ...
搞好了,谢谢
页:
[1]