当前位置:   article > 正文

STM32矩形(矩阵)按键(键盘)输入控制LED灯 ——4*4矩阵按键源码解析_矩形按键连接

矩形按键连接

本文基于标准函数库的工程实现stm32F103C8T6使用4*4的矩阵按键控制LED灯的亮灭及闪烁等功能。

程序源码:链接:https://pan.baidu.com/s/1_MPhvMduKCTP0MPG-Gtw3A?pwd=2syk 
提取码:2syk

文章目录

一、矩形键盘介绍

1、硬件电路基本原理

2、两种识别方法介绍

3、硬件接线即使用

二、程序源码

1、矩阵键盘源码说明

2、主函数源码

三、实验现象


一、矩形按键介绍

1、硬件电路基本原理

矩阵键盘意思是指按键的电路排列类似于矩阵的按键,而不是按键的排列外表呈矩阵状。矩阵式键盘用N条I/O线作为行线,N条I/O线作为列线,构成了一个具有N*N个按键的矩阵按键。由图中可见,这个4*4一共16个按键的矩阵按键只需要接8个IO口,若采用单个按键接法,却需要16个IO口,由此可见采用矩阵键盘可以大大提高IO口的利用率。

其原理图如下:

2、两种识别方法介绍

一般对于矩阵键盘,有扫描法和反转法识别按键状态。

2.1  反转法

反转法找出每个按键的码,程序中判断8个引脚的状态,进行对比,判断出是那哪按键被按下,每个按键的码值由行码和列码构成。

我们以行为输入,列为输出。这里行输入端需要使用上拉输入(即四个行引脚均为高电平),输出需要使用推挽输出(输出为低电平),然后读取四个行输入的状态,若读到某一行为低电平时,则对应行被按下,这样就可以获取到行码。

用同样的方法,将行跟列的输出输入对调再进行判断,这样就可以得到行码,结合行列码,我们就可以知道是哪个按钮被按下。

2.2  扫描法

扫描法:令所有的引脚都为高电平(行为输出,使用推挽输出高电平,列为输入,使用上拉电阻输入高电平),这时我们配置第一行为0,然后判断各列的输入状态,如某一列出出现低电平,则可判断出是第一行的某一列被按下;如果没有出现低电平,则令第二行引脚为0其余引脚为高电平,判断各列的输入状态;如此反复,若没有输入没有识别到低电平就继续对三四行进行判断,如此就可以对四行四列进行判断。

3、硬件接线及使用

由上图可知整个4*4的矩阵键盘一共为8个引脚,其中C1、C2、C3、C4为列,R1、R2、R3、R4为行,这里将行接到PA0,PA1,PA2,PA3 ,列接到PA4,PA5,PA6,PA7。

二、程序源码

1、矩阵键盘源码说明

这里我们用扫描法进行矩阵按钮的识别,详细如下:

在函数初始化的时候给矩阵按钮的所有引脚配置成1(高电平),然后在实行逐行扫描,先令第一行为0(低电平),这是第一行的四个按钮进行判断(读取GPIO的引脚电平),若有按钮为0(低电平)时,即按钮被按下。当按钮被按下时,会将对应的键码传送到变量key中。

由于是机械按键,在按钮被按下的时候要进行消抖,然后在按钮按下的状态进行一个循环读取,当按钮松开后再对后面的按钮进行扫描,防止多个按钮同时按下时出现误判的情况。

第一行扫描完成且没有按钮被按下后,按照上面的方法对剩余的三行进行扫描。

将识别的子程序放在while循环函数中,可进行无限循环判断,这样我们对矩阵按钮的识别函数就完成了。详细程序看下方代码即后面的注释

  1. #include "stm32f10x.h"
  2. #include "key.h"
  3. #include "Delay.h"
  4. u8 FLAG = 0; //FLAG这个变量为1时,证明有按钮正在被按下
  5. void KEY_4x4_Init(void) //键盘IO口配置及初始化
  6. {
  7. GPIO_InitTypeDef GPIO_InitStructure;
  8. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  9. //使用GPIOA的0,1,2,3引脚为行 R1~R4对应矩形按钮的5,6,7,8引脚
  10. GPIO_InitStructure.GPIO_Pin = KEY_HANG; //0123
  11. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  12. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //使用推挽输出
  13. GPIO_Init(GPIOA, &GPIO_InitStructure);
  14. GPIO_SetBits(GPIOA,KEY_HANG); //令GPIO的0,1,2,3引脚输出为1
  15. /********************************************************************/
  16. GPIO_InitStructure.GPIO_Pin = lie1|lie2|lie3|lie4;
  17. //使用GPIOA的4,5,6,7引脚为列 C1~C4对应矩形按钮的4,3,2,1引脚
  18. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //使用上拉输入
  19. GPIO_Init(GPIOA, &GPIO_InitStructure);
  20. GPIO_SetBits(GPIOA,lie1|lie2|lie3|lie4); //令GPIO的4,5,6,7引脚输出为1
  21. }
  22. //端口配置后,GPIOA的所有端口输出均为高电平
  23. void KEY_Scan(u8 *key)
  24. {
  25. GPIO_Write(GPIOA,0x00fe); //第一行 0000 0000 1111 1110 低四位为行 高四位为列
  26. /*令第一行输出为低电平,这时再判断4个列的输入状态的值,
  27. 在按键没有被按下时,四列输出都是1,如果其中一列变为1,则可以判断S1按钮被按下*/
  28. if((lie1_Input==0)||(lie2_Input==0)||(lie3_Input==0)||(lie4_Input==0))
  29. {
  30. Delay_ms(10); //去抖动
  31. if(lie1_Input==0) //如果第一列被按下
  32. {
  33. FLAG = 1; //按钮判断变量
  34. *key = 1; //输出key的值为1传递到主函数,当值为x时,则说明按钮Sx被按下
  35. /*在变量前增加*,为c语言中的指针操作,使用指针进行地址传递,在子函数中修改的值在主函数中可以利用地址读取,
  36. 而不需要利用子函数返回值,然后主函数在增加一个变量进行接收*/
  37. while(!GPIO_ReadInputDataBit(GPIOA,lie1));
  38. //当按钮处于被按下的状态的时候,程序一直卡在循环读取按钮的状态,避免多按钮同时按下时读取错误
  39. }
  40. else if(lie2_Input==0)
  41. {
  42. FLAG = 1;
  43. *key = 2;
  44. while(!GPIO_ReadInputDataBit(GPIOA,lie2));
  45. }
  46. else if(lie3_Input==0)
  47. {
  48. FLAG = 1;
  49. *key = 3;
  50. while(!GPIO_ReadInputDataBit(GPIOA,lie3));
  51. }
  52. else if(lie4_Input==0)
  53. {
  54. FLAG = 1;
  55. *key = 4;
  56. while(!GPIO_ReadInputDataBit(GPIOA,lie4));
  57. }
  58. else //如果第一行四列中没有按钮被按下
  59. {
  60. FLAG = 0;
  61. GPIO_Write(GPIOA,0x00ff);
  62. }
  63. }//第一行判断完成,这是我们判断第二行
  64. GPIO_Write(GPIOA,0x00fd); //第二行
  65. if((lie1_Input==0)||(lie2_Input==0)||(lie3_Input==0)||(lie4_Input==0))
  66. {
  67. Delay_ms(10);//去抖动
  68. if(lie1_Input==0)
  69. {
  70. FLAG = 1;
  71. *key = 5;
  72. while(!GPIO_ReadInputDataBit(GPIOA,lie1));
  73. }
  74. else if(lie2_Input==0)
  75. {
  76. FLAG = 1;
  77. *key = 6;
  78. while(!GPIO_ReadInputDataBit(GPIOA,lie2));
  79. }
  80. else if(lie3_Input==0)
  81. {
  82. FLAG = 1;
  83. *key = 7;
  84. while(!GPIO_ReadInputDataBit(GPIOA,lie3));
  85. }
  86. else if(lie4_Input==0)
  87. {
  88. FLAG = 1;
  89. *key = 8;
  90. while(!GPIO_ReadInputDataBit(GPIOA,lie4));
  91. }
  92. else
  93. {
  94. FLAG = 0;
  95. GPIO_Write(GPIOA,0x00ff);
  96. }
  97. }
  98. GPIO_Write(GPIOA,0x00fb);//第三行
  99. if((lie1_Input==0)||(lie2_Input==0)||(lie3_Input==0)||(lie4_Input==0))
  100. {
  101. Delay_ms(10);//去抖动
  102. if(lie1_Input==0)
  103. {
  104. FLAG = 1;
  105. *key = 9;
  106. while(!GPIO_ReadInputDataBit(GPIOA,lie1));
  107. }
  108. else if(lie2_Input==0)
  109. {
  110. FLAG = 1;
  111. *key = 10;
  112. while(!GPIO_ReadInputDataBit(GPIOA,lie2));
  113. }
  114. else if(lie3_Input==0)
  115. {
  116. FLAG = 1;
  117. *key = 11;
  118. while(!GPIO_ReadInputDataBit(GPIOA,lie3));
  119. }
  120. else if(lie4_Input==0)
  121. {
  122. FLAG = 1;
  123. *key = 12;
  124. while(!GPIO_ReadInputDataBit(GPIOA,lie4));
  125. }
  126. else
  127. {
  128. FLAG = 0;
  129. GPIO_Write(GPIOA,0x00ff);
  130. }
  131. }
  132. GPIO_Write(GPIOA,0x00f7);//第四行
  133. if((lie1_Input==0)||(lie2_Input==0)||(lie3_Input==0)||(lie4_Input==0))
  134. {
  135. Delay_ms(10);//去抖动
  136. if(lie1_Input==0)
  137. {
  138. FLAG = 1;
  139. *key = 13;
  140. while(!GPIO_ReadInputDataBit(GPIOA,lie1));
  141. }
  142. else if(lie2_Input==0)
  143. {
  144. FLAG = 1;
  145. *key = 14;
  146. while(!GPIO_ReadInputDataBit(GPIOA,lie2));
  147. }
  148. else if(lie3_Input==0)
  149. {
  150. FLAG = 1;
  151. *key = 15;
  152. while(!GPIO_ReadInputDataBit(GPIOA,lie3));
  153. }
  154. else if(lie4_Input==0)
  155. {
  156. FLAG = 1;
  157. *key = 16;
  158. while(!GPIO_ReadInputDataBit(GPIOA,lie4));
  159. }
  160. else
  161. {
  162. FLAG = 0;
  163. GPIO_Write(GPIOA,0x00ff);
  164. }
  165. }
  166. }

2、主函数源码

这里用上GPIOB的10,11,12三个引脚接LED彩灯模块,对应为R,G,B(红,绿,蓝)三色,主函数中有两个子函数段,一个为端口初始化,另一个则是LED闪烁变换的程序段,其中函数的参数为闪烁间隔的时间。其现象为:按下S1,红灯亮;按下S2,绿灯亮;按下S3,蓝灯亮;按下S4,熄灭所有灯;按下S5,以0.3s的间隔RGB轮流闪烁一次;按下S6,以0.5s的间隔RGB循坏闪烁3次

  1. #include "stm32f10x.h" // Device header
  2. #include "Delay.H"
  3. #include "key.H"
  4. /****************************************************/
  5. /*引脚使用说明: */
  6. /* 矩形键盘: C1~C4对应GPIOA 4,5,6,7 */
  7. /* R1~R4对应GPIOA 0,1,2,3 */
  8. /* LED中的R,G,B对应GPIOB 10,11,12 */
  9. /****************************************************/
  10. void GPIO_Config(void) //对GPIOB进行配置初始化
  11. {
  12. RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOB,ENABLE );
  13. GPIO_InitTypeDef GPIO_Initstructure;
  14. GPIO_Initstructure .GPIO_Mode =GPIO_Mode_Out_PP;
  15. GPIO_Initstructure .GPIO_Pin=0X1D00 ; //0001 1100 0000 0000
  16. GPIO_Initstructure .GPIO_Speed =GPIO_Speed_50MHz ;
  17. GPIO_Init (GPIOB ,&GPIO_Initstructure );
  18. }
  19. void LED_RGB(float time)
  20. {
  21. u16 t =time *1000;
  22. GPIO_Write (GPIOB ,0X0400); // 0000 0100 0000 0000
  23. Delay_ms (t);
  24. GPIO_Write (GPIOB ,0X0800); // 0000 1000 0000 0000
  25. Delay_ms (t);
  26. GPIO_Write (GPIOB ,0X1000); // 0001 0000 0000 0000
  27. Delay_ms (t);
  28. GPIO_Write (GPIOB ,0X0000);
  29. }
  30. u8 key=0;
  31. u8 k =0;
  32. int main(void)
  33. {
  34. GPIO_Config ();
  35. KEY_4x4_Init();
  36. while(1)
  37. {
  38. KEY_Scan (&key);
  39. if(FLAG == 1) //按键按下
  40. {
  41. FLAG = 0;
  42. if(key==1) //按下S1,亮红灯
  43. {
  44. GPIO_SetBits (GPIOB ,GPIO_Pin_10 );
  45. }
  46. else if(key==2) //按下S2,亮绿灯
  47. {
  48. GPIO_SetBits(GPIOB,GPIO_Pin_11 );
  49. }
  50. else if(key==3) //按下S3,亮蓝灯
  51. {
  52. GPIO_SetBits(GPIOB,GPIO_Pin_12 );
  53. }
  54. else if(key==4) //按下S4,关闭所有灯
  55. {
  56. GPIO_Write (GPIOB,0X0000); //0000 0000 0000 0000
  57. }
  58. else if(key==5)
  59. {
  60. LED_RGB (0.3); //子函数参数为时间,单位为s
  61. }
  62. else if(key==6)
  63. {
  64. for(k=0;k<3;k++)
  65. {
  66. LED_RGB (0.5);
  67. }
  68. }
  69. }
  70. }
  71. }

三、实验现象展示

矩阵按键

本人也是初学STM32,在学习的同时以初学者的角度来理解说明,如果文章有错误的地方,请大家多多指正,谢谢!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/527906
推荐阅读
相关标签
  

闽ICP备14008679号