你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F103 矩阵键盘4*4 16*16等任意矩阵 按键扫描程序

[复制链接]
STMCU-管管 发布时间:2021-6-7 17:43
基于STM32的按键扫描测试程序(学习记录):
1 @0 h+ J3 A/ F+ t, s" t6 v+ f
4 i3 X2 z' r, l5 t" |+ C' f

! c+ u' K  s+ e3 X! f* L: s& L1、粘贴代码时,粘贴在源文件存放的位置中(如:HARDWARE中的.c和.h文件),用C++编译器打开,而不是kei;最后keil会正常显示中文字符;1 B/ k$ A( o5 z* B
2、程序使用嵌套循环实现4x4按键扫描,如果IO口设置过乱时,将循环拆分即可;8 I2 q0 m& I3 L( @5 [8 O0 e
key4x4.h源文件' r8 f7 y! T1 j  p
  1. #ifndef __KEY4x4_H
    ( |5 m( i" ]" E9 d# U: l0 |4 F
  2. #define __KEY4x4_H         
    2 w: i5 q7 w% V0 G& J& B2 i* J# X
  3. #include "sys.h"
    % ^& b; N, v; W2 {+ }
  4. + j2 X" f( m- C; D+ u, |
  5. #define KEY_X(X)        PEin(X)                                // 尽量避免使用PD以上GPIO,便于移植;
    ! n2 O, E2 g- Y/ j8 R
  6. #define KEY_Y(Y)        PEout(Y)' w! {% o' U. f2 \. j3 C4 [
  7. 1 r' {+ J* y$ h6 s; n7 ~1 ]
  8. #define ALL_DOWN_KEY_Y        {        KEY_Y(11) = 0; KEY_Y(12) = 0; KEY_Y(13) = 0; KEY_Y(14) = 0;}
    0 C) V0 N. _! {' _7 p- X
  9. 2 ]) H" B5 x* i& v) U2 B
  10. void KEY4x4_Init(void);                // IO口初始化
    . p& r) V" l# A; k2 s. f; B
  11. u8 KEY4x4_Scan(void);                  // 矩阵按键反馈函数        // 可配置任意矩阵按键使用!!
    5 h) F5 W* o0 S# d
  12. u8 KEY16_Scan(void);2 w2 Z" h$ u. _" j% h
  13. - _- r# h- v7 |  Y/ _
  14. /**************
    ; o! x9 Z9 Y; }1 s- O6 X; f; J
  15. 按键扫描方案二:+ q+ ?: Z* l9 n8 O$ T
  16. 按键使用8个输入IO口, 且所有IO口一端接VCC/VSS;3 @9 Q: D5 v* N7 D

  17. ) D- H0 [- c$ Q' t6 k+ ^
  18. 程序框架:        6 f8 f  v: O0 e! F$ C
  19.         扫描检测哪两个IO口输入高/低电平;VCC/VSS
    " d& [* P% g2 D  |" ^
  20.         根据对应坐标,return对应编号;' U% U" w  d, `
  21. **************/
    % K8 ]- O& @% r) ^
  22. $ C& B$ o& X" G: }* W8 J4 @3 X
  23. #endif
    5 [2 R3 m; q! t6 W* W1 r2 C
复制代码
key4x4.c源文件
5 K# \. \3 a6 j: {
  1. #include "stm32f10x.h"
    7 g+ J: q# F% }0 O* U* ?7 l
  2. #include "key4x4.h"8 X0 ~9 L6 q$ e8 b7 @
  3. #include "sys.h" / U2 B3 q3 Z# U5 E# C
  4. #include "delay.h": a; h  r/ Z3 F
  5. #include "usart.h"8 ]3 s. D* c+ b. u3 X; M
  6. 6 W6 @- B1 l4 v, f# F7 g' H3 o) l- k" K

  7. ' Z2 V9 Y( f( q: j; m
  8. /*************************7 \, V6 Y6 U7 z9 H# b
  9. X:  g0 M  M4 n$ b% u+ k6 }. t! x
  10.         PEin        7-10
    4 H+ A! E# X- u0 n" z* t6 L
  11. Y:
    ' c  j" G' Z7 w- f3 G
  12.         PEout        11-146 V: V0 S# [0 u& p
  13. *************************/9 C8 e3 Y. m- U0 @9 `7 l
  14. : ?: n3 C) w- ^8 I

  15. 2 T# p8 }; Y) b' W
  16. // 矩阵按键初始化函数" c/ i- ~1 \2 \+ F. B2 U& b
  17. void KEY4x4_Init(void), Q  J! F. k2 w4 C4 Q9 t
  18. {
      B/ z/ J: C0 i) O1 w
  19.                 GPIO_InitTypeDef GPIO_InitStructure;6 A3 A' M6 [0 G3 |' j% M
  20. 9 F: m3 b' M/ L3 ~) R6 B$ k
  21.                 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);5 Q4 b; B. E0 m5 w0 V; _2 A9 Z

  22. + Y  W, Y" b& p) v
  23.                 GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10;//KEY0-KEY1( ?& e, s) o' W# u
  24.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //设置成下拉输入
    8 S" M2 v; B/ W0 K1 F# N6 D
  25.                 GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE- i* V9 N  h* D5 c; ]* M
  26. - |: W$ V* o- _8 B, S4 R' w6 @
  27.                 GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14;                                 //LED0-->PB.5 端口配置8 |8 Z: d# W7 W# c
  28.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //推挽输出: l4 @1 _/ U1 b6 ]
  29.                 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                 //IO口速度为50MHz
    & O, t! X" h, j# b( A4 n# E; N
  30.                 GPIO_Init(GPIOE, &GPIO_InitStructure);                                                         //根据设定参数初始化GPIOE% a! I" i) {$ e1 a" [0 M
  31. }
    4 V' Y9 X5 e, S$ ~
  32. ! G1 b: _3 _4 q0 m# \5 T
  33. // 使所有输出拉低;初始化;                // 可以使用define宏定义,执行速度更快,不用跳转函数!!# n3 q* R! D( d# i* k
  34. static void KEY_ALL_Pull_Down(void)9 I* W& @3 O8 r* h" F
  35. {# {, s: o8 e  X4 y  ]1 D
  36.         KEY_Y(11) = 0;0 N6 W# h/ J. N% [: F; C
  37.         KEY_Y(12) = 0;
    0 W& n4 o5 f; K/ D, B6 A
  38.         KEY_Y(13) = 0;
    1 |0 F1 \1 J& }, b% |  x& D
  39.         KEY_Y(14) = 0;# d4 _! {; w8 `3 }
  40. }
    * z7 p" \" o5 Q. e; t" e6 T
  41. ; y2 h3 k$ V9 G0 J. s: ~
  42. // 4x4按键扫描函数3 F& l) @5 F6 r0 @( g  N3 D
  43. // 使用一个嵌套循环,完成扫描X和Y;# x# K$ ?( v7 g
  44. // 原理: 通过Y 依次输出高电平,% Z  f7 s3 [* d5 V; G8 B
  45. //                                扫描X 那个IO口输入高电平;
    # `; M& ~: j) s7 Q
  46. // X轴:输入检查、扫描;
    9 g, t! U  s- }# I1 [0 Y+ E
  47. // Y轴:设置输出状态;+ X" }! M, l! ~* }8 t+ M
  48. // 该函数适合任意排列矩阵按键,只需修改循环中对应编号!!
    # I4 |/ t9 N! ^6 r7 j2 D
  49. // 注意: 1. 改变IO口时,该函数还需要改变循环中IO口编号;(可以定义好IO口编号,便于修改)
    + D+ E+ Q6 u5 I
  50. //                                2. 该函数同样有优先级问题! 即同时按下时,只反馈先被扫描到的(0-15标号最小的)
    & w5 B3 g/ ^; }& O6 E2 ^
  51. //                                3. 函数同一坐标轴的IO口编号必须相邻或能有 规律递增可寻;(否则无法用循环判断)
    ' I) H' Q- j8 f+ {& Y
  52. //                                4. 暂时未添加功能(模式):        按键复用 和 长按;
    * y+ G6 x, L' `. f
  53. // 2020-11-13                返回值调整为:1-16+ g( E- P1 I# ~0 O9 s# N
  54. // 11/14 不支持连按;解决重复反馈的问题;
    * z% m' A7 Y1 X  C/ K
  55. u8 KEY4x4_Scan(void)3 D! @, |& z) P' O% w9 H. d7 o
  56. {6 _' o$ s7 s7 f- Z
  57.         int i,j;
    $ I6 z7 i4 D, a+ N
  58.         u8 IO_Sign = 0;                                // 很简便的一个IO反馈方式标签!!!  且嵌套循环特有!!  // 能返回0-15,适合任意排列矩阵按键
    ! R  w+ r; l2 A' E0 L& ^( P
  59.         static key_up = 1;
    6 B& ]$ ?" w+ `7 ^
  60.         5 L: Q3 p; r( T4 X$ c
  61.         //KEY_ALL_Pull_Down();                                                                                // 初始化所有按键输出拉低;
    % n7 w' B9 u& `; K5 J
  62.        
      Q& p! J. m9 G& x) a
  63.         for (i = 11; i <= 14; i++)                                                        // Y输出IO口编号;
    3 g, Y4 T$ g% S
  64.                 for (j = 7; j <= 10; j++,IO_Sign++)                // X输出IO口编号;  // 递增IO_Sign,反馈对应值(0-15);
    9 [8 G- B' i* {! Q4 O7 K2 k
  65.                 {6 N" d7 ^  I2 q& L  A: _
  66.                         KEY_Y(i) = 1;                        // 使PEout(i)输出高电平;6 S- L1 n0 ]  `3 {- F+ U* w' B
  67.                         6 [7 t1 s) v! h5 f
  68.                         if (KEY_Y(i))                        // 扫描Y输出高电平, 可以取消此判断; 因为必须输出高电平时,才能正常判断!!2 w9 @- j) L. o4 O1 P* n
  69.                         {3 r4 f: k% H" d
  70.                                 if (KEY_X(j) && key_up)                // 当输入检查到高电平时;, |( \6 v" T0 q1 H: @9 ?
  71.                                 {( }, h7 W% K. [1 a; x. D
  72.                                         key_up = 0;
    2 R1 O$ t8 y+ u3 |8 h3 T
  73.                                         printf("按键扫描反馈: %d  \r\n",IO_Sign);
    9 k* c; ?8 f$ P9 S2 Q
  74.                                         return IO_Sign;. a, P2 d9 Y! X2 }
  75.                                 }
    + K6 I. d7 X0 h6 P
  76.                                 else if (!KEY_X(7)&&!KEY_X(8)&&!KEY_X(9)&&!KEY_X(10))                        // 当所有输入检测到低电平时,再次使能按键; 防止重复反馈8 M3 V7 E% }% s, ]
  77.                                 {
    8 @3 y$ }% p) a9 ?, p+ O
  78.                                         key_up = 1;
    2 n4 [& Y! c7 i8 [( c+ T
  79.                                         KEY_ALL_Pull_Down();                                                                                // 初始化所有按键输出拉低(低电平);必须在此位置;! L2 Q0 q' _7 N
  80.                                 }0 L3 h$ L# a: C4 ?
  81.                         }3 ~) s, h0 Y: y6 v0 ?
  82.                         else) M" M  |* Z) i4 P: c
  83.                                 printf("PEout:IO口%d输出异常!  \r\n ", i);
    ' h/ k; h7 w- z+ ]7 M
  84.                 }
    5 {9 m8 |/ c& p9 M" Y+ [% @. ^# o
  85.                 % J! ~9 n! d6 a5 z& @$ s% `
  86.         delay_ms(10);                                        // 按键防抖;1 f% i+ O+ p' r! J5 o3 |
  87. }
    + B9 m( B* ?# F

  88. 1 ?: y6 b0 Q6 L! I3 t, V

  89. $ [  h4 d6 Y$ C2 _8 ?( h/ ?! V
  90. /******************************************标准扫描函数*********************************************/
    0 ?3 T$ R, a% h
  91. // 支持连按( Z. t0 L/ I- `) k# V9 n2 i# J
  92. u8 KEY16_Scan(void)
    0 ^9 T2 B& ~; K; h. @, b: d) g
  93. {
    5 K+ x5 H. N. }5 @
  94.         int i,j;
    : Q! {8 p" p& d$ P
  95.         u8 IO_Sign = 0;                                // 很简便的一个IO反馈方式标签!!!  且嵌套循环特有!!  // 能返回0-15,适合任意排列矩阵按键+ h& |0 N. ~) a
  96.         7 \2 [: f8 d. p" n& u; J) d
  97.         ALL_DOWN_KEY_Y                                                                                                        // 初始化所有按键输出拉低;& W! Q3 O0 y5 X. @0 k* s( t- u
  98.        
    . O% B8 M  u6 m- [$ X
  99.         for (i = 11; i <= 14; i++)                                                        // Y输出IO口编号;
    " v& x2 J6 a, o* @1 L* v% q% p
  100.                 for (j = 7; j <= 10; j++,IO_Sign++)                // X输出IO口编号;  // 递增IO_Sign,反馈对应值(0-15);5 H' f8 O  m1 i; Q: O3 S9 P
  101.                 {7 G- x4 [' R, ^0 k3 |5 {
  102.                         KEY_Y(i) = 1;                        // 使PEout(i)输出高电平;# t5 m& n% d2 g/ l
  103. 8 ^  ~& ], g1 S" J$ z# I1 R
  104.                         if (KEY_X(j))                        // 当输入检查到高电平时;
    1 s2 s$ g9 i, }
  105.                                 return IO_Sign;
    ; v8 [* B9 A% S# @. ^! c
  106.                 }
    " l! p3 ^2 x0 m. G
  107.                 2 T) \% k0 Y2 N+ C8 e% c' x
  108.         delay_ms(20);                                        // 按键防抖;                // 连按延时;' o0 M# ~4 E$ @2 a
  109. }
    ; P3 i. W. N3 |5 C: ?/ W5 |+ j

  110. 1 n7 u; O! O0 ~" R( a
复制代码
" H3 C) C1 Z, L" p
8 ]$ \- @& k; T' @
*4x4按键原理图9 H4 J( H, w: d3 }3 E
1.png
, {  D( H! u1 J- o( ?3、按键工作原理:0 K! f4 V8 ]7 P; D6 w
当按键被按下时,相连的电路导通;即S1按下时,位于0行0列的线短路,使标号4和5对应的IO口相连(导通);
* k- W6 }" l* f; Z% Y8 F4 w$ `3 y1 o最后通过扫描检测输入输出状态即可判断出对应按键被按下;- F7 i( y. d1 t8 E2 c
$ K# x9 \- `; Y) O) W) r
: z' p5 X/ F  x% e- H) S
4、程序设计思路:
  x: d0 r6 [2 m3 ?程序通过依次使标号1、2、3、4(列0-3)输出高电平,判断5/6/7/8(行0-3)状态;完成按键扫描;
2 f( W3 Q& Q4 H& n& v% `# n. @/ S, X0 u( ?; X: l% K

8 x- [* u6 I$ `- f( A
# G% f8 p- i# L; p" D' g. r( q
' {, w1 r) c  Q' x) y! `2 p! ~
赞 收藏 评论0 发布时间:2021-6-7 17:43

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版