思路:
将输入和输出互换分别确定列和行来找到对应的按键。
若S6被按下,第一次没有翻转之前PA0~PA3为输入,PA4~PA7为输出,S6被按下此时PA5输出低电平到达PA1,此时PA1从原来的高电平变为低电平,此时我们确定了按键在第二列
进行一次翻转,此时PA0~PA3为输出,PA4~PA7为输入,此时PA1输出低电平,PA5由翻转之后的内部上拉1也转为0,此时我们确定了按键在第二行,从而确定了S6的位置
此时如何让我们的S6和第二行第二列对应:
第一行我们是1,5,9,13的编号第二列开始每个数一次+1
设计一个函数,函数返回我们按下按键的编号
1.将PA0~PA3定义成上拉输入,将PA4~PA7定义成通用推挽输出低电平。
int Matrix_Key(int value)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
2.读取PA0~PA3的电平状态。(没有按键按下去四个管脚均为1111)
GPIO_WriteBit(GPIOA, GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7, Bit_SET);
if((GPIOA->IDR & 0XF)!= 0XF)//直接操作寄存器的前四位如果不等于0XF则说明有按键被按下
{
Delay(1000);//消抖
if((GPIOA->IDR & 0XF)!= 0X0F)//再次判断按键是否按下
{
switch((GPIOA->IDR & 0XF))
case 0xE:val = 1;break;
case 0xD:val = 5;break;
case 0xB:val = 9;break;
case 0x7:val = 13;break;
default:break;
}
else
return 0;
//将PA0~PA3设置成通用推挽输出且输出低电平,将PA4~PA7设置成上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_WriteBit(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3, Bit_SET);
if((GPIOA->IDR & 0XF0) != 0XF0)
{
Delay(1000);//消抖
if((GPIOA->IDR & 0XF0) != 0XF0)
{
switch((GPIOA->IDR & 0XF0))
case 0xE0:val += 0;break;
case 0xD0:val += 1;break;
case 0xB0:val += 2;break;
case 0x70:val += 3;break;
default:break;
}
else
return 0;
}
else
return 0;
while(((GPIOA->IDR & 0XF0) != 0XF0) != 0xF0)//确保我们按键松手的时候返回val,否则会一直扫描
return val;
}
else
return 0;//没有按键被按下
3.软件消抖:SYSTICK
4.UART口配置:UART口介绍
最后附上整合好的主要代码
int main(void)
{
int key_num;
SysTick_Configuration();
Uart1_Configuration();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
while(1)
{
key_num = Matrix_Key_Scan();
if(key_num != 0)
printf("Key %d is pressed.\n", key_num);
}
}
int Matrix_Key(int value)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_WriteBit(GPIOA, GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7, Bit_SET);
if((GPIOA->IDR & 0XF)!= 0XF)
{
Delay(1000);
if((GPIOA->IDR & 0XF)!= 0X0F)
{
switch((GPIOA->IDR & 0XF))
case 0xE:val = 1;break;
case 0xD:val = 5;break;
case 0xB:val = 9;break;
case 0x7:val = 13;break;
default:break;
}
else
return 0;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_WriteBit(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3, Bit_SET);
if((GPIOA->IDR & 0XF0) != 0XF0)
{
Delay(1000);
if((GPIOA->IDR & 0XF0) != 0XF0)
{
switch((GPIOA->IDR & 0XF0))
case 0xE0:val += 0;break;
case 0xD0:val += 1;break;
case 0xB0:val += 2;break;
case 0x70:val += 3;break;
default:break;
}
else
return 0;
}
else
return 0;
while(((GPIOA->IDR & 0XF0) != 0XF0) != 0xF0)
return val;
}
else
return 0;
}