目录
一、简介
二、原理图
三、程序实现
一、简介
矩阵键盘,也称矩阵按键,是为了节约单片机IO口占用所引入的一种外设。
二、矩阵按键的原理图
三、程序实现
GPIO初始化引脚代码
/*!
\brief Init Key Function
\param[in] none
\param[out] none
\retval none
*/
void Key_Init(void)
{
gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_10MHZ,GPIO_PIN_0); //PA0
gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_10MHZ,GPIO_PIN_1); //PA1
gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_10MHZ,GPIO_PIN_2); //PA2
gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_10MHZ,GPIO_PIN_3); //PA3 复用
gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_10MHZ,GPIO_PIN_4); //PA4 复用
gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_10MHZ,GPIO_PIN_5); //PA5 复用
gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_10MHZ,GPIO_PIN_6); //PA6 复用
gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_10MHZ,GPIO_PIN_7); //PA7 复用
gpio_init(GPIOB,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_10MHZ,GPIO_PIN_0); //PB0
gpio_init(GPIOB,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_10MHZ,GPIO_PIN_1); //PB1
gpio_init(GPIOB,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_10MHZ,GPIO_PIN_2); //PB2
gpio_init(GPIOC,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_10MHZ,GPIO_PIN_4); //PC4 复用
gpio_init(GPIOC,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_10MHZ,GPIO_PIN_13);//PC13
gpio_init(GPIOC,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_10MHZ,GPIO_PIN_14);//PC14
gpio_init(GPIOB,GPIO_MODE_IPD,GPIO_OSPEED_10MHZ,GPIO_PIN_10);//PB10 下拉输入
gpio_init(GPIOB,GPIO_MODE_IPD,GPIO_OSPEED_10MHZ,GPIO_PIN_11);//PB11 下拉输入
把公共端PB10 和PB11初始化为GPIO_MODE_IPD下拉输入模式GPIO_OSPEED_10MHZ输出最大速度10MHz,其余配置成GPIO_MODE_IN_FLOATING浮空输入模式,GPIO_OSPEED_10MHZ输出最大速度10MHz。
void Exti_Inteerupt_Config(void)
{
/*中断优先级配置*/
nvic_irq_enable(EXTI10_15_IRQn, 1U, 0U);
/* connect key EXTI line to key GPIO pin */
gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOB, GPIO_PIN_SOURCE_10); //PB0
gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOB, GPIO_PIN_SOURCE_11); //PB1
/* configure key EXTI line */
exti_init(EXTI_10, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_init(EXTI_11, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_interrupt_flag_clear(EXTI_10);
exti_interrupt_flag_clear(EXTI_11);
exti_interrupt_enable(EXTI_10);
exti_interrupt_enable(EXTI_11);
}
外部中断配置函数
nvic_irq_enable(EXTI10_15_IRQn, 1U, 0U); 配置外部中断优先级 1U抢占优先级,0U子优先级
gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOB, GPIO_PIN_SOURCE_10); 把 GPIOB Pin10配置外部源
exti_init(EXTI_10, EXTI_INTERRUPT, EXTI_TRIG_RISING);初始化EXTI_10 为EXTI_INTERRUPT外部中断,EXTI_TRIG_RISING上升沿触发
exti_interrupt_flag_clear(EXTI_10); 清除EXTI_10中段标志位
exti_interrupt_enable(EXTI_10); 使能外部中断
/*!
\brief Key Judge Function
\param[in] none
\param[out] none
\retval none
*/
void Key_Judge(void)
{
if (RESET != exti_interrupt_flag_get(EXTI_10)) //PB10里面的按键按下
{
gpio_init(GPIOB,GPIO_MODE_OUT_OD,GPIO_OSPEED_10MHZ,GPIO_PIN_10); //PB10 开漏输出
delay_1ms(20);
Key_PB10(); //判断是PB10里面的那个按键按下
gpio_init(GPIOB,GPIO_MODE_IPD,GPIO_OSPEED_10MHZ,GPIO_PIN_10); //PB10 下拉输入
exti_interrupt_flag_clear(EXTI_10); //清除中断
}
else if (RESET != exti_interrupt_flag_get(EXTI_11)) //PB11里面的按键按下
{
gpio_init(GPIOB,GPIO_MODE_OUT_OD,GPIO_OSPEED_10MHZ,GPIO_PIN_11); //PB11 开漏输出
delay_1ms(20);
Key_PB11(); //判断是PB11里面的那个按键按下
gpio_init(GPIOB,GPIO_MODE_IPD,GPIO_OSPEED_10MHZ,GPIO_PIN_11); //PB11 下拉输入
exti_interrupt_flag_clear(EXTI_11);
}
}
这是按键检测函数
if判断是哪个公共端触发的中断
gpio_init(GPIOB,GPIO_MODE_OUT_OD,GPIO_OSPEED_10MHZ,GPIO_PIN_10); //PB10 开漏输出 如果是EXTI_10 就把PB10引脚初始化为开漏输出,延迟20个毫秒是等待初始化完成,在调用检测引脚函数找出按键,最后再次初始化PB10为下拉输入,清除中断标志为。
/*!
\brief Key PB10 Function
\param[in] none
\param[out] none
\retval none
*/
void Key_PB10(void)
{
if(gpio_input_bit_get(GPIOA,GPIO_PIN_4) == RESET) {
PB10.ACC = 1;
} else if(gpio_input_bit_get(GPIOC,GPIO_PIN_4) == RESET) {
PB10.P_key = 1;
} else if(gpio_input_bit_get(GPIOA,GPIO_PIN_7) == RESET) {
PB10.double_flash = 1;
} else if(gpio_input_bit_get(GPIOA,GPIO_PIN_6) == RESET) {
PB10.right_turn_light = 1;
} else if(gpio_input_bit_get(GPIOA,GPIO_PIN_5) == RESET) {
PB10.left_turn_light = 1;
} else if(gpio_input_bit_get(GPIOA,GPIO_PIN_3) == RESET) {
PB10.return_key = 1;
} else if(gpio_input_bit_get(GPIOB,GPIO_PIN_2) == RESET) {
PB10.locus_minus = 1;
} else if(gpio_input_bit_get(GPIOB,GPIO_PIN_1) == RESET) {
PB10.locus_add = 1;
} else if(gpio_input_bit_get(GPIOB,GPIO_PIN_0) == RESET) {
PB10.reserved2 = 1;
}
}
按键判断函数就是挨个检测哪个引脚是低电平。
/*!
\brief this function handles Exti10-15
\param[in] none
\param[out] none
\retval none
*/
void EXTI10_15_IRQHandler(void)
{
Key_Judge(); //按键判断函数
}
总结
举例
当我按下K10的时候,初始化时我们把PA6初始化为浮空输入,看原理图3.3v电源是和PA6导通,我按下K10按键,PB11这里会导通,PB11初始化为下拉输入,并为EXTI_11的中断源,此时会跑到EXTI10_15_IRQHandler中断函数,在进入Key_Judge()函数里面,Key_Judge()函数里面会去判断是哪个中断源触发的,判断出是PB11后,马上初始化引脚为开漏输出,在进Key_PB11函数里面去读取连接PB11上的每根引脚电平,因为是开漏输出,所以当按键按下,会把连接的pin脚也拉低,这样就判断出是哪个按键按下,判断出来后在把PB11初始化为下拉输入,等待下一次按键的按下。