完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1)实验平台:正点原子STM32mini开发板
2)摘自《正点原子STM32 不完全手册(HAL 库版)》关注官方微信号公众号,获取更多资料:正点原子 第七章 按键输入实验 上一章,我们介绍了 STM32 的 IO 口作为输出的使用,这一章,我们将向大家介绍如何使 用 STM32 的 IO 口作为输入用。在本章中,我们将利用板载的 3 个按键,来控制板载的两个 LED 的亮灭。通过本章的学习,你将了解到 STM32 的 IO 口作为输入口的使用方法。本章分为如下 几个小节: 7.1 STM32 IO 口简介 7.2 硬件设计 7.3 软件设计 7.4 下载验证 7.1 STM32 IO 口简介 STM32 的 IO 口在上一章已经有了详细的介绍,这里我们不再多说。STM32 的 IO 口做输 入使用的时候,是通过读取 IDR 的内容来读取 IO 口的状态的。了解了这点,就可以开始我们 的代码编写了。 这一节,我们将通过 MiniSTM32 开发板上载有的 3 个按钮(KEY0/KEY1/WK_UP),来控 制板上的 2 个 LED,其中 KEY0 控制 DS0,按一次亮,再按一次,就灭。KEY1 控制 DS1,效 果同 KEY0。WK_UP 按键则同时控制 DS0 和 DS1,按一次,他们的状态就翻转一次。 。 7.2 硬件设计 本实验用到的硬件资源有: 1) 指示灯 DS0、DS1 2) 3 个按键:KEY0、KEY1 和 KEY_UP。 DS0、DS1 和 STM32 的连接在上一章已经介绍了,在 MiniSTM32 开发板上的按键 KEY0 连接在 PC5 上、KEY1 连接在 PA15 上、WK_UP 连接在 PA0 上。如图 7.2.1 所示: 图 7.2.1 按键与 STM32 连接原理图 这里需要注意的是:KEY0 和 KEY1 是低电平有效的,而 WK_UP 是高电平有效的,除了 KEY1 有上拉电阻(与 JTDI 共用),其他两个都没有上下拉电阻,所以,需要在 STM32 内部设 置上下拉。 7.3 软件设计 这里的代码设计,我们还是在之前的基础上继续编写,打开上一章的 TEST 工程,然后在 HARDWARE 文件夹下新建一个 KEY 文件夹,用来存放与按键相关的代码。如图 7.3.1 所示: 图 7.3.1 在 HARDWARE 下新增 KEY 文件夹 然后我们打开 USER 文件夹下的 test.uvprojx 工程,按 按钮新建一个文件,然后保存在 HARDWARE→KEY 文件夹下面,保存为 key.c。在该文件中输入如下代码: #include "key.h" #include "delay.h" //按键初始化函数 void KEY_Init(void) { GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_GPIOA_CLK_ENABLE(); //开启 GPIOA 时钟 __HAL_RCC_GPIOC_CLK_ENABLE(); //开启 GPIOC 时钟 GPIO_Initure.Pin=GPIO_PIN_0; //PA0 GPIO_Initure.Mode=GPIO_MODE_INPUT; //输入 GPIO_Initure.Pull=GPIO_PULLDOWN; //下拉 GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH; //高速 HAL_GPIO_Init(GPIOA,&GPIO_Initure); GPIO_Initure.Pin=GPIO_PIN_15; //PA15 GPIO_Initure.Pull=GPIO_PULLUP; //上拉 HAL_GPIO_Init(GPIOA,&GPIO_Initure); GPIO_Initure.Pin=GPIO_PIN_5; //PC5 GPIO_Initure.Pull=GPIO_PULLUP; //上拉 HAL_GPIO_Init(GPIOC,&GPIO_Initure); } //按键处理函数 //返回按键值 //mode:0,不支持连续按;1,支持连续按; //0,没有任何按键按下 //1,WKUP 按下 WK_UP //注意此函数有响应优先级,KEY0>KEY1>KEY2>WK_UP!! u8 KEY_Scan(u8 mode) { static u8 key_up=1; //按键松开标志 if(mode==1)key_up=1; //支持连按 if(key_up&&(KEY0==0||KEY1==0||WK_UP==1)) { delay_ms(10); key_up=0; if(KEY0==0) return KEY0_PRES; else if(KEY1==0) return KEY1_PRES; else if(WK_UP==1) return WKUP_PRES; }else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1; return 0; //无按键按下 } 这段代码包含 2 个函数,void KEY_Init(void)和 u8 KEY_Scan(u8 mode),KEY_Init 是用来 初始化按键输入的 IO 口的。实现 PA0、PA15 和 PC5 的输入设置,注意这调用了:JTAG_Set 这个函数,用于禁止 JTAG,开启 SWD,因为 PA15 占用了 JTAG 的一个 IO,所以要禁止 JTAG, 从而让 PA15 用作普通 IO 输入。 KEY_Scan 函数,则是用来扫描这 3 个 IO 口是否有按键按下。KEY_Scan 函数,支持两种 扫描方式,通过 mode 参数来设置。 当 mode 为 0 的时候,KEY_Scan 函数将不支持连续按,扫描某个按键,该按键按下之后必 须要松开,才能第二次触发,否则不会再响应这个按键,这样的好处就是可以防止按一次多次 触发,而坏处就是在需要长按的时候就不合适了。 当 mode 为 1 的时候,KEY_Scan 函数将支持连续按,如果某个按键一直按下,则会一直返 回这个按键的键值,这样可以方便的实现长按检测。 有了 mode 这个参数,大家就可以根据自己的需要,选择不同的方式。这里要提醒大家, 因为该函数里面有 static 变量,所以该函数不是一个可重入函数,在有 OS 的情况下,这个大家 要留意下。同时还有一点要注意的就是,该函数的按键扫描是有优先级的,最优先的是 KEY0, 第二优先的是 KEY1,最后是 WK_UP 按键。该函数有返回值,如果有按键按下,则返回非 0 值,如果没有或者按键不正确,则返回 0。 保存 key.c 代码,然后我们按同样的方法,新建一个 key.h 文件,也保存在 KEY 文件夹下 面。在 key.h 中输入如下代码: #ifndef __KEY_H #define __KEY_H #include "sys.h" #define KEY0 HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_5) //KEY0 按键 PC5 #define KEY1 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_15) //KEY1 按键 PA15 #define WK_UP HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) //WKUP 按键 PA0 #define KEY0_PRES 1 #define KEY1_PRES 2 #define WKUP_PRES 3 void KEY_Init(void); u8 KEY_Scan(u8 mode); #endif 这段代码里面最关键就是 3 个宏定义: #define KEY0 HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_5) //KEY0 按键 PC5 #define KEY1 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_15) //KEY1 按键 PA15 #define WK_UP HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) //WKUP 按键 PA0 这里使用的是位带操作来实现读取某个 IO 口的 1 个位的。同输出一样,上面的功能也同 样可以通过位带操作来简单的实现: #define KEY0 PCin(5) //KEY0 按键 PC5 #define KEY1 PAin(15) //KEY1 按键 PA15 #define WK_UP PAin(0) //WKUP 按键 PA0 用库函数实现的好处是在各个 STM32 芯片上面的移植性非常好,不需要修改任何代码。 用位带操作的好处是简洁,至于使用哪种方法,看各位的爱好了。 在 key.h 中,我们还定义了 KEY0_PRES / KEY1_PRES / KEYUP_PRES 等 3 个宏定义,分 别对应开发板的 KEY0、KEY1 和 WK_UP 按键按下时 KEY_Scan 的返回值。通过这些宏定义, 可以方便大家记忆和使用。 将 key.h 也保存一下。接着,我们把 key.c 加入到 HARDWARE 这个组里面,这一次我们通 过双击的方式来增加新的.c 文件,双击 HARDWARE,找到 key.c,加入到 HARDWARE 里面, 如图 7.3.2 所示: 图 7. 3.2 将 key.c 加入 HARDWARE 组下 可以看到 HARDWARE 文件夹里面多了一个 key.c 的文件, 然后还是用老办法把 key.h 头 文件所在的路径加入到工程里面。回到主界面,在 test.c 里面编写如下代码: #include "sys.h" #include "usart.h" #include "delay.h" #include "led.h" #include "key.h" int main(void) { u8 key=0; HAL_Init(); //初始化 HAL 库 Stm32_Clock_Init(RCC_PLL_MUL9); //设置时钟,72M delay_init(72); //初始化延时函数 LED_Init(); //初始化 LED KEY_Init(); //初始化按键 LED0=0; //点亮 LED while(1) { key=KEY_Scan(0); //得到键值 switch(key) { case KEY0_PRES: LED0=!LED0; break; case KEY1_PRES: LED1=!LED1; break; case WKUP_PRES: LED0=!LED0; LED1=!LED1; break; default: delay_ms(10); } } } 注意要将 KEY 文件夹加入头文件包含路径,不能少,否则编译的时候会报错。这段代码 就实现前面 7.1 节所阐述的功能,相对比较简单。 然后按 ,编译工程,得到结果如图 7.3.3 所示 图 7.3.3 编译结果 可以看到没有错误,也没有警告。接下来,大家就可以下载验证了。 7.4 下载验证 同样,我们还是通过 flymcu 下载代码,在下载完之后,我们可以按 KEY0、KEY1 和 KEY_UP 来看看 DS0 和 DS1 以及蜂鸣器的变化,是否和我们预期的结果一致? 特别注意:因为 PA0 用作按键输入,而且是高电平有效的,所以不要把 PA0 和 1820 的跳 线帽短接在一起了,否则会按键“失灵”。 至此,我们的本章的学习就结束了。本章,作为 STM32F1 的入门第三个例子,介绍了 STM32F1 的 IO 作为输入的使用方法,同时巩固了前面的学习。希望大家在开发板上实际验证 一下,从而加深印象。 |
|
相关推荐
|
|
1950 浏览 1 评论
AD7686芯片不传输数据给STM32,但是手按住就会有数据。
1809 浏览 3 评论
4389 浏览 0 评论
如何解决MPU-9250与STM32通讯时,出现HAL_ERROR = 0x01U
1960 浏览 1 评论
hal库中i2c卡死在HAL_I2C_Master_Transmit
2463 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-18 12:35 , Processed in 0.544315 second(s), Total 64, Slave 47 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号