一、按键原理
5 i& _) ?$ C1 f- h; |( n4 o# e按键电路原理图(CT117E-M4产品手册)
( E7 S: i4 a% ^& u7 Q# j
, M- _1 G, Z: P$ b: g- U1 ~
! l5 l& }' V5 U这四个按键一端都接了VDD,所以默认高电平,当我们按下按键时,电路闭合,IO口电平从高电平到低电平,检测IO口电平的变化就是判断按键是否按下的依据。9 Y9 R: x8 V J) g$ K4 T& p
4 l* K; ?+ l7 A4 p
由于按键默认上电为高电平,所以可以选择浮空输入模式,该模式只是默认输入值不能确定,但是这里是接的VDD,也就是默认输入值高电平。而上下拉输入模式,默认输入值是确定的。读取输入结果时,只有0或1两种,只是默认值不能确定- R* ^# @8 k3 i0 Q4 ]# n$ s8 S
! ?3 ]- _7 K( I
在单纯作为输入的时,浮空模式是有用的,在外部有上拉/下拉的条件下,可以设置为浮空输入。或者IO有冲突的时候,也可以设置为浮空输入,从而完全不干扰其他IO; W7 L2 X9 T+ p: p0 P/ o) y
! ~; o/ v8 d& [9 t4 Y. K+ ~对比一下正点原子F4按键实验模式选择:KEY0,1,2选择的是输入上拉,KEY_UP选择的输入下拉: P& Z8 e* @ K8 n: ^
0 N/ [) R5 {$ y5 H) k
- ?% I0 M' ~, r& ^, v0 F8 |) u
' H% Z# A* ]) {1 Z) G9 ^5 VKEY0、 KEY1 和 KEY2 是低电平有效的,而 KEY_UP 是高电平有效4 [, H+ U( v9 P& Z# A
的, 并且外部都没有上下拉电阻,所以,需要在 STM32F4 内部设置上下拉,STM32G4是可以看到外部接了上拉电阻的,所以程序里面没有设置上下拉模式9 c* r, C9 p6 N2 |) P! }
- t5 B' Q. _8 ?9 U- \输入上拉:无论输入管脚悬空或者被高电平驱动时,读取的都是1. 只有在输入端为0的时,读取到的值才是0。
0 I9 F3 E* ~" n& I/ u) P$ p) G3 q: |/ l: h0 o+ M
要判断KEY0,1,2的IO口电平,只有按键按下了,输入端为0 ,才能检测读取到低电平,所以这三个引脚选择输入上拉模式
# O6 x( g' W" G: |" H; Z
! B( ]; L% L: F9 R4 _输入下拉:无论输入管脚悬空或者被低电平驱动时,读取的都是0. 只有在输入端为1的时,读取到的值才是1。
9 c6 F. g4 X' m* U# S6 u/ B& l( Q! |2 b) R9 [" d% e3 ^/ b
要判断KEY_UP的IO口电平,只有按键按下了,输入端为1,才能检测读取到高电平,所以这这个引脚选择输入下拉模式 D9 H7 A! a& @2 h
3 L8 n: Z$ e: @$ kGPIO模式详细介绍:GPIO模式8 i, T5 v) S7 \: n5 s
) ]! F) V. b6 e& ]5 V' p1 H- C二、程序编写
, f0 T/ H8 [# `: }# t% T) W按键GPIO设置为浮空输入,使用STM32CubeMX配置2 p5 S( j" v0 C3 p9 ^' m
( r$ ~( ]8 z- N: @
( j' @. I+ Q/ ~5 \+ Y* S/ U
& O6 D: [' X- [$ y3 K将里面按键IO的初始化移植到LED的工程下。
! D, n1 N# Q. f6 ]3 A/ F3 ]; [& t
) e4 R+ k' g1 {# R9 |- v) { H9 I* v1.按键扫描函数
0 n# I. x' W) }- unsigned char Key_Scan(void)4 {3 f: x# h8 m) ]: q1 o
- {# I1 g# a3 l/ Q z) T2 t. \) \
- unsigned char unKey_Val = 0;) T! [4 y' s' \" M7 G
- ! n/ K& y. d4 c0 w0 `
- if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET); s; W& g( d0 C" l
- unKey_Val = 1;- H7 T; {8 e! }7 G
- 9 ]$ L! W8 g$ B- L
- if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET)
+ b/ M! | v, O3 l8 v - unKey_Val = 2;/ s/ R/ U; \* \$ [. {5 Z- T
+ f: q7 q: D v! c" D% d. Q4 A- if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET)
- E9 P( u& l, U( X+ } - unKey_Val = 3;1 _: {1 c% w8 J; z$ C, Y) K; M+ P
- 4 E* J! N$ r0 [
- if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
8 \9 r+ z: A1 Q# M& | - unKey_Val = 4;
' q" G" i e& L: O# z - / P8 t* t, f& ]& E& v( E3 X
- return unKey_Val;" ~4 F# A. x" ?+ L# ?
- }
复制代码 $ B. Z. |3 t' o) }
2.按键处理函数8 f5 v5 G. z: ]/ ^" N
: H! ]* T% H: k1 x/ ~- __IO uint32_t uwTick_Set_Point = 0;
6 \4 ~. }$ g7 C; Q1 ^2 I; v
# r7 k. x: |9 e- _ f- unsigned char ucKey_Val,ucKey_Down,ucKey_Up,ucKey_Old;6 w) M2 D0 H( k% G" }/ X
- void Key_Proc(void)9 E B4 }( Q& S3 V& [8 I
- {- `& Z/ w; I5 b# M1 s
- // uwTick每隔1ms加1 刚开始肯定差值大于100ms
1 B5 g9 ]2 h& s, i1 U - if((uwTick -uwTick_Set_Point) < 100) return; // 每隔100ms扫描一次 * n+ n% p0 Z' g' d- X A7 ?2 r
- uwTick_Set_Point = uwTick; // 记录每次扫描时的uwTick值5 H. G& w9 U0 m' u
- ; y0 Z8 \( S2 q5 G
- ucKey_Val = Key_Scan();
" b' `' s5 \! S - ucKey_Down = ucKey_Val & (ucKey_Old ^ ucKey_Val);* Q4 r) \9 A4 n Q% a8 ^# G: F
- ucKey_Up = ~ucKey_Val & (ucKey_Old ^ ucKey_Val);
- G; i+ f- ]+ E0 c: l - ucKey_Old = ucKey_Val;
/ T1 N- h% u# p" U; G8 L -
4 E0 U% n/ ^3 @+ Z @& b( R+ K - if(ucKey_Down == 4)( m# z" U# C- F9 L* l
- {' B$ F( C0 b5 V; U( n8 ~3 H6 f3 ?
- LED_Display(0x88);
$ F; S3 k$ F8 w6 B+ x - }2 f. Q. a( \& E7 c; ~9 I, M
- if(ucKey_Down == 1): h8 @* B+ t" J% N( \+ r
- {
% o* G8 @8 |( n7 x. X4 v - LED_Display(0x00);, Y0 w# j$ @) h, Z) z
- }% {1 P+ ?/ d: n" M9 R$ |
- }
复制代码- &(按位与): 两个操作数都为1 ,才为1 1&0 = 0 0&1 = 0 1&1 = 15 s- H& \+ K1 D0 I
- |(按位或):两个操作数只要有一个为1 ,结果为1 1|0 = 1 1|1= 1 0|0 = 0
( B- q& D; u6 u; |4 A - ^(按位异或):两个操作数相同为0 ,不同才为1 0^0 = 1 1^0 = 0# g4 t+ `% C- `
- ~(取反):0变为1 ,1变为 0 ~0=1
复制代码
. f( M5 t; k! h位运算参考:位运算, S; V" ~+ l8 l. a
) e% c4 y. {! V
按键扫描可以分为三种情况:
. l+ T4 x8 v) A8 [ n4 x
, z4 k$ e8 i$ |% _9 I+ ]- 情况1 : 100ms扫描了两次,按键返回的结果从0 变为4(按键4被按下了),产生了下降沿9 ?( O; S. J5 f6 A* y9 j
- ucKey_Val = 4 (0000 0100)
& D4 ^- ?- g$ K4 i - ucKey_Down = 0000 0100 & (0000 0000 ^ 0000 0100) = 0000 0100 & 0000 0100 = 0000 0100 =41 {! a& ?! |! V# \
- ucKey_Up = ~0000 0100 & (0000 0000 ^ 0000 0100) = 1111 1011 & 0000 0100 = 0
) U, q) s2 `7 ^2 p! G* C - ucKey_Old = 4
6 F! V7 t# ?' f" m - 8 K. B! P5 a, T+ H6 P- n( t
- 情况2 : B4产生了下降沿后,按键一直按着' Z }/ a. _* U& q/ B- |1 N- x
- ucKey_Val = 40 ] {2 W5 u# W* m& M
- ucKey_Down = 0000 0100 & (0000 0100 ^ 0000 0100) = 0000 0100 & 0000 = 0
4 w: L2 [1 c, ~( g: h3 O - ucKey_Up = 1111 1011 & 0000 0000 =0
8 O/ |* X" ]- Z2 B3 P+ t1 \; R - ucKey_Old = 0000 0100 = 4% ?) N8 m1 y0 @+ Q6 @# U" p" R
- 9 m5 I" e7 B% o
- 情况3 : B4按键一直按下后在松手时产生上升沿这个时候
( K d: J2 W8 K2 A' E0 H - ucKey_Val = 0+ g4 \/ M) ]9 a
- ucKey_Down = 0000 0000 & (0000 0100 ^ 0000 0000) = 0000 0000 & 0000 01000 = 0
8 V; k T; g9 u4 s4 C - ucKey_Up = 1111 1111 & 0000 01000 = 0000 01000 = 43 x z3 f/ u& t2 a
- ucKey_Old = 0
复制代码
- k6 D0 C- {7 k0 P' f/ }: o/ {, l5 a% g+ t4 v4 b# t
. I" ` b$ _6 J
# |7 u+ t9 h) ~5 e. m1 }- X |