
前面几个实验我们学习了了 STM32 的 IO 口作为输出以及系统时钟的使用,这次实验,通过学习按键来学习如何使用 STM32 的 IO 口作为输入用。我们将利用板载的 4 个按键,来控制板子上的 4 个 LED。 通过本次的实验, 了解到 STM32 的 IO 口作为输入口的方法。实验目标:. e" p0 j: r: ]# @& E9 ? 1、了解按键输入的原理。 2、了解 STM32 的输入模式配置。$ q- w; E! g: a 7 C5 i. U: f$ K3 ~$ M2 k( M/ Z 硬件电路设计如图所示1 f" v: t: D" b" q/ e6 X ![]() 上面的原理图,三个按键分别接到单片机的 PE2、PE3、PE4。: w2 z- g+ N* v 1 I* V/ S2 N+ v# |+ @ 按键消抖 按键所用开关为机械弹性开关,当机械触点断开 、闭合时,电压信号 如图示,因此需要做消抖处理。6 [6 s0 q' h' M- y - d, {* ^9 o5 q1 c6 A1 m3 V$ N ![]() 由于机械点的弹性作用,一个按键开关在闭合时不会马上稳定的接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动。抖动时间的长短由按键的机械特性决定的,一般为 5ms 到 10ms。按键抖动会引起按键被误读多次。为了确保 CPU 对键的一次闭合仅作一次处理,必须去除按键抖动。一般来说一个简单的按键消抖就是先读取一次按键的状态,如果得到按键按下之后,延时 10ms,再次读取一次按键的状态,如果按键还是按下状态,那么说明按键已经按下。 d& k$ d# N9 m 库函数输入函数 GPIO_ReadInputDataBit ()函数 这个函数是读取一个设置为输出模式时,一个 IO 口的状态值。当读取的 IO 口为 1 的时候,输出 1,当 IO 口输出为 0 的时候,输出 0。+ P" v7 b. `" _# e; n! K 按键 IO 初始化函数配置 void key_init() { GPIO_InitTypeDef GPIO_InitStructure; //声明一个结构体变量,用来初始化 GPIO RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE); /* 配置 GPIO 的模式和 IO 口 */! T: W- g8 X" D) ^! O. M" m GPIO_InitStructure.GPIO_Pin=K_DOWN|K_LEFT|K_RIGHT;4 O ?& i3 a9 w3 ~7 F! f GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //上拉输入4 k) {4 b$ f' x8 p4 _4 H GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOE,&GPIO_InitStructure);; V& r9 L! b4 ?2 {; _ }8 K& x, ~2 X9 S) N 宏定义输入: #define K_DOWN GPIO_Pin_3 //PE3* ~' n3 ?3 J U& A #define K_LEFT GPIO_Pin_2 //PE2 #define K_RIGHT GPIO_Pin_4 //PE4 #define k_up GPIO_ReadInputDataBit(GPIOA,K_UP) //获取按键的状态 #define k_down GPIO_ReadInputDataBit(GPIOE,K_DOWN): ?7 j7 H4 t, r% l8 I) R #define k_left GPIO_ReadInputDataBit(GPIOE,K_LEFT) #define k_right GPIO_ReadInputDataBit(GPIOE,K_RIGHT) % X' _( }3 @ k( M6 a 按键扫描函数/ C1 H ^9 B1 a& C void keyscan() //按键处理函数 {+ N) w' s$ ~/ y if(k_down==0)+ W* J r( H: v6 P! e3 ~ {! A! p& ~1 c/ g, \ delay_ms(10);" j0 N/ O! ~7 | if(k_down==0) I+ ]. c* W4 |! W; E5 k S2 s {, |% e/ C8 Y. G, ]- }$ l GPIO_Write(GPIOC,(u16)(0xfd)); } while(!k_down);, K% S$ I- g" m2 r) j } if(k_left==0)6 i3 R) O" \% s p" S$ i6 q/ H {/ m% ~! x, h* y% G( i i+ _ delay_ms(10);( E) J1 i1 M) g7 h7 s if(k_left==0) {0 p1 n# v: m( E: F# W8 f GPIO_Write(GPIOC,(u16)(0xfb)); } while(!k_left); }+ K. Y: e- t1 n5 F6 a3 m; e if(k_right==0) {; @6 Z1 W) o: p- N* N# u delay_ms(10);" r, J, m& {# [; e if(k_right==0)8 G0 [9 @8 p" t N- G! M {" [8 x8 d: f* I2 G GPIO_Write(GPIOC,(u16)(0xf7));. B( h R8 Q: j, s- J }$ ` @/ I" E$ _5 v while(!k_right);- k3 M2 A% V$ l1 [4 f } } 这个按键扫描函数只是一个简单的函数,在比较简单的程序里面比较实用,有很明显的缺陷,不支持多按键输入,而且由于使用的是延时消抖,不能充分利用 CPU 资源。大家 如在比较复杂的程序使用按键扫描的话,使用状态机方式的按键扫描,或者零时消抖的按键扫描方式。# z u8 l6 o) l0 ]1 Z 1 K9 J5 {! K9 ]2 n t int main() l" W& m$ [% t/ m8 ?5 S* e4 a0 o { # w1 |5 L, m/ U- k: c0 j+ Y+ ? led_Init(); //LED 初始化" r) `6 v" e, j# t( h key_init(); //按键端口初始化函数0 ~" V( A2 ~/ k! G3 z GPIO_Write(GPIOC,(u16)(0xff)); //LED 灭 while(1) { keyscan(); //按键处理函数 } }) ^& ? E1 r. y; m, e/ x! }! x( H ( Y% S. K7 C8 r- `. d! ]2 E 独立按键就先写到这里吧,后面还会分享其它的按键扫描函数。6 z6 C5 z( ?9 v+ j0 @# p S- \) k0 }4 d8 d( F# y |
另外,LZ的硬件是啥板子