我用STM32写矩阵键盘程序。以前发过几个帖子,一直没搞好。
电路图:
代码:
/*******************************************************************************
* 函数名 : TIM4_IRQHandler
* 描述 : 定时器4中断断服务函数
* 输入 : 无
* 输出 : 无
* 返回 : 无
* 说明 : 无
*******************************************************************************/
void TIM4_IRQHandler(void)
{
static uint8_t key_Pace = 0;
static uint32_t old_KeyVal;
if(TIM_GetITStatus(TIM4, TIM_IT_Update) == SET)
{ //设定4ms中断一次
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
//键盘检测可以做成for循环4次
// PE.3,5,4设施成输入 ,PE6输出L
GPIO_SetBits(GPIOE,GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5);
GPIO_ResetBits(GPIOE, GPIO_Pin_6 );
delay_us(XD);
new_KeyVal = (~((GPIO_ReadInputData(GPIOE) & 7) + ((GPIO_ReadInputData(GPIOB)&0x0300) >>5))) & 0x1f ;
//PE.3输入,PE5输出L
GPIO_SetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_3 | GPIO_Pin_4);
GPIO_ResetBits(GPIOE, GPIO_Pin_5 );
delay_us(XD);
new_KeyVal |= (((~((GPIO_ReadInputData(GPIOE) & 7) + ((GPIO_ReadInputData(GPIOB)&0x0300) >>5))) & 0x1f) << 5);
//PE.4输入,PE4输出L
GPIO_SetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_5 | GPIO_Pin_3);
GPIO_ResetBits(GPIOE, GPIO_Pin_4 );
delay_us(XD);
new_KeyVal |= (((~((GPIO_ReadInputData(GPIOE) & 7) + ((GPIO_ReadInputData(GPIOB)&0x0380) >>4))) & 0x3f) << 10);
//PE.5输入,PE3输出L
GPIO_SetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_4 | GPIO_Pin_5);
GPIO_ResetBits(GPIOE, GPIO_Pin_3 );
delay_us(XD);
new_KeyVal |= (((~((GPIO_ReadInputData(GPIOE) & 7) + ((GPIO_ReadInputData(GPIOB)&0x0380) >>4)))& 0x3f ) << 16);
//恢复键盘待机,PE.6,5,4, 3全部输出L
GPIO_ResetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_3);
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
keyvalue=3;
break;
case 0x000002: //键盘2
keyvalue=2;
break;
case 0x000004: //键盘3
keyvalue=1;
break;
case 0x000008: //键盘4
keyvalue=5;
break;
case 0x000010: //键盘5
keyvalue=4;
break;
case 0x000020: //键盘6
keyvalue=8;
break;
case 0x000040: //键盘7
keyvalue=7;
break;
case 0x000080: //键盘8
keyvalue=6;
break;
case 0x000100: //键盘9
keyvalue=10;
break;
case 0x000200: //键盘10
keyvalue=9;
break;
case 0x000400: //键盘11
keyvalue=13;
break;
case 0x000800: //键盘12
keyvalue=12;
break;
case 0x001000: //键盘13
keyvalue=11;
break;
case 0x002000: //键盘14
keyvalue=16;
break;
case 0x004000: //键盘15
keyvalue=15;
break;
case 0x008000: //键盘16
keyvalue=14;
break;
case 0x010000: //键盘17
keyvalue=19;
break;
case 0x020000: //键盘18
keyvalue=18;
break;
case 0x040000: //键盘19
keyvalue=17;
break;
case 0x080000: //键盘20
keyvalue=22;
break;
case 0x100000: //键盘21
keyvalue=21;
break;
case 0x200000: //键盘22
keyvalue=20;
break;
default: //其它组合键盘
break;
}
// 可以用统筹方法组合好后统一发送数据到通讯口
keynum=keyvalue ;
old_KeyVal = 0;
}
else if(key_Pace < 20)
{ //键盘释放去抖
if(new_KeyVal != 0) key_Pace = 6; //等待键盘释放
}
else key_Pace = 0; //键盘释放
}
}
实际测试,发现按键3,8,12比较难按,不容易检测到,经常按了没反应。
大神看看,哪里有问题?谢谢
// PE.3,5,4设施成输入 ,PE6输出L 这个不对吧。都应该设置为输出啊。只是PE.3,5,4设施成输出高 ,PE6输出低。
其实PB7,8,9 PE0 1 2做输出好
PE3 4 5 6读
这样不用与或之类的事。
本帖最后由 damiaa 于 2020-8-23 23:11 编辑引用: damiaa 发表于 2020-8-23 23:05 // PE.3,5,4设施成输入 ,PE6输出L 这个不对吧。都应该设置为输出啊。只是PE.3,5,4设施成输出高 ,PE6 ...
那个注释有问题
引用: chenbingjy 发表于 2020-8-24 08:21 那个注释有问题
//如果按键值没有变化KeyValue=0 ModiFlag =0;按键按下ModiFlag置1 值在ModiFlag里 用完请清ModiFlag和ModiFlag
KeyVal[]是做消抖用。
unsigned char keytable[] ={3,2,1,5,4,8,7,6,10,9,13,12,11,16,15,14,,19,18,17,22,21,20};
void TIM4_IRQHandler(void)
{
static uint32_t KeyVal[6],KeyOldVal=0,KeyValue;
static uint8_t KeyPoint=0,ModiFlag=0;
if(TIM_GetITStatus(TIM4, TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
GPIO_SetBits(GPIOE,GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5); GPIO_ResetBits(GPIOE, GPIO_Pin_6 ); delay_us(XD);
new_KeyVal = (~((GPIO_ReadInputData(GPIOE) & 7) + ((GPIO_ReadInputData(GPIOB)&0x0300) >>5))) & 0x1f ;
GPIO_SetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_3 | GPIO_Pin_4);GPIO_ResetBits(GPIOE, GPIO_Pin_5 ); delay_us(XD);
new_KeyVal |= (((~((GPIO_ReadInputData(GPIOE) & 7) + ((GPIO_ReadInputData(GPIOB)&0x0300) >>5))) & 0x1f) << 5);
GPIO_SetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_5 | GPIO_Pin_3); GPIO_ResetBits(GPIOE, GPIO_Pin_4 ); delay_us(XD);
new_KeyVal |= (((~((GPIO_ReadInputData(GPIOE) & 7) + ((GPIO_ReadInputData(GPIOB)&0x0380) >>4))) & 0x3f) << 10);
GPIO_SetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_4 | GPIO_Pin_5); GPIO_ResetBits(GPIOE, GPIO_Pin_3 ); delay_us(XD);
new_KeyVal |= (((~((GPIO_ReadInputData(GPIOE) & 7) + ((GPIO_ReadInputData(GPIOB)&0x0380) >>4)))& 0x3f ) << 16);
GPIO_ResetBits(GPIOE,GPIO_Pin_6 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_3);
KeyVal[KeyPoint++]= new_KeyVal;
if(KeyPoint >= 6) KeyPoint =0;
if((KeyVal[0] == KeyVal[1])&&(KeyVal[0] == KeyVal[2])&&&&(KeyVal[0] == KeyVal[3])&&(KeyVal[0] == KeyVal[4])&&(KeyVal[0] == KeyVal[5]))
{ for(i=0;i<22;i++)
{
if(KeyVal[0] &(1<<i))
break;
}
if(i >=22)
KeyValue =0;
else
KeyValue =keytable[i];
if(KeyValue != KeyOldVal)
{
KeyOldVal=KeyValue;
ModiFlag=1;
}
}
}
}
引用: 29447945 发表于 2020-8-24 09:44 中断里面还delay,这很不合适吧,中断程序要尽量断,你可以看看别人的按键程序的框架,不用定时器都能做好 ...
我现在就是不明白,有几个按键有问题。
我看了一些别人的矩阵键盘程序,都差不多
chenbingjy 发表于 2020-8-24 10:07 我现在就是不明白,有几个按键有问题。 我看了一些别人的矩阵键盘程序,都差不多
这里有一个简单的例程,你可以用这个完善下,不一定要用中断,只要保证程序进scan的时间在100ms内就可以了。
引用: chenbingjy 发表于 2020-8-24 10:07 我现在就是不明白,有几个按键有问题。 我看了一些别人的矩阵键盘程序,都差不多
你这种用法,即使找到问题,解决了也不合适用,所以我并没有分析问题的原因
引用: 29447945 发表于 2020-8-24 10:14 chenbingjy 发表于 2020-8-24 10:07 我现在就是不明白,有几个按键有问题。 我看了一些别人的矩阵键盘程 ...
谢谢,我看看
引用: 29447945 发表于 2020-8-24 09:44 中断里面还delay,这很不合适吧,中断程序要尽量断,你可以看看别人的按键程序的框架,不用定时器都能做好 ...
中断里的delay主要是让IO口电平稳定,不加会出错。
引用: damiaa 发表于 2020-8-24 09:40 //如果按键值没有变化KeyValue=0 ModiFlag =0;按键按下ModiFlag置1 值在ModiFlag里 用完请清ModiFlag和M ...
用完请清ModiFlag和ModiFlag
是不是清ModiFlag和KeyValue?
引用: damiaa 发表于 2020-8-24 09:40 //如果按键值没有变化KeyValue=0 ModiFlag =0;按键按下ModiFlag置1 值在ModiFlag里 用完请清ModiFlag和M ...
谢谢!我试了一下,发现要使劲按按键才出键值,不知道哪个参数没设置对,是不是定时器时间。我现在设的4ms
引用: chenbingjy 发表于 2020-8-24 17:14 中断里的delay主要是让IO口电平稳定,不加会出错。
我明白delay是消抖,但是中断里面delay处理不太合理,其次,消抖时间一般ms级别,如果是机械按键,us级别消抖是不够的。
引用: 29447945 发表于 2020-8-24 18:34 我明白delay是消抖,但是中断里面delay处理不太合理,其次,消抖时间一般ms级别,如果是机械按键,us级别 ...
那个delay不是消抖,是让矩阵键盘行线发出的驱动高低电平稳定,否则会误判。
你那个一大堆case没必要,最好不要在中断里处理按键以后的分支程序,那样会混乱不清。。。。。 关于按键以前写过一个贴你可以看看 输出口的speed设置为低就可以避免延时,如果不行的话可以把扫描拆成几次在中断里输出,这样效率高
引用: huo_hu 发表于 2020-8-25 03:43 你那个一大堆case没必要,最好不要在中断里处理按键以后的分支程序,那样会混乱不清。。。。。 关于按键以 ...
谢谢,我再试试
引用: huo_hu 发表于 2020-8-25 03:43 你那个一大堆case没必要,最好不要在中断里处理按键以后的分支程序,那样会混乱不清。。。。。 关于按键以 ...
输出口的speed设置为低还是不行,原来50MHz,现在2MHz。
引用: chenbingjy 发表于 2020-8-24 17:16 用完请清ModiFlag和ModiFlag 是不是清ModiFlag和KeyValue?
是呢 就是你根据ModiFlag和ModiFlag判断有按键了。你就使用。使用完了你要让他们数据为0
这样他们就可以开始下次按键的判断。