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

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

[复制链接]
STMCU-管管 发布时间:2021-6-7 17:43
基于STM32的按键扫描测试程序(学习记录):
) y/ L5 ?8 E9 i( _) ?$ Y; H0 l6 W6 O
% d" t+ ]) G/ I0 D0 A) ]
0 q, m0 s  p1 F; \# m+ w
1、粘贴代码时,粘贴在源文件存放的位置中(如:HARDWARE中的.c和.h文件),用C++编译器打开,而不是kei;最后keil会正常显示中文字符;# G! l& d) o2 [  `2 x
2、程序使用嵌套循环实现4x4按键扫描,如果IO口设置过乱时,将循环拆分即可;
3 O' N! h# Y; ^) e9 jkey4x4.h源文件
8 f& H! n. U, m$ [; h' ?
  1. #ifndef __KEY4x4_H. U2 S  B* g7 Q" t0 G
  2. #define __KEY4x4_H         ) a( D) V) C$ W: `0 X/ Q2 |8 T
  3. #include "sys.h"
    8 X$ r: l, t) o9 R: e
  4. - p) x4 F/ \/ f9 k
  5. #define KEY_X(X)        PEin(X)                                // 尽量避免使用PD以上GPIO,便于移植;4 C+ _6 U8 Y, I( w' G
  6. #define KEY_Y(Y)        PEout(Y)
    - F# {  b* L) Y8 F7 B& p
  7. 7 u; z: @% I, k3 a! ?# g
  8. #define ALL_DOWN_KEY_Y        {        KEY_Y(11) = 0; KEY_Y(12) = 0; KEY_Y(13) = 0; KEY_Y(14) = 0;}8 K! v( q& k4 W, m) h' k

  9. ( P  k5 W9 H1 X, y# u. H
  10. void KEY4x4_Init(void);                // IO口初始化9 Z/ D5 {4 j5 U# @5 j2 y4 t
  11. u8 KEY4x4_Scan(void);                  // 矩阵按键反馈函数        // 可配置任意矩阵按键使用!!
    4 v6 Y% ?% h0 U* w5 ^1 z: ^2 u8 t( |
  12. u8 KEY16_Scan(void);* g" o# f" X' a9 w
  13. 3 n* E! X7 Y: P4 w
  14. /**************
    & f& @  s/ ]- s: E
  15. 按键扫描方案二:
      L6 b, z. l$ ^4 E/ d! R# K4 o
  16. 按键使用8个输入IO口, 且所有IO口一端接VCC/VSS;
    . u: n+ U( C2 V0 Z8 D0 i

  17. . r! ?2 t% P3 G/ N$ R/ O
  18. 程序框架:       
    : z; M/ n( n* S  n. U
  19.         扫描检测哪两个IO口输入高/低电平;VCC/VSS4 Y/ _: c5 L4 c, N; p# B
  20.         根据对应坐标,return对应编号;8 X" v$ c1 F; |, G; z( |- J4 S
  21. **************/
    9 q# w! L* {, m

  22. " n& r( X* s, m8 r4 }/ M& F
  23. #endif
    + z3 z' w- ~7 [. m
复制代码
key4x4.c源文件
8 {  }% t4 s0 V' {
  1. #include "stm32f10x.h"
    9 L# }2 a7 H' K+ ?% Q
  2. #include "key4x4.h"6 b$ I# H" M$ {& A
  3. #include "sys.h" 9 @2 H7 I& o  @6 ]
  4. #include "delay.h"
    # C) @: J( i" x7 R6 N/ q) {) |
  5. #include "usart.h"
    . e; k3 q, C0 Q( ]+ A! w
  6. / f& t4 b  e2 C9 M% Q4 h
  7. % H0 v+ J: E' a" t& v& t2 t
  8. /*************************5 y! ?! I' e1 I% {; y) w+ ]
  9. X:
      i0 [0 c: w/ G2 U* I4 Y( ?
  10.         PEin        7-10
    $ Z; I6 e3 ]. C+ m# Q( T
  11. Y:4 z% s  ~$ U0 s; W+ n6 e
  12.         PEout        11-14/ S* ]( J: q2 `$ g; L  E
  13. *************************/' D' H5 I" A! `2 j& H

  14. , W( x, N, C) k- m+ T2 x" s" \

  15. ) \, u4 M/ u% c; X
  16. // 矩阵按键初始化函数
    3 y- x$ \+ I& t! o
  17. void KEY4x4_Init(void)
    1 Y# N/ i& I: x# _
  18. {+ w; Z* e# x' H& q3 h7 J4 Z
  19.                 GPIO_InitTypeDef GPIO_InitStructure;# M( f( R* Y0 Q! {
  20. 2 d# E' n. J4 ]: \- S2 b; H' b: i
  21.                 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
    & X) u5 [% g4 C- }1 M; {

  22. 4 \8 e3 W/ u+ ^# I8 Z
  23.                 GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10;//KEY0-KEY1
    ; r. M! w5 W: B6 `
  24.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //设置成下拉输入
    4 V; _8 W! T, X! |
  25.                 GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE1 B# i, N& R# {. u6 V7 ~

  26. 0 E0 _( l* W5 M6 B' `
  27.                 GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14;                                 //LED0-->PB.5 端口配置
    6 _! N' f  V; L$ L0 m
  28.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //推挽输出# i" V& q4 y" X1 e$ U1 t. t) l% ?
  29.                 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                 //IO口速度为50MHz" m9 j; f( [  K5 j& J
  30.                 GPIO_Init(GPIOE, &GPIO_InitStructure);                                                         //根据设定参数初始化GPIOE/ z* h; w9 @: a* s7 l8 h9 ~
  31. }
    ' k; O( y. Q: p' m$ O; T; w3 C

  32. 6 \. ?/ R, `2 n- Z7 u( _6 u
  33. // 使所有输出拉低;初始化;                // 可以使用define宏定义,执行速度更快,不用跳转函数!!
    9 q  F( }5 _. @* q  `! P! S/ i/ {
  34. static void KEY_ALL_Pull_Down(void)( d" f7 f# U( O8 x! c
  35. {
    ; U# [' e- u6 H, j/ a6 j' g
  36.         KEY_Y(11) = 0;' c" H& Y% R  \$ j, D: Q# Z. c
  37.         KEY_Y(12) = 0;& n/ T3 j. J1 ~: v, e
  38.         KEY_Y(13) = 0;
    7 V% V* k! ^, h
  39.         KEY_Y(14) = 0;
    3 O. b; q6 `9 b. S" V& B6 D. I4 V, M
  40. }7 u# t& t& Z6 M) q& C& T5 a- B. J$ H
  41. ! Z' f) W+ m' t  y; G: Q  |
  42. // 4x4按键扫描函数+ M4 ~9 W4 t: S3 r" O" w1 A( `
  43. // 使用一个嵌套循环,完成扫描X和Y;0 @) F' V' v0 ]+ V; m
  44. // 原理: 通过Y 依次输出高电平,
    9 p. c: Y6 s  u( c. A$ K
  45. //                                扫描X 那个IO口输入高电平;3 o8 i3 Z9 U$ [% R
  46. // X轴:输入检查、扫描;
    2 r5 n- \- S$ z7 h9 C& J8 C- U8 e
  47. // Y轴:设置输出状态;
    6 d( ~' }6 R& b  t: A
  48. // 该函数适合任意排列矩阵按键,只需修改循环中对应编号!!
    ( U7 }& Z& x" J
  49. // 注意: 1. 改变IO口时,该函数还需要改变循环中IO口编号;(可以定义好IO口编号,便于修改)& A; P/ R" G- I; E% B& ?, F
  50. //                                2. 该函数同样有优先级问题! 即同时按下时,只反馈先被扫描到的(0-15标号最小的)+ u' c. Q% K, N6 n0 g
  51. //                                3. 函数同一坐标轴的IO口编号必须相邻或能有 规律递增可寻;(否则无法用循环判断)
    3 X/ ?3 g) O0 c1 Z4 C( F1 m! x+ D* o
  52. //                                4. 暂时未添加功能(模式):        按键复用 和 长按;6 ?' R0 }" z  L# S
  53. // 2020-11-13                返回值调整为:1-16
    ( M3 S: E. M+ E3 r6 F
  54. // 11/14 不支持连按;解决重复反馈的问题;
    0 f7 d0 N# Z2 Y# h/ D
  55. u8 KEY4x4_Scan(void)
      F# H& [' R' |1 g' z# o- w
  56. {
    " _; Z* h7 K# ]( W: J
  57.         int i,j;" @8 j0 S" E2 }% l' `  b1 G3 M
  58.         u8 IO_Sign = 0;                                // 很简便的一个IO反馈方式标签!!!  且嵌套循环特有!!  // 能返回0-15,适合任意排列矩阵按键; V9 Q  \+ j" R; |/ ]3 w
  59.         static key_up = 1;
    5 k& u4 I  _' H$ w% Q+ ?, i5 w
  60.         / B$ u& D5 G1 L5 v* F3 E
  61.         //KEY_ALL_Pull_Down();                                                                                // 初始化所有按键输出拉低;
    6 v; R1 F: `0 i5 z+ S: ]
  62.         9 _: M7 p+ Z% C* p+ b: ?
  63.         for (i = 11; i <= 14; i++)                                                        // Y输出IO口编号;8 c/ z% J" \% q" M; k
  64.                 for (j = 7; j <= 10; j++,IO_Sign++)                // X输出IO口编号;  // 递增IO_Sign,反馈对应值(0-15);
    # s2 X. b# h  K: z3 C( ?
  65.                 {' @. \. ^' A% E& F
  66.                         KEY_Y(i) = 1;                        // 使PEout(i)输出高电平;
    ; Z0 B' C1 |; X2 v. P
  67.                        
    ! m' q% K" L0 Y9 z. p; [
  68.                         if (KEY_Y(i))                        // 扫描Y输出高电平, 可以取消此判断; 因为必须输出高电平时,才能正常判断!!
    : I, k' n* [' {+ w( s3 j; A8 p
  69.                         {$ |. {4 y9 F+ r) J
  70.                                 if (KEY_X(j) && key_up)                // 当输入检查到高电平时;
    4 |3 n- d, `: Z: d
  71.                                 {$ j3 i8 E; X: Q6 ?7 M& x/ R. i
  72.                                         key_up = 0;4 V  S' Z9 S. |8 U2 P* ]) W( y
  73.                                         printf("按键扫描反馈: %d  \r\n",IO_Sign);
      p3 n/ K7 ~5 _: e3 R+ q; J
  74.                                         return IO_Sign;
    7 D$ F% h+ r" f/ S% W
  75.                                 }
    - Y4 X( q; ?1 X5 m1 w
  76.                                 else if (!KEY_X(7)&&!KEY_X(8)&&!KEY_X(9)&&!KEY_X(10))                        // 当所有输入检测到低电平时,再次使能按键; 防止重复反馈
    3 y1 D$ Z' |' M; p; k6 y
  77.                                 {, k0 B' q$ ^" _6 {) O
  78.                                         key_up = 1;; A1 |$ q0 k  _( z( P
  79.                                         KEY_ALL_Pull_Down();                                                                                // 初始化所有按键输出拉低(低电平);必须在此位置;
    ; B6 q4 c' D- L1 [) L
  80.                                 }; E) |7 ~, z0 L& P# w* N5 c) J
  81.                         }
    ) T/ z! T9 s* S, ~! v$ W+ a
  82.                         else
    4 C" J( `$ ]: ?% n
  83.                                 printf("PEout:IO口%d输出异常!  \r\n ", i);
    ' T( K' [, W6 E+ J: T* [
  84.                 }6 ?; ~) b/ h+ w# v; W& ^! q: s
  85.                
    5 I' N& |4 N3 N* `1 V- w/ ^
  86.         delay_ms(10);                                        // 按键防抖;; j7 a. d( W& T, N$ m, h3 P7 R  j
  87. }
    2 P. g- N$ u) I% W2 N

  88. $ k) c( W3 z, W" [2 Z4 V9 G
  89. , y8 D2 s6 p( i- z% ^$ r
  90. /******************************************标准扫描函数*********************************************/
    ( f8 f( `  z1 E9 z( R) V3 ^) ^4 I
  91. // 支持连按* Z. y3 a, I' L; y; U$ z
  92. u8 KEY16_Scan(void)
    / J7 X; l% `* r$ k$ n- s/ z
  93. {
    / S  j4 v) ?7 A6 b: b
  94.         int i,j;( \: N" D: H- z. I5 F5 E/ s
  95.         u8 IO_Sign = 0;                                // 很简便的一个IO反馈方式标签!!!  且嵌套循环特有!!  // 能返回0-15,适合任意排列矩阵按键
    , C  P1 c) I4 `7 O
  96.         # Y& E6 U$ r# T$ G0 A* E- y4 @5 U
  97.         ALL_DOWN_KEY_Y                                                                                                        // 初始化所有按键输出拉低;* w8 @1 n" g& a) f5 F
  98.        
    8 P) l  b0 p0 L7 u
  99.         for (i = 11; i <= 14; i++)                                                        // Y输出IO口编号;/ K% I. L7 C: B  j
  100.                 for (j = 7; j <= 10; j++,IO_Sign++)                // X输出IO口编号;  // 递增IO_Sign,反馈对应值(0-15);9 m/ }! v& D: E: t, e% {2 h
  101.                 {; O; }! {7 g, s8 _5 ]7 D
  102.                         KEY_Y(i) = 1;                        // 使PEout(i)输出高电平;9 B+ k3 t! a3 I# V3 _5 f
  103. 2 A0 r* y6 }% I0 A& `
  104.                         if (KEY_X(j))                        // 当输入检查到高电平时;8 |5 ~& c1 [/ S# i2 B
  105.                                 return IO_Sign;
    7 O! l, Z. [# J! ?  R! Z
  106.                 }
    0 y2 e. ~! t( k
  107.                
    / D% m* c) i  ^9 {8 N' S0 \" Y( r; A
  108.         delay_ms(20);                                        // 按键防抖;                // 连按延时;+ \4 @7 M' H5 {5 V; K
  109. }
    " v' O, A2 u5 B# I% E2 j' g

  110. / U) T! F; s4 V" _
复制代码

; b4 ?: v, ]! n3 c. k. I9 V# `+ \

3 `; c; W; @+ m1 K4 S5 n; }*4x4按键原理图" u& s6 m* a5 Q5 M4 J+ o6 S
1.png % Z; q- g8 U6 k8 ?8 Y" ]2 j7 Q# ^
3、按键工作原理:
1 l! i+ i5 S, N5 ?' I, P当按键被按下时,相连的电路导通;即S1按下时,位于0行0列的线短路,使标号4和5对应的IO口相连(导通);
! d* K6 B1 N* E' c- `) I' A8 o最后通过扫描检测输入输出状态即可判断出对应按键被按下;5 d) I" Y0 b: X7 _4 y

& F" _; t& g' k# \6 ~1 H' x; C

8 ?* y- ^$ M* H# S: O4、程序设计思路:
. o) _) l) E6 [# |* V! j3 g$ x程序通过依次使标号1、2、3、4(列0-3)输出高电平,判断5/6/7/8(行0-3)状态;完成按键扫描;# F8 S+ s, ~$ j. @" Q# P7 s( a
5 e! r3 K5 f; ?4 z% }3 r

& d) z; @1 h2 Q5 {6 M0 r, m$ E6 N; P
4 x' ?3 g  O* _. O
收藏 评论0 发布时间:2021-6-7 17:43

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版