01-国产MCU兆易GD32实现矩阵按键扫描

一、矩阵键盘
    为了减少I/O口的占用,通常将按键排列成矩阵形式。在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。使用8个io口来进行16个按键的控制读取,可以减小io口的使用,用4条I/O线作为行线,4条I/O线作为列线组成的键盘。矩阵键盘检测方法主要有两种,一种是逐行扫描、一种是行列扫描。

1、逐行扫描
    通过在矩阵按键的每一条行线上轮流输出低(高)电平,检测矩阵按键的列线,当检测到的列线不全为高(低)电平的时候,说明有按键按下。然后,根据当前输出低电平的行号和检测到低电平的列号组合,判断是哪一个按键被按下。

2、行列扫描
    首先,在全部行线上输出低电平,检测矩阵按键的列线,当检测到的列线不全为高电平的时候,说明有按键按下,并判断是哪一列有按键按下。然后,反过来,在全部列线上输出低电平,检测矩阵按键的行线,当检测到的行线不全为高电平的时候,说明有按键按下,并判断是哪一行有按键按下。最后,根据检测到的行号和检测的列号组合,以判断是哪一个按键被按下。

二、程序设计

实现效果:逐行扫描矩阵键盘并打印出键值。
思路:保持一列输出高,重复扫描行。
接线:C为列,R为行
四列: PB1 PB2 PB10 PB11
四行: PA3 PA4 PA5 PA6

key.c

#include "key.h" uint8_t i=0,j=0;//行、列号 /* *@Function :key_Init *@brief :按键GPIO初始化函数 *@param :void *@retval : void */ void Key_Init(void) { //使能GPIO时钟 rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_GPIOB); //四列 PB1 PB2 PB10 PB11 作为输出 gpio_init(GPIOB,GPIO_MODE_OUT_PP,GPIO_OSPEED_10MHZ,GPIO_PIN_1); gpio_init(GPIOB,GPIO_MODE_OUT_PP,GPIO_OSPEED_10MHZ,GPIO_PIN_2); gpio_init(GPIOB,GPIO_MODE_OUT_PP,GPIO_OSPEED_10MHZ,GPIO_PIN_10); gpio_init(GPIOB,GPIO_MODE_OUT_PP,GPIO_OSPEED_10MHZ,GPIO_PIN_11); //四行 PA3 PA4 PA5 PA6 下拉输入 默认为低电平 gpio_init(GPIOA,GPIO_MODE_IPD,GPIO_OSPEED_10MHZ,GPIO_PIN_3); gpio_init(GPIOA,GPIO_MODE_IPD,GPIO_OSPEED_10MHZ,GPIO_PIN_4); gpio_init(GPIOA,GPIO_MODE_IPD,GPIO_OSPEED_10MHZ,GPIO_PIN_5); gpio_init(GPIOA,GPIO_MODE_IPD,GPIO_OSPEED_10MHZ,GPIO_PIN_6); //列初始化为低电平 gpio_bit_reset(GPIOB, GPIO_PIN_1); gpio_bit_reset(GPIOB, GPIO_PIN_2); gpio_bit_reset(GPIOB, GPIO_PIN_10); gpio_bit_reset(GPIOB, GPIO_PIN_11); } /* *@Function :Rank1_Scan(void) *@brief :第一行扫描函数 *@param :void *@retval : 0(可以返回行号i) */ uint8_t Rank1_Scan(void) { //第一列输出高,其它三列输出低 gpio_bit_set(GPIOB, GPIO_PIN_1); gpio_bit_reset(GPIOB, GPIO_PIN_2); gpio_bit_reset(GPIOB, GPIO_PIN_10); gpio_bit_reset(GPIOB, GPIO_PIN_11); //检测第一行按键状态,为高则按下 if(gpio_input_bit_get(GPIOA, GPIO_PIN_3)==1) { delay_1ms(10);//消抖 while(gpio_input_bit_get(GPIOA, GPIO_PIN_3)==1) delay_1ms(10); printf("KeyNumber:%d\r\n",KEY1); } //检测第二行按键状态,为高则按下 if(gpio_input_bit_get(GPIOA, GPIO_PIN_4)==1) { delay_1ms(10);; while(gpio_input_bit_get(GPIOA, GPIO_PIN_4)==1) delay_1ms(10);; printf("KeyNumber:%d\r\n",KEY5); } //检测第三行按键状态 if(gpio_input_bit_get(GPIOA, GPIO_PIN_5)==1) { delay_1ms(10);; while(gpio_input_bit_get(GPIOA, GPIO_PIN_5)==1) delay_1ms(10); printf("KeyNumber:%d\r\n",KEY9); } //检测第四行按键状态 if(gpio_input_bit_get(GPIOA, GPIO_PIN_6)==1) { delay_1ms(10); while(gpio_input_bit_get(GPIOA, GPIO_PIN_6)==1) delay_1ms(10); printf("KeyNumber:%d\r\n",KEY13); } gpio_bit_reset(GPIOB, GPIO_PIN_1);//将第一列拉低回原状态 return 0; }

主函数

#include "gd32f10x.h" #include "gd32f103c_eval.h" #include "systick.h" #include "key.h" #include "usart.h" int main(void) { systick_config();//系统时钟 //USART相关配置 Usart_Init(); Key_Init(); printf("Init OK!\r\n"); while(1) { Rank1_Scan(); } }

以上是行扫描实现思路,剩下的按键只需将剩下的三列依次保持一列输出高,重复扫描行即可。

三、实验现象

实际测试均能准确打印出键值。

四、程序优化

     行扫描程序有大量重复代码,可以使用循环语句嵌套条件选择语句将四列依次置高,这样就只需要一段通用的行扫描语句,降低重复率。


__EOF__

本文作者xiaohu
本文链接https://www.cnblogs.com/xiaohuzaixue/p/17494667.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   EternalH  阅读(420)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 提示词工程——AI应用必不可少的技术
· 地球OL攻略 —— 某应届生求职总结
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界
点击右上角即可分享
微信分享提示