完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
STM32CUBEMX+MDK5实现按键以及LED灯
1 概述 1.1 资源概述 开发板:正点原子STM32F103 Nano开发板 CUBEMX版本:1.3.0 MDK版本:5.23 主控芯片型号:STM32F103RBT6 1.2 实现功能 使用KEY0~KEY3分别控制LED0到LED3的亮灭,KEY_UP控制LED4的亮灭。按一次按键对应的灯亮,再按一次对应的灯灭。另外长按KEY0可以实现蜂鸣器的鸣响。 2 CUBEMX的配置 2.1 GPIO口配置 2.1.1 端口配置图 (部分引脚配置此次实验未用,但是不影响程序的编译,不会报错) 2.1.2 端口资源汇总表 查阅开发板的电路图确认实验用到的GPIO口配置资源如下。 LED0PC0 LED1PC1 LED2PC2 LED3PC3 KEYUPPA0 KEY0PC8 KEY1PC9 KEY2PD2 BEEPPB8 USART1_TXPA9 USART1_RXPA10 2.1.3 通用GPIO口的配置 KEY_UP是输出高有效,因此初始化时,配置输入下拉。其余LED端口或者按键均是低有效,所以配置为上拉。这里定义User Label(用户标签),方便后续程序的移植。 2.2 时钟配置 2.2.1时钟RCC配置图 使用外部HSE,PLL选择9倍频,系统时钟选择PLL,HCLK配置为72MHz,APB1设置为2分频。 2.2.2晶振选择 选择外部晶振,高速晶振为8MHz,低速晶振为32.768KHz。 2.3 调试端口 采用SW方式进行调试烧录。 2.4 CUBEMX工程管理配置 1、选择Advanced、MDK-ARM、V5。 2、代码生成配置 勾选生成外设C文件和H文件。否则这些端口的配置都会存在于main函数中。 3、高级设置 全部勾选HAL函数。HAL函数的全称是Hardware abstract layer(硬件抽象层),这里还可以选择LL即Low layer(底层),函数和HAL完全不一样,优点是直接操作底层,程序占用空间小。咨询ST原厂FAE工程师,后续新开发芯片均不在支持标准库函数,仅支持HAL和LL函数。比如最新的H7系列芯片,就没有标准库函数的支持。 2.3 选择生成代码 点击Generate code,生成软件代码,在之后的提示框中点击打开工程。 3 main函数增加代码 3.1 端口初始化函数 在生成的main函数中增加相应的功能函数,端口初始化函数,给各个GPIO口赋值初值,防止上电时状态不确定。写入串口打印函数,提示信息。 /* USER CODE BEGIN 2 */ HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_SET); HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_SET); HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_SET); HAL_GPIO_WritePin(LED3_GPIO_Port,LED3_Pin,GPIO_PIN_SET); HAL_GPIO_WritePin(LED4_GPIO_Port,LED4_Pin,GPIO_PIN_SET); HAL_GPIO_WritePin(LED5_GPIO_Port,LED5_Pin,GPIO_PIN_SET); HAL_GPIO_WritePin(LED6_GPIO_Port,LED6_Pin,GPIO_PIN_SET); HAL_GPIO_WritePin(LED7_GPIO_Port,LED7_Pin,GPIO_PIN_SET);//初始化LED灯的状态,全部为灭 HAL_GPIO_WritePin(BEEP_GPIO_Port,BEEP_Pin,GPIO_PIN_SET);//初始化BEEP,不响 uint8_t temp[]=“Press a keyrn ”;//向串口输入提示信息 /* USER CODE END 2 */ 3.2 功能实现函数 在while(1)函数中增加下述函数,实现不间断的按键检测 while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==RESET)//判定KEY0按键是否有按下 { HAL_Delay(10); //延时,用于按键消抖 if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==RESET) //判定KEY0按键是否有按下 { HAL_Delay(500);//判定KEY0按键是否长按 if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==RESET) //KEY0按键被长按 { HAL_GPIO_WritePin(BEEP_GPIO_Port,BEEP_Pin,GPIO_PIN_RESET);//开启蜂鸣器 HAL_Delay(1000);//开启蜂鸣器1000ms HAL_UART_Transmit(&huart1,temp,sizeof(temp),50);//向串口输出提示信息 HAL_GPIO_WritePin(BEEP_GPIO_Port,BEEP_Pin,GPIO_PIN_SET);//关闭蜂鸣器 } else HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);//KEY0按键为短按,LED0灯状态翻转 HAL_UART_Transmit(&huart1,temp,sizeof(temp),50); } } else if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==RESET) { HAL_Delay(10); if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==RESET) { HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin); HAL_Delay(200); HAL_UART_Transmit(&huart1,temp,sizeof(temp),50); } } else if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==RESET) { HAL_Delay(10); if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==RESET) { HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin); HAL_Delay(200); HAL_UART_Transmit(&huart1,temp,sizeof(temp),50); } } else if(HAL_GPIO_ReadPin(KEYUP_GPIO_Port,KEYUP_Pin)==SET) { HAL_Delay(10); if(HAL_GPIO_ReadPin(KEYUP_GPIO_Port,KEYUP_Pin)==SET) { HAL_GPIO_TogglePin(LED3_GPIO_Port,LED3_Pin); HAL_Delay(200); HAL_UART_Transmit(&huart1,temp,sizeof(temp),50); } } } /* USER CODE END 3 */ 4 实验结果 4.1 串口打印 使用串口调试助手,按下一次按键后,串口会打印一个Press a key的字符 4.2 硬件实现 将程序下载到开发板中,验证软件功能。全部功能实现完成。 通过按键将全部的灯点亮 通过按键熄灭LED1和LED2 硬件实现视频 STM32 按键和LED以及蜂鸣器实验(使用CUBEMX和MDK5) 5 按键检测程序之魔鬼数字优化 参考正点原子的官方例程,按键这一段是这么写的 u8 KEY_Scan(u8 mode) { static u8 key_up=1;//按键按松开标志 if(mode)key_up=1; //支持连按 if(key_up&&(KEY0==0||KEY1==0||KEY2==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(KEY2==0)return KEY2_PRES; else if(WK_UP==1)return WKUP_PRES; }else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)key_up=1; return 0;// 无按键按下 } 初次看感觉非常绕,云里雾里,一会0一会1的,传递的全部是数值,非常不利于阅读,于是增加了一些宏定义,消除掉这些魔鬼数字。将key_up的变量名进行了更改。 增加的宏定义 #define KEYOFF 1 #define KEYON 0 #define SINGLE_CLICK 0 #define CONTINUOUS_CLICK 1 #define NOKEY_PRESS 0 依据宏定义改后的程序 u8 KEY_Scan(u8 mode) { static u8 keyState=KEYOFF;//按键状态为OFF if(mode==CONTINUOUS_CLICK) keyState=KEYOFF; //按键初始态为OFF if((keyState==KEYOFF)&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1)) { delay_ms(10);//去抖动 keyState=KEYON; if(KEY0==0) return KEY0_PRES; else if(KEY1==0) return KEY1_PRES; else if(WK_UP==1) return WKUP_PRES; else if(KEY2==0) return KEY2_PRES; }else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0) { keyState=KEYOFF; } return NOKEY_PRESS;// 无按键按下 主函数中引用的地方原来为 key=KEY_Scan(0; //扫描按键 if((Key_Queue!=NULL)&&key) //消息队列Key_Queue创建成功,并且按键被按下 更改后为 key=KEY_Scan(SINGLE_CLICK); //扫描按键 if((Key_Queue!=NULL)&&(key!=NOKEY_PRESS)) //消息队列Key_Queue创建成功,并且按键被按下 这样就可以知道函数在主函数中调用方式为单次按有效,按键函数的逻辑也很清楚了,就是初次进入函数,静态变量keystate为keyoff,第二项条件式不满足,跳转到按键检测中,当有按键被按下时,keystate为keyon,并返回键值。如果按键没有松手,那么第二次进入这个函数时,if((keyStateKEYOFF)&&(KEY00||KEY10||KEY20||WK_UP==1))条件不满足,无法对按键进行检测。直到按键松手,keyState状态为Keyoff后,才可再次进去按键检测状态。同理可以理解连续按时的实现逻辑。 整个按键的功能的实现如下流程图 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1632 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1559 浏览 1 评论
985 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
688 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1605 浏览 2 评论
1869浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
653浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
523浏览 3评论
539浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
508浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-25 13:57 , Processed in 0.894889 second(s), Total 78, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号