STM32独立按键控制LED流水灯详细解析
创作时间:
作者:
@小白创作中心
STM32独立按键控制LED流水灯详细解析
引用
CSDN
1.
https://blog.csdn.net/caoyang158332/article/details/146243006
在嵌入式开发中,按键控制LED进行不同的显示效果是一个常见的实验。本项目基于STM32单片机,实现四个独立按键控制LED进行不同的灯效变化。
1. 项目背景
在嵌入式开发中,按键控制LED进行不同的显示效果是一个常见的实验。本项目基于STM32单片机,实现四个独立按键控制LED进行不同的灯效变化。
2. 硬件设计
2.1 按键电路原理
从按键电路图来看,每个按键(KEY1-KEY4)都与GPIO端口(PC0-PC3)相连,同时通过220Ω的限流电阻接地。
- 按键按下时,GPIO读取为低电平(0)。
- 按键释放时,GPIO读取为高电平(1)。
2.2 LED控制电路
LED电路由8颗LED(LED1-LED8)组成,每个LED通过510Ω的限流电阻连接到VCC,并受PNP型三极管S8550控制。
- 三极管Q1的基极由LED_SW控制,当LED_SW置低时,三极管导通,LED获得驱动电流。
- 通过LED1至LED8对应的GPIO控制各个LED的亮灭状态。
3. 代码实现
3.1 按键扫描函数
uint8_t key_status(void)
{
if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == 0)
{
key_flag = 1;
}
if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == 0)
{
key_flag = 2;
}
if (HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin) == 0)
{
key_flag = 3;
}
if (HAL_GPIO_ReadPin(KEY4_GPIO_Port, KEY4_Pin) == 0)
{
key_flag = 4;
}
if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == 1 &&
HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == 1 &&
HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin) == 1 &&
HAL_GPIO_ReadPin(KEY4_GPIO_Port, KEY4_Pin) == 1)
{
if (key_flag == 3 || key_flag == 4)
{
key_flag = 0;
}
}
return key_flag;
}
3.2 LED控制函数
单个LED控制
void led_on(uint8_t led) {
HAL_GPIO_WritePin(LED_SW_GPIO_Port, LED_SW_Pin, GPIO_PIN_RESET);
switch (led) {
case 1: HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET); break;
case 2: HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET); break;
case 3: HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET); break;
case 4: HAL_GPIO_WritePin(LED4_GPIO_Port, LED4_Pin, GPIO_PIN_RESET); break;
case 5: HAL_GPIO_WritePin(LED5_GPIO_Port, LED5_Pin, GPIO_PIN_RESET); break;
case 6: HAL_GPIO_WritePin(LED6_GPIO_Port, LED6_Pin, GPIO_PIN_RESET); break;
case 7: HAL_GPIO_WritePin(LED7_GPIO_Port, LED7_Pin, GPIO_PIN_RESET); break;
case 8: HAL_GPIO_WritePin(LED8_GPIO_Port, LED8_Pin, GPIO_PIN_RESET); break;
}
}
全部LED控制
void led_all_on(){
HAL_GPIO_WritePin(LED_SW_GPIO_Port,LED_SW_Pin,GPIO_PIN_RESET);
for (int i = 1; i <= 8; i++) {
led_on(i);
}
}
void led_all_off(){
HAL_GPIO_WritePin(LED_SW_GPIO_Port,LED_SW_Pin,GPIO_PIN_RESET);
for (int i = 1; i <= 8; i++) {
led_off(i);
}
}
3.3 流水灯功能
左移流水灯
void led_left(void){
uint8_t j;
HAL_GPIO_WritePin(LED_SW_GPIO_Port, LED_SW_Pin, GPIO_PIN_RESET);
for(uint8_t i = 1; i <= 8; i++){
led_on(i);
HAL_Delay(DELAY_MS);
led_off(i-1);
for (j = 0; j < DELAY_MS / 10; j++) {
HAL_Delay(10);
key_status();
if (key_flag != 1) return;
}
}
}
右移流水灯
void led_right(void){
uint8_t j;
HAL_GPIO_WritePin(LED_SW_GPIO_Port, LED_SW_Pin, GPIO_PIN_RESET);
for(uint8_t i = 8; i > 0; i--){
led_on(i);
HAL_Delay(DELAY_MS);
led_off(i+1);
for (j = 0; j < DELAY_MS / 10; j++) {
HAL_Delay(10);
key_status();
if (key_flag != 2) return;
}
}
}
3.4 红绿灯控制
void led_red(){
HAL_GPIO_WritePin(LED_SW_GPIO_Port,LED_SW_Pin,GPIO_PIN_RESET);
led_on(1); led_on(3); led_on(5); led_on(7);
}
void led_green(){
HAL_GPIO_WritePin(LED_SW_GPIO_Port,LED_SW_Pin,GPIO_PIN_RESET);
led_on(2); led_on(4); led_on(6); led_on(8);
}
4. 主循环
while(1){
key_status();
switch(key_flag){
case 0: led_all_off(); break;
case 1: led_left(); break;
case 2: led_right(); break;
case 3: led_red(); break;
case 4: led_green(); break;
}
}
目前led_left()
和led_right()
使用for
循环逐个点亮LED,并在HAL_Delay
过程中不断轮询按键状态。可以优化为:仅当key_flag
仍为1或2时继续循环
避免多次调用HAL_GPIO_WritePin(LED_SW_GPIO_Port, LED_SW_Pin, GPIO_PIN_RESET);
void led_left(void) {
uint8_t i = 1;
while (key_flag == 1) {
led_on(i);
HAL_Delay(DELAY_MS);
led_off(i);
i = (i % 8) + 1; // 让LED依次点亮
}
}
使用数组优化LED控制
目前led_on()
和led_off()
代码冗余,可用数组优化:
GPIO_TypeDef* LED_PORTS[] = {LED1_GPIO_Port, LED2_GPIO_Port, LED3_GPIO_Port, LED4_GPIO_Port,
LED5_GPIO_Port, LED6_GPIO_Port, LED7_GPIO_Port, LED8_GPIO_Port};
uint16_t LED_PINS[] = {LED1_Pin, LED2_Pin, LED3_Pin, LED4_Pin,
LED5_Pin, LED6_Pin, LED7_Pin, LED8_Pin};
void led_on(uint8_t led) {
if (led >= 1 && led <= 8) {
HAL_GPIO_WritePin(LED_PORTS[led - 1], LED_PINS[led - 1], GPIO_PIN_RESET);
}
}
5. 结论
本项目实现了按键控制LED的不同显示模式,涵盖流水灯、红绿灯控制等。整个程序逻辑清晰,能够用于STM32的按键与LED控制实验。希望对大家有所帮助!
6. 优化
增加调试技巧
- 按键消抖
当前代码没有进行按键消抖,可能会导致误触发。可以使用简单的软件消抖,例如:
uint8_t read_key(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) {
if (HAL_GPIO_ReadPin(GPIOx, GPIO_Pin) == GPIO_PIN_RESET) {
HAL_Delay(10); // 简单消抖
if (HAL_GPIO_ReadPin(GPIOx, GPIO_Pin) == GPIO_PIN_RESET) {
return 1;
}
}
return 0;
}
然后在key_status()
中使用read_key(KEY1_GPIO_Port, KEY1_Pin)
代替HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin)
。
添加串口调试信息
在关键位置加入printf
输出,有助于调试:
热门推荐
基于R语言遥感随机森林建模与空间预测
垫江:提质扩量发展优势产业 打造全市重要工业基地
如何进行全面的投资风险评估
模型量化概述:从基础概念到实现方法
熊园:近期债券利率明显调整,怎么看、怎么办?
中医心理学中的“心神说”与“脑神说”
以白定天下的定瓷,选料严格为什么还是走向衰落
单招与高考的优劣势,你了解多少?从报名到录取的全过程指南
读懂《传习录》,领悟阳明心学智慧
五条悟:《咒术回战》最强特级咒术师
哪些情形劳动者可以提前通知用人单位解除劳动合同
事故报告责任主体解析:明确各方责任,确保安全无忧
年度绩效考核的结果如何应用到薪酬调整中?
阿莫西林克拉维酸钾分散片怎么使用是正确的
从零开始C++棋牌游戏开发之第一篇:C++ 游戏开发环境搭建与工具简介
胸椎疼痛应该怎么解决
两种方式签名APK
了解个人和企业财务的基础知识
怎么判断是不是干槽症
空间重塑:如何用小细节让家居焕发新生
水土流失防治措施-水土流失的防止和综合治理措施
减脂全攻略:减脂肪饮食+运动,一个月减脂3%轻松瘦
如何策划完美的生日会
布里斯托大学2025硕士申请大更新!11个超火专业+五档分级
做近视手术前需要做哪些准备?
武庙72将中三国武将都有哪些人?司马懿为何没有进入?
如何撰写一个优秀的PPT:关键要点解析
元素周期表怎么背
宠物皮癣会传染人吗?
劳动合同维权指南:丢失、终止与签订过程中的权益保护