问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

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. 优化

增加调试技巧

  1. 按键消抖

当前代码没有进行按键消抖,可能会导致误触发。可以使用简单的软件消抖,例如:

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输出,有助于调试:

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号