一、按键原理
& Z$ |) H) E* o) R) \4 Q按键电路原理图(CT117E-M4产品手册)* v5 K7 Z4 \' z" A0 J
8 r3 ?9 r* `# P# _6 B
4 U: r& \9 Q4 ^+ o7 q6 I' K1 X
这四个按键一端都接了VDD,所以默认高电平,当我们按下按键时,电路闭合,IO口电平从高电平到低电平,检测IO口电平的变化就是判断按键是否按下的依据。
) z" U; A9 W4 }+ A/ ]) c! S5 o0 E- R
& b' y# G5 U2 ^8 }% D由于按键默认上电为高电平,所以可以选择浮空输入模式,该模式只是默认输入值不能确定,但是这里是接的VDD,也就是默认输入值高电平。而上下拉输入模式,默认输入值是确定的。读取输入结果时,只有0或1两种,只是默认值不能确定7 I' `7 c7 L! m' ~; K
5 j9 B* O# P3 M/ I% w在单纯作为输入的时,浮空模式是有用的,在外部有上拉/下拉的条件下,可以设置为浮空输入。或者IO有冲突的时候,也可以设置为浮空输入,从而完全不干扰其他IO
. |5 O8 s" J9 s, W0 z9 X9 i/ ]$ M* v9 g, f
对比一下正点原子F4按键实验模式选择:KEY0,1,2选择的是输入上拉,KEY_UP选择的输入下拉, V: a( T: @! J/ `2 z
7 b% ?( s! D/ M0 B& ^5 i& I% w$ e
" C5 S1 ]+ s% A# x5 R1 F
& F! X$ Z$ v4 u4 b0 V
KEY0、 KEY1 和 KEY2 是低电平有效的,而 KEY_UP 是高电平有效
0 s x* v1 W4 l) i; M的, 并且外部都没有上下拉电阻,所以,需要在 STM32F4 内部设置上下拉,STM32G4是可以看到外部接了上拉电阻的,所以程序里面没有设置上下拉模式
! o& y) k' L; `
3 V3 E* N& e' e; ] `9 t g; y输入上拉:无论输入管脚悬空或者被高电平驱动时,读取的都是1. 只有在输入端为0的时,读取到的值才是0。 k0 z; k0 z6 y1 B
2 x: d' X( C3 O: e% F. G
要判断KEY0,1,2的IO口电平,只有按键按下了,输入端为0 ,才能检测读取到低电平,所以这三个引脚选择输入上拉模式
. e5 J! x4 M; F- a! g. v( Y. D0 x
输入下拉:无论输入管脚悬空或者被低电平驱动时,读取的都是0. 只有在输入端为1的时,读取到的值才是1。" V- B5 p; r, O
Q. ]* h- n x: @2 ~/ s6 \- R要判断KEY_UP的IO口电平,只有按键按下了,输入端为1,才能检测读取到高电平,所以这这个引脚选择输入下拉模式
! w" o6 {% x& u, x, R2 s I6 x# p* D- f
GPIO模式详细介绍:GPIO模式
: S* `6 h6 i" H- o5 f% Q
) V5 G( W2 S3 u7 P2 w二、程序编写
+ d/ \2 Q2 `$ m6 W8 Q2 ?+ {3 P8 v按键GPIO设置为浮空输入,使用STM32CubeMX配置
- a) m' l! l M, a9 B" P( B1 m+ q a# |5 ]8 C. G4 _
) g0 g3 {' J, p) D$ m" ?1 H+ { a/ [
将里面按键IO的初始化移植到LED的工程下。- u$ D2 Y+ v' @" M$ i% \+ ~
/ `) y: b( o" o/ k; Y( N7 G
1.按键扫描函数: L8 Z) U" Q0 W ?
- unsigned char Key_Scan(void)
- I3 B9 a6 Q: @" {9 `* X, } - {
9 b2 g) O9 {: `+ e1 I! j - unsigned char unKey_Val = 0;
& Q% k% ~# k5 z; A0 l% G - 9 S7 i& @% X6 l4 S
- if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET): h( r! |' Y( k/ Y. e$ U6 A
- unKey_Val = 1;8 Q$ J4 R# r; b, ~% A: v
J+ B: W' _+ a& i8 J- N5 K/ v4 u- if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET)
% q) `% s( z& n( h - unKey_Val = 2;; A" g& G' |* C% I
- ( V- P0 G6 t( U
- if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET); A1 T5 D0 Y2 h
- unKey_Val = 3;
. K7 ^1 |( k2 i* E& c! E -
/ N& J9 }$ w; }. `4 S0 j+ y - if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
5 `- o/ s" q* c/ g% L2 } - unKey_Val = 4; 8 K0 H& }6 D2 ?5 b# }7 P
-
* i: ^5 U3 U6 j, d7 ` - return unKey_Val;
7 S, P: a u2 t* D* e& x% D/ ? - }
复制代码
. }- j! P- b" S$ m M2.按键处理函数! K% k9 d, `/ |
7 ` \; ~; {3 c2 } c- __IO uint32_t uwTick_Set_Point = 0;
9 ~( `* ~# K0 n R7 L - # q; ~% V$ h0 m5 @
- unsigned char ucKey_Val,ucKey_Down,ucKey_Up,ucKey_Old;; q6 z5 F6 O5 B5 Z# h w1 w% x% S
- void Key_Proc(void). `; ^3 N9 _5 |& F6 F' m; [
- {
7 q' s; q+ K9 U! T2 F2 j _ L/ S - // uwTick每隔1ms加1 刚开始肯定差值大于100ms! d5 n. r; c, J: _" Q- z
- if((uwTick -uwTick_Set_Point) < 100) return; // 每隔100ms扫描一次 , h1 j2 O! H1 J9 T
- uwTick_Set_Point = uwTick; // 记录每次扫描时的uwTick值1 ~3 F/ s5 Q- }, h
-
' u* T: S# R$ `8 O( c* d - ucKey_Val = Key_Scan();$ D9 R6 D9 m$ _" R
- ucKey_Down = ucKey_Val & (ucKey_Old ^ ucKey_Val);# g) X6 o: b1 V2 _5 B* v X
- ucKey_Up = ~ucKey_Val & (ucKey_Old ^ ucKey_Val);
3 @$ x- i$ {; B$ d+ n* G4 \ - ucKey_Old = ucKey_Val;: z! _9 r: n8 i# w* Z1 }
-
& T) d; ?3 E6 H/ y3 F - if(ucKey_Down == 4)
" M! a% `3 k; \9 C - {. L+ m& K( H3 W1 S! K8 i
- LED_Display(0x88);2 X1 c4 Q! i ~
- }3 W$ S8 {3 }1 |7 k& J0 n
- if(ucKey_Down == 1)
& B" R! L. |9 _5 _( r7 B. T' e: f - {* k: j0 s. Y! F3 l
- LED_Display(0x00); h9 r' p) H/ v2 ~3 q% G* t
- }
9 F }4 U8 \3 N' c& G# s0 Y - }
复制代码- &(按位与): 两个操作数都为1 ,才为1 1&0 = 0 0&1 = 0 1&1 = 1
+ f; I+ ^ g: t1 F T - |(按位或):两个操作数只要有一个为1 ,结果为1 1|0 = 1 1|1= 1 0|0 = 0: J3 G# G* u! K
- ^(按位异或):两个操作数相同为0 ,不同才为1 0^0 = 1 1^0 = 0
) i7 f9 W$ W5 E9 d/ q. L2 G - ~(取反):0变为1 ,1变为 0 ~0=1
复制代码
# H5 j8 H' q$ Q# v位运算参考:位运算- V' {! A2 b% I/ P m8 z8 H" L
' N" p/ w. f& W: i
按键扫描可以分为三种情况:4 r: X: \5 g+ ~& ^$ P
" Z) I4 G6 r6 z0 L# t# T
- 情况1 : 100ms扫描了两次,按键返回的结果从0 变为4(按键4被按下了),产生了下降沿/ a" |/ H/ [' }$ f9 P6 E0 E# ^
- ucKey_Val = 4 (0000 0100)- ~3 r$ E$ p8 O: _
- ucKey_Down = 0000 0100 & (0000 0000 ^ 0000 0100) = 0000 0100 & 0000 0100 = 0000 0100 =4
, V3 Y& f" @3 L8 q4 \: G - ucKey_Up = ~0000 0100 & (0000 0000 ^ 0000 0100) = 1111 1011 & 0000 0100 = 0 " g1 k! C" n; X# p
- ucKey_Old = 4
; m* y9 x* `: L7 \7 s1 E
; h0 Y2 I; l% X3 a0 ^- 情况2 : B4产生了下降沿后,按键一直按着
; L$ b# m1 k# |0 U6 D' w x0 G; E" u, i - ucKey_Val = 4
, ?) ^' F' ~1 R, `7 o2 z! Z - ucKey_Down = 0000 0100 & (0000 0100 ^ 0000 0100) = 0000 0100 & 0000 = 0
) E/ W* s' A6 k/ { - ucKey_Up = 1111 1011 & 0000 0000 =0/ [( \8 X% H# ? `2 a9 }
- ucKey_Old = 0000 0100 = 4
" o' @7 x- [9 @4 C8 f* Z! b$ X
, a: P* I9 I0 g+ X- 情况3 : B4按键一直按下后在松手时产生上升沿这个时候( f) a0 g& ?% {; ~6 r" \( x
- ucKey_Val = 0
! A; D9 u4 L4 K, _7 j% h' k - ucKey_Down = 0000 0000 & (0000 0100 ^ 0000 0000) = 0000 0000 & 0000 01000 = 0
' w% Q1 B- i( w# s" l - ucKey_Up = 1111 1111 & 0000 01000 = 0000 01000 = 4
/ ?. I ~( r% b- u, c& T0 G - ucKey_Old = 0
复制代码
- u' t; s6 H2 r5 T3 P/ [. K
# V' [. a& [$ S
! W) p2 W$ R1 `8 P+ l( y% d& b8 V" k7 @+ A% k
|