基于事件驱动的LED控制框架详解

在嵌入式系统开发中,LED控制是一个常见的需求,不同项目对LED的效果和功能要求各不相同。传统的LED控制方式需要针对不同的需求编写不同的代码,增加了开发的工作量和复杂度。为了解决这一问题,我开发了一种扩展性较强的LED框架,该框架脱离底层细节,只关注应用层,提供一种通用的LED控制方案,使得开发人员可以轻松实现各种LED效果,极大地提高了开发效率和灵活性。

背景介绍

在嵌入式系统中,LED作为一种简单直观的状态指示器,被广泛应用于各种设备中,例如单片机开发板、智能家居设备、工业控制系统等。在实际应用中,LED的效果和功能需求千差万别,有时需要实现常亮、闪烁、呼吸等效果,有时需要实现流水灯、跑马灯等动态效果。然而,传统的LED控制方式往往需要针对不同的需求编写不同的代码,导致代码冗余、维护困难,严重影响了开发效率和代码质量。

问题分析

在实际开发中,每次修改LED的功能或效果时,都需要重新编写代码,这样会导致代码重复、维护困难等问题。而且,随着项目的不断迭代和功能的不断增加,LED控制的需求也会不断变化,传统的硬编码方式很难满足快速、灵活地进行修改和定制的需求。

框架设计思路

基于以上问题,我设计了一种基于事件驱动的LED控制框架,该框架将LED控制从底层解耦,只关注应用层,提供了一种通用的LED控制方案,使得开发人员可以轻松实现各种LED效果,极大地提高了开发效率和灵活性。该框架主要包括以下几个关键点:

  • LED事件表管理:通过定义LED事件表,将不同的LED控制功能映射到相应的事件上,实现LED控制的灵活配置和管理。
  • LED状态控制:提供统一的LED状态控制接口,使得开发人员可以方便地调用各种LED效果,并且可以根据实际需求进行定制和扩展。

核心代码解析

下面是LED框架的核心代码,包括LED事件表初始化、事件表管理、LED状态控制等功能的实现原理和关键代码片段:

// LED事件表初始化
void LED_EventTableInit(LED_EventTableItem_t ledEvent[]) 
{
    if (ledEvent == NULL)
    {
        ledPrintf(LOG_ERROR, "ledEvent is NULL\r\n");
        return;
    }
    memset(ledPriorityTable, 0, sizeof(ledPriorityTable));
    memset(ledEventTable, 0, sizeof(ledEventTable));
    memcpy(ledEventTable, ledEvent, sizeof(ledEventTable));
}

// 将LED事件加入事件表
void LED_EventAdd(LED_Event_t ledEvent) {
    for (size_t i = 0; i < EVENT_MAX; i++) {
        if (ledEventTable[i].event == ledEvent) {
            if (ledPriorityTable[ledEventTable[i].priority].event != ledEvent) {
                // 如果当前优先级中存在不同的LED事件,则执行以下操作
                ledEventTable[i].config.currentTime = TIME_Get(); // 记录开始执行时的时间戳
                if (ledPriorityTable[ledEventTable[i].priority].event != 0) {
                    if (LED_SetState == NULL) {
                        ledPrintf(LOG_ERROR, "LED_SetState is NULL!!!\r\n");
                        return;
                    }
                    // 关闭其他LED事件与本LED事件不同的LED灯
                    LED_SetState((ledPriorityTable[ledEventTable[i].priority].config.ledMask)^(ledEventTable[i].config.ledMask), LED_OFF);
                }
            }
            // 更新LED事件表中对应优先级的LED事件
            ledPriorityTable[ledEventTable[i].priority] = ledEventTable[i];
            return;
        }
    }
}

// 将LED事件从事件表删除
void LED_EventDelete(LED_Event_t ledEvent) {
    for (size_t i = 0; i < PRIORITY_MAX; i++) {
        if (ledPriorityTable[i].event == ledEvent) {
            // 找到与传入的LED事件相同的事件,将其清零并关闭LED
            memset(&ledPriorityTable[i], 0, sizeof(LED_EventTableItem_t));
            if (LED_SetState == NULL) {
                ledPrintf(LOG_ERROR, "LED_SetState is NULL!!!\r\n");
                return;
            }
            LED_SetState(ledEventTable[ledEvent].config.ledMask, LED_OFF);
            return;
        }
    }
}

// LED事件处理函数
void LED_EventHandle(void) {
    uint8_t ret;
    int i;
    for (i = (PRIORITY_MAX - 1); i >= 0; i--) {
        // 从高优先级开始往下查询
        if (ledPriorityTable[i].event != 0) {
            // 如果当前优先级中存在LED事件,则执行对应的LED事件处理函数
            ledPrintf(LOG_DEBUG, "led_priority_table[%d].event %d\r\n", i, ledPriorityTable[i].event);
            ret = ledPriorityTable[i].ledEventHandler(&ledPriorityTable[i].config);
            // 如果正在执行事件功能返回1,执行完事件功能返回0
            // 例:每30秒闪烁1次,闪烁的1s里返回1,闪烁完成返回0
            if (ret) {
                return;
            }
        }
    }
}

uint8_t LED_Lighting_Update(LED_Config_t *led);
uint8_t LED_AlternatingBlinking_Update(LED_Config_t *led);
uint8_t LED_Blinking_Update(LED_Config_t *led);
uint8_t LED_Breathing_Update(LED_Config_t *led);
uint8_t LED_Running_Update(LED_Config_t *led);
uint8_t LED_MARQUEE_Update(LED_Config_t *led);

// LED更新函数
uint8_t LED_Update(LED_Config_t *led) {
    uint8_t ret;
    switch (led->state) {
        case LED_LIGHT:
            ret = LED_Lighting_Update(led);
            break;
#if (BLINK_ENABLE)
        case LED_ALTERNATING_BLINK:
            ret = LED_AlternatingBlinking_Update(led);
            break;
#endif
#if (ALTERNATING_BLINK_ENABLE)
        case LED_BLINKING:
            ret = LED_Blinking_Update(led);
            break;
#endif
#if (BREATH_ENABLE)
        case LED_BREATHING:
            ret = LED_Breathing_Update(led);
            break;
#endif
#if (RUNNING_ENABLE)
        case LED_RUNNING:
            ret = LED_Running_Update(led);
            break;
#endif
#if (MARQUEE_ENABLE)
        case LED_MARQUEE:
            ret = LED_MARQUEE_Update(led);
            break;
#endif
        default:
            break;
    }
    return ret;
}

程序解析

以下是对LED框架核心代码的详细解析:

LED事件表初始化(LED_EventTableInit)
  • LED_EventTableInit 函数用于初始化LED事件表。
  • 首先检查传入的 ledEvent 是否为空指针,如果为空,则打印错误日志并返回。
  • 然后,将 ledPriorityTableledEventTable 数组清零。
  • 最后,通过 memcpy 将传入的 ledEvent 复制到 ledEventTable 数组中。
将LED事件加入事件表(LED_EventAdd)
  • LED_EventAdd 函数用于将LED事件添加到事件表中。
  • 通过循环遍历 ledEventTable 数组,查找是否存在与传入的 ledEvent 相同的事件。
  • 如果找到相同的事件,则检查当前优先级中是否已经存在相同的LED事件,如果不存在,则执行以下操作:
    • 记录当前时间戳。
    • 如果当前优先级中存在其他LED事件,则关闭该LED事件与本LED事件不同的LED灯。
  • 更新LED事件表中对应优先级的LED事件为传入的LED事件。
将LED事件从事件表删除(LED_EventDelete)
  • LED_EventDelete 函数用于从事件表中删除LED事件。
  • 通过循环遍历 ledPriorityTable 数组,查找是否存在与传入的 ledEvent 相同的事件。
  • 如果找到相同的事件,则将该事件对应的项清零,并关闭LED。
LED事件处理函数(LED_EventHandle)
  • LED_EventHandle 函数用于处理LED事件。
  • 通过循环遍历 ledPriorityTable 数组,从高优先级开始往下查询是否存在LED事件。
  • 如果当前优先级中存在LED事件,则执行对应的LED事件处理函数,并根据返回值判断是否继续执行下一个事件。
LED更新函数(LED_Update)
  • LED_Update 函数根据传入的LED状态选择对应的更新函数,并返回更新结果。

以上是LED框架核心代码的解析,通过对每个函数的功能和实现原理进行分析,可以更好地理解LED框架的设计和使用方式。

LED框架的功能模块

该LED框架主要包括以下几个功能模块:

  • 常亮状态控制(LED_LIGHT): 使LED保持常亮状态,适用于需要持续指示某种状态的场景。
  • 闪烁状态控制(LED_BLINKING): 控制LED周期性地闪烁,可用于提醒、警告等场景。
  • 交替闪烁状态控制(LED_ALTERNATING_BLINK): 控制LED两组灯交替闪烁,更加生动有趣。
  • 呼吸状态控制(LED_BREATHING): 控制LED呼吸效果,实现渐变的亮度变化。
  • 流水灯状态控制(LED_RUNNING): 控制LED像流水一样流动,增加动态感。
  • 跑马灯状态控制(LED_MARQUEE): 控制LED像跑马灯一样循环移动,适用于展示性的场景。

用户可根据宏打开或关闭某个模块,节省空间开支。

使用示例

下面是LED框架的使用示例,演示了如何初始化LED事件表、添加LED事件、处理LED事件以及更新LED状态的过程:

// 输出LED状态
void set_led(GPIO_TypeDef *gpio_port, uint32_t pin, uint8_t state)
{
    if (state)
    {
        LL_GPIO_SetOutputPin(gpio_port, pin);
    }
    else
    {
        LL_GPIO_ResetOutputPin(gpio_port, pin);
    }
}
// 对LED进行状态设置
void set_led_state(uint16_t led_site, uint8_t state)
{
    switch (led_site)
    {
    case USER_LED1:
        set_led(USER_LED1_GPIO_PORT, USER_LED1_PIN, state);
        break;
    case USER_LED2:
        set_led(USER_LED2_GPIO_PORT, USER_LED2_PIN, state);
        break;
    case USER_LED3:
        set_led(USER_LED3_GPIO_PORT, USER_LED3_PIN, state);
        break;
    case USER_LED4:
        set_led(USER_LED4_GPIO_PORT, USER_LED4_PIN, state);
        break;
    case USER_LED5:
        set_led(USER_LED5_GPIO_PORT, USER_LED5_PIN, state);
        break;
    default:
        break;
    }
}
// LED状态设置回调函数
void set_led_multi(uint16_t led, uint8_t state)
{
    for (size_t led_site = USER_LED1; led_site < USER_LED_MAX; led_site++)
    {
        if (led & LED_CHANNEL(led_site))
        {
            set_led_state(led_site, state);
        }
    }
}

// 不充电事件LED事件
uint8_t not_charging_led_handle(LED_Config_t *led_config)
{
    uint16_t batteryLevel;
    static uint32_t flow_interval = 0;

    uint16_t led_channels[] = {USER_LED2, USER_LED3, USER_LED4, USER_LED5};
    uint16_t charge_levels[] = {charg_level_gear1,charg_level_gear2,charg_level_gear3,charg_level_gear4};
    size_t num_levels = sizeof(charge_levels) / sizeof(charge_levels[0]);

    led_config->ledMask = 0;
    // 获取电池电量百分比
    batteryLevel = BAT_DischargeVol();

    // 迭代充电等级,根据电量设置LED通道
    for (size_t i = 0; i < num_levels; ++i)
    {
        if (batteryLevel >= charge_levels[i])
        {
            // 添加对应的LED通道
            led_config->ledMask |= LED_CHANNEL(led_channels[i]);
        }
        else
        {
            // 熄灭电量不足的LED灯
            set_led_multi(LED_CHANNEL(led_channels[i]), LED_OFF);
        }
    }
    if (LED_Update(led_config))
    {
        return 1;
    }
    // 返回0会继续执行下个优先级任务,返回1则不运行其他低优先级任务
    return 0;
}

// 充电事件LED事件
uint8_t charging_led_handle(LED_Config_t *led_config)
{
    if (LED_Update(led_config))
    {
        return 1;
    }
    // 返回0会继续执行下个优先级任务,返回1则不运行其他低优先级任务
    return 0;
}

// 缺电LED事件
uint8_t bat_low_led_handle(LED_Config_t *led_config)
{
    if (!LED_Update(led_config))
    {
        LED_EventDelete(EVENT_LOW_BATTERY);     // 删除缺电事件
        state_machine.board_state = BOARD_STOP; // 进入休眠状态
    }
    // 返回0会继续执行下个优先级任务,返回1则不运行其他低优先级任务
    return 0;
}

// led初始化
void user_led_init(void)
{
    // 初始化时钟
    USER_LED1_GPIO_CLK_ENABLE();
    USER_LED2_GPIO_CLK_ENABLE();
    USER_LED3_GPIO_CLK_ENABLE();
    USER_LED4_GPIO_CLK_ENABLE();
    USER_LED5_GPIO_CLK_ENABLE();
	// 初始化GPIO
    LL_GPIO_SetPinMode(USER_LED1_GPIO_PORT, USER_LED1_PIN, LL_GPIO_MODE_OUTPUT);
    LL_GPIO_SetPinMode(USER_LED2_GPIO_PORT, USER_LED2_PIN, LL_GPIO_MODE_OUTPUT);
    LL_GPIO_SetPinMode(USER_LED3_GPIO_PORT, USER_LED3_PIN, LL_GPIO_MODE_OUTPUT);
    LL_GPIO_SetPinMode(USER_LED4_GPIO_PORT, USER_LED4_PIN, LL_GPIO_MODE_OUTPUT);
    LL_GPIO_SetPinMode(USER_LED5_GPIO_PORT, USER_LED5_PIN, LL_GPIO_MODE_OUTPUT);

    LED_SetStateInit(set_led_multi); // 设置LED灯状态的回调函数
    SET_TimeGetInit(LL_GetTick);     // 获取时间戳的回调函数

    // LED事件初始化
    LED_EventTableItem_t led_event_category[EVENT_MAX] = {
        [EVENT_NOT_CHARGING] = {
            // 不充电时LED显示电量。
            .event = EVENT_NOT_CHARGING,
            .priority = PRIORITY_4,	// 优先级为4
            // 参与本次事件的LED
            .config.ledMask = LED_CHANNEL(USER_LED2) | LED_CHANNEL(USER_LED3) | LED_CHANNEL(USER_LED4) | LED_CHANNEL(USER_LED5),
            // 常亮1s为一个周期,没有次数,没有循环,即一直常亮下去
            .config.state = LED_LIGHT,
            .config.runNum = 0, // 次数为0次数无限大,一直执行
            .ledEventHandler = not_charging_led_handle,
        },
        [EVENT_CHARGING] = {
            // 充电时LED跑马灯工作。
            .event = EVENT_CHARGING,
            .priority = PRIORITY_4,// 优先级为4
            // 参与本次事件的LED
            .config.ledMask = LED_CHANNEL(USER_LED2) | LED_CHANNEL(USER_LED3) | LED_CHANNEL(USER_LED4) | LED_CHANNEL(USER_LED5),
            // 每个LED亮起的时间为250ms,跑完一轮间隔500ms。
            .config.state = LED_MARQUEE,
            .config.marqueeParams.cycleTime = 250,
            .config.marqueeParams.intervalTime = 500,
            .config.runNum = 0, // 次数为0次数无限大,一直执行
            .ledEventHandler = charging_led_handle,
        },
        [EVENT_LOW_BATTERY] = {
            /// 缺电时(电压低于 8.4V±0.1V)故障LED闪烁3次
            .event = EVENT_LOW_BATTERY,
            .priority = PRIORITY_4,// 优先级为4
            // 参与本次事件的LED
            .config.ledMask = LED_CHANNEL(USER_LED1),
            // 灭500ms,亮500ms,即1s为一个周期,次数3次
            .config.state = LED_BLINKING,
            .config.blinkParams.offTime = 500,
            .config.blinkParams.onTime = 500,
            .config.runNum = 3, // 次数为0次数无限大,一直执行
            .ledEventHandler = bat_low_led_handle,
        },
    };
    LED_EventTableInit(led_event_category);
}

int main(void)
{
    user_led_init();	// 初始化LED事件组
    LED_EventAdd(EVENT_NOT_CHARGING);	// 添加不充电的LED事件
    while(1)
    {
        LED_EventHandle();          // LED事件处理函数
    }
}

程序解析

以下是对新增的LED事件处理函数、LED初始化函数以及主函数的详细解析:

不充电事件LED事件处理函数(not_charging_led_handle)
  • not_charging_led_handle 函数用于处理不充电事件下LED的状态。
  • 首先声明了变量 batteryLevelflow_interval 以及LED通道数组和电量等级数组。
  • 获取电池电量百分比。
  • 迭代充电等级,根据电量设置LED通道。
  • 如果LED更新成功,则返回1,否则返回0。
充电事件LED事件处理函数(charging_led_handle)
  • charging_led_handle 函数用于处理充电事件下LED的状态。
  • 如果LED更新成功,则返回1,否则返回0。
缺电LED事件处理函数(bat_low_led_handle)
  • bat_low_led_handle 函数用于处理缺电LED事件。
  • 如果LED更新成功,则删除缺电事件并进入休眠状态。
LED初始化函数(user_led_init)
  • user_led_init 函数用于初始化LED。
  • 首先初始化LED的时钟和GPIO。
  • 然后设置LED灯状态的回调函数和获取时间戳的回调函数。
  • 最后初始化LED事件,包括不充电事件、充电事件和缺电事件。
主函数(main)
  • 主函数中首先调用user_led_init 函数,初始化LED事件组。
  • 然后调用 LED_EventAdd(EVENT_NOT_CHARGING),添加不充电的LED事件。
  • 最后进入一个无限循环,在循环中不断调用 LED_EventHandle 函数,用于处理LED事件。

整体框架程序

/**
 * @file led.c
 * @author cyWu (1917507415@qq.com)
 * @brief LED应用层框架
 * @version 0.1
 * @date 2024-02-22
 * 
 * @copyright Copyright (c) 2024
 * */

#include "led.h"

static LED_EventTableItem_t ledPriorityTable[PRIORITY_MAX];
static LED_EventTableItem_t ledEventTable[EVENT_MAX];
static LED_SetState_t LED_SetState;
static TIME_Get_t TIME_Get;

// 设置led状态回调函数
void LED_SetStateInit(LED_SetState_t setState)
{
    LED_SetState = setState;
}

// 设置获取时间戳回调函数
void SET_TimeGetInit(TIME_Get_t getTime)
{
    TIME_Get = getTime;
}

// LED事件表初始化
void LED_EventTableInit(LED_EventTableItem_t ledEvent[]) 
{
    if (ledEvent == NULL)
    {
        ledPrintf(LOG_ERROR, "ledEvent is NULL\r\n");
        return;
    }
    memset(ledPriorityTable, 0, sizeof(ledPriorityTable));
    memset(ledEventTable, 0, sizeof(ledEventTable));
    memcpy(ledEventTable, ledEvent, sizeof(ledEventTable));
}

// 将LED事件加入事件表
void LED_EventAdd(LED_Event_t ledEvent) {
    for (size_t i = 0; i < EVENT_MAX; i++) {
        if (ledEventTable[i].event == ledEvent) {
            if (ledPriorityTable[ledEventTable[i].priority].event != ledEvent) {
                ledEventTable[i].config.currentTime = TIME_Get(); // 记录开始执行时的时间戳
                if (ledPriorityTable[ledEventTable[i].priority].event != 0) {
                    if (LED_SetState == NULL) {
                        ledPrintf(LOG_ERROR, "LED_SetState is NULL!!!\r\n");
                        return;
                    }
                    LED_SetState((ledPriorityTable[ledEventTable[i].priority].config.ledMask)^(ledEventTable[i].config.ledMask), LED_OFF);
                }
            }
            ledPriorityTable[ledEventTable[i].priority] = ledEventTable[i]; // 相同优先级的会覆盖
            return;
        }
    }
}

// 将LED事件从事件表删除
void LED_EventDelete(LED_Event_t ledEvent) {
    for (size_t i = 0; i < PRIORITY_MAX; i++) {
        if (ledPriorityTable[i].event == ledEvent) {
            memset(&ledPriorityTable[i], 0, sizeof(LED_EventTableItem_t));
            if (LED_SetState == NULL) {
                ledPrintf(LOG_ERROR, "LED_SetState is NULL!!!\r\n");
                return;
            }
            LED_SetState(ledEventTable[ledEvent].config.ledMask, LED_OFF);
            return;
        }
    }
}

// LED事件处理函数
void LED_EventHandle(void) {
    uint8_t ret;
    int i;
    for (i = (PRIORITY_MAX - 1); i >= 0; i--) { // 从高优先级开始往下查询
        if (ledPriorityTable[i].event != 0) {
            ledPrintf(LOG_DEBUG, "led_priority_table[%d].event %d\r\n", i, ledPriorityTable[i].event);
            ret = ledPriorityTable[i].ledEventHandler(&ledPriorityTable[i].config); // 执行对应LED事件处理函数
            // 正在执行事件功能返回1,执行完事件功能返回0,例:每30秒闪烁1次,闪烁的1s里返回1,闪烁完成返回0,目的是使间隔的30秒内可以运行别的LED事件
            if (ret) {
                return;
            }
        }
    }
}

// 计算时间差
uint32_t GetTickDiff(uint32_t meiosis)
{
    uint32_t temp = TIME_Get();
    if (temp >= meiosis)
    {
        temp = temp - meiosis;
    }
    else
    {
        temp = 0xFFFFFFFFU - meiosis + temp;
    }
    return temp;
}

uint8_t LED_Lighting_Update(LED_Config_t *led);
uint8_t LED_AlternatingBlinking_Update(LED_Config_t *led);
uint8_t LED_Blinking_Update(LED_Config_t *led);
uint8_t LED_Breathing_Update(LED_Config_t *led);
uint8_t LED_Running_Update(LED_Config_t *led);
uint8_t LED_MARQUEE_Update(LED_Config_t *led);

// LED更新函数
uint8_t LED_Update(LED_Config_t *led) {
    uint8_t ret;
    switch (led->state) {
        case LED_LIGHT:
            ret = LED_Lighting_Update(led);
            break;
#if (BLINK_ENABLE)
        case LED_ALTERNATING_BLINK:
            ret = LED_AlternatingBlinking_Update(led);
            break;
#endif
#if (ALTERNATING_BLINK_ENABLE)
        case LED_BLINKING:
            ret = LED_Blinking_Update(led);
            break;
#endif
#if (BREATH_ENABLE)
        case LED_BREATHING:
            ret = LED_Breathing_Update(led);
            break;
#endif
#if (RUNNING_ENABLE)
        case LED_RUNNING:
            ret = LED_Running_Update(led);
            break;
#endif
#if (MARQUEE_ENABLE)
        case LED_MARQUEE:
            ret = LED_MARQUEE_Update(led);
            break;
#endif
        default:
            break;
    }
    return ret;
}

// LED常亮状态更新函数
static uint8_t LED_Lighting_Update(LED_Config_t *led) 
{
    // 以1s为周期计算已经进行了多少次常亮
    uint16_t blinkCount = GetTickDiff(led->currentTime) / 1000;
    // 判断是否大于运行次数
    if (led->runNum > 0 && blinkCount >= led->runNum) {
        LED_SetState(led->ledMask, LED_OFF); // 关闭LED
        // 达到指定次数后停止闪烁
        return 0;
    }

    LED_SetState(led->ledMask, LED_ON); // 常亮
    return 1;
}

// LED闪烁状态更新函数
#if (BLINK_ENABLE)
static uint8_t LED_Blinking_Update(LED_Config_t *led) 
{
    // 周期时间
    uint32_t run_cycle = led->blinkParams.onTime + led->blinkParams.offTime;
    // 计算已经进行了多少次闪烁
    uint16_t blinkCount = GetTickDiff(led->currentTime) / run_cycle;
    // 计算当前时间在周期中的位置
    uint32_t sec_left = GetTickDiff(led->currentTime) % run_cycle;   
    // 判断是否大于运行次数
    if (led->runNum > 0 && blinkCount >= led->runNum) {
        
        LED_SetState(led->ledMask, LED_OFF); // 关闭LED
        // 达到指定次数后停止闪烁
        return 0;
    }

    // 判断当前时间是否在一个周期内的亮灭时间段内
    if (sec_left <= led->blinkParams.onTime) {
        LED_SetState(led->ledMask, led->blinkParams.orDer ? LED_OFF : LED_ON); // 先灭后亮
    } else if (sec_left <= run_cycle) {
        LED_SetState(led->ledMask, led->blinkParams.orDer ? LED_ON : LED_OFF); // 先亮后灭
    }
    return 1;
}
#endif

// LED交替闪烁状态更新函数
#if (ALTERNATING_BLINK_ENABLE)
static uint8_t LED_AlternatingBlinking_Update(LED_Config_t *led) 
{
    // 计算已经进行了多少次交替
    uint16_t blinkCount = GetTickDiff(led->currentTime) / led->alternatingBlinkParams.Cycle;
    // 计算当前时间在周期中的位置
    uint32_t sec_left = GetTickDiff(led->currentTime) % led->alternatingBlinkParams.Cycle;  

    // 判断是否大于运行次数
    if (led->runNum > 0 && blinkCount >= led->runNum) {
        LED_SetState(led->ledMask, LED_OFF); // 关闭LED
        // 达到指定次数后停止闪烁
        return 0;
    }
    // 计算每一组的时间片
    uint32_t timeSlice = led->alternatingBlinkParams.Cycle / ALTERNAT_GROUP;

    // 判断当前时间是否在哪一组的亮时间段内
    for (size_t i = 0; i < ALTERNAT_GROUP; i++)
    {
        if (sec_left > (timeSlice*i) && sec_left <= (timeSlice*(i+1)))
        {
            LED_SetState(led->alternatingBlinkParams.Group[i],LED_ON); // 亮
        }else
        {
            LED_SetState(led->alternatingBlinkParams.Group[i],LED_OFF); // 灭
        }
        
    }
    return 1;
}
#endif

// LED呼吸状态更新函数
#if (BREATH_ENABLE)
static uint8_t LED_Breathing_Update(LED_Config_t *led) {
    //记录占空比
    uint8_t result = 0;

    // 计算增减步数
    uint8_t stepNum = (led->breathParams.maxCycle - led->breathParams.minCycle) / led->breathParams.step;
    
    // 计算呼吸周期总时间
    uint32_t breathCycleTime = led->breathParams.onTime + led->breathParams.offTime;
    
    // 计算已经进行了多少次呼吸
    uint16_t breathCount = GetTickDiff(led->currentTime) / breathCycleTime;
    
    // 计算当前时间在周期中的位置
    uint32_t timeInCycle = GetTickDiff(led->currentTime) % breathCycleTime;

    // 静态变量,用于记录上次更新时间
    static uint32_t lastUpdateTime;
    
    // 判断是否大于运行次数
    if (led->runNum > 0 && breathCount >= led->runNum) {
        led->breathParams.pwmCallback(led->breathParams.minCycle); // 关闭LED
        // 达到指定次数后停止呼吸
        return 0;
    }

    // 根据当前呼吸周期阶段进行占空比调整
    if (led->breathParams.currentCycle >= (led->breathParams.maxCycle * 2)) {
        led->breathParams.currentCycle = led->breathParams.minCycle;
    } else {
        // 计算当前阶段每个梯度的时间
        uint32_t stepTime = (led->breathParams.currentCycle >= led->breathParams.maxCycle) ? 
                (led->breathParams.offTime / stepNum) : (led->breathParams.onTime / stepNum);
        
        // 检查距离上次更新时间是否超过了应该增加的时间
        if (GetTickDiff(lastUpdateTime) >= stepTime) {
            // 增加占空比梯度
            led->breathParams.currentCycle += led->breathParams.step;
            // 更新上次更新时间
            lastUpdateTime = TIME_Get(); 
        }
    }

    // 返回当前占空比
    if (led->breathParams.currentCycle <= led->breathParams.maxCycle) {
        result = led->breathParams.currentCycle;
    } else {
        result = (led->breathParams.maxCycle * 2) - led->breathParams.currentCycle;
    }

    led->breathParams.pwmCallback(result);
    return 1;
}
#endif

// LED流水灯状态更新函数
#if (RUNNING_ENABLE)
static uint8_t LED_Running_Update(LED_Config_t *led) {
    // 记录 LED 灯的数量
    uint8_t count = 0;
    // 记录 LED 灯的映射
    uint8_t mask = led->ledMask;

    // 获取最低位的 LED 灯
    uint16_t Running_low = (led->ledMask & (~led->ledMask+1)); 
    // 计算 LED 灯的数量
    while (mask) {
        mask &= (mask - 1);
        count++;
    }
    
    // 获取当前已经进行了多少次流水
    uint16_t flowCount = GetTickDiff(led->currentTime) / led->runningParams.cycleTime;

    // 判断是否超过运行次数
    if (led->runNum > 0 && flowCount >= led->runNum) {
        LED_SetState(led->ledMask, LED_OFF); // 关闭LED
        // 达到指定次数后停止流水
        return 0;
    }

    // 判断是否到达下次流水的间隔时间
    if (GetTickDiff(led->runningParams.lastCycleTime) >= led->runningParams.intervalTime) {
        // 判断是否到达 LED 点亮的间隔时间
        if (GetTickDiff(led->runningParams.lastLEDTime) >= led->runningParams.cycleTime) {
            // 判断是否已经点亮所有 LED
            if (led->runningParams.numLEDs >= count) {
                // 如果已经点亮所有 LED,则将 LED 灭掉并更新时间
                LED_SetState(led->runningParams.currentSite, LED_OFF);
                led->runningParams.lastCycleTime = TIME_Get(); 
                led->runningParams.numLEDs = 0;
                led->runningParams.currentSite = 0;
            }else
            {
                // 更新 LED 灯的数量和位置
                led->runningParams.numLEDs++;
                led->runningParams.currentSite <<= 1;
                led->runningParams.currentSite |= Running_low;
                // 点亮 LED 并更新时间
                LED_SetState(led->runningParams.currentSite, LED_ON);
                led->runningParams.lastLEDTime = TIME_Get(); 
            }      
        } 
    }
    return 1;
}
#endif

// LED跑马灯状态更新函数
#if (MARQUEE_ENABLE)
static uint8_t LED_MARQUEE_Update(LED_Config_t *led) {
    // 记录 LED 灯的数量
    uint8_t count = 0;
    // 记录 LED 灯的映射
    uint8_t mask = led->ledMask;

    // 获取最低位的 LED 灯
    uint16_t Running_low = (led->ledMask & (~led->ledMask+1)); 
    // 计算 LED 灯的数量
    while (mask) {
        mask &= (mask - 1);
        count++;
    }
    
    // 获取当前已经进行了多少次跑马
    uint16_t flowCount = GetTickDiff(led->currentTime) / led->marqueeParams.cycleTime;

    // 判断是否超过运行次数
    if (led->runNum > 0 && flowCount >= led->runNum) {
        LED_SetState(led->ledMask, LED_OFF); // 关闭LED
        // 达到指定次数后停止跑马
        return 0;
    }

    // 判断是否到达下次跑马的间隔时间
    if (GetTickDiff(led->marqueeParams.lastCycleTime) >= led->marqueeParams.intervalTime) {
        // 判断是否到达 LED 点亮的间隔时间
        if (GetTickDiff(led->marqueeParams.lastLEDTime) >= led->marqueeParams.cycleTime) {
            // 判断是否已经点亮所有 LED
            if (led->marqueeParams.numLEDs >= count) {
                // 如果已经点亮所有 LED,则将 LED 灭掉并更新时间
                LED_SetState(led->marqueeParams.currentSite, LED_OFF);
                led->marqueeParams.lastCycleTime = TIME_Get(); 
                led->marqueeParams.numLEDs = 0;
                led->marqueeParams.currentSite = 0;
            }else
            {
                LED_SetState(led->marqueeParams.currentSite, LED_OFF);
                // 更新 LED 灯的数量和位置
                led->marqueeParams.numLEDs++;
                if (led->marqueeParams.currentSite == 0)
                {
                    led->marqueeParams.currentSite = Running_low;
                }else
                {
                    led->marqueeParams.currentSite <<= 1;
                }
                // 点亮 LED 并更新时间
                LED_SetState(led->marqueeParams.currentSite, LED_ON);
                led->marqueeParams.lastLEDTime = TIME_Get(); 
            }      
        } 
    }
    return 1;
}
#endif
/**
 * @file led.h
 * @author cyWu (1917507415@qq.com)
 * @brief LED应用层框架
 * @version 0.1
 * @date 2024-02-22
 *
 * @copyright Copyright (c) 2024
 *
 */

#ifndef LED_H
#define LED_H

#include <main.h>
#include <stdint.h>

#define BLINK_ENABLE 1
#define ALTERNATING_BLINK_ENABLE 1
#define BREATH_ENABLE 0
#define RUNNING_ENABLE 0
#define MARQUEE_ENABLE 1
// 定义LED开关状态
#define LED_ON 1
#define LED_OFF 0

// 定义LED通道宏
#define LED_CHANNEL(user_led) (1 << (user_led))

// LED状态枚举
typedef enum
{
    LED_LIGHT,             // 常亮状态
    LED_BLINKING,          // 闪烁状态
    LED_ALTERNATING_BLINK, // 交替闪烁模式
    LED_BREATHING,         // 呼吸状态
    LED_RUNNING,           // 流水灯状态
    LED_MARQUEE            // 跑马灯状态
} LED_State_t;

// LED事件枚举
typedef enum
{
    EVENT_NULL,         // 无事件
    EVENT_LOCK,         // 锁定事件
    EVENT_LOCK_WARN,    // 锁定通知事件
    EVENT_UNLOCK,       // 解锁事件
    EVENT_POWER_TEST,   // 上电事件
    EVENT_NOT_CHARGING, // 不充电事件
    EVENT_CHARGING,     // 充电事件
    EVENT_FULL_BATTERY, // 充满电事件
    EVENT_LOW_BATTERY,  // 缺电事件
    EVENT_CURRENT_HIGH, // 电机电流过大事件
    EVENT_MAX           // 事件数量
} LED_Event_t;

// LED事件优先级枚举
typedef enum
{
    PRIORITY_1,
    PRIORITY_2,
    PRIORITY_3,
    PRIORITY_4,
    PRIORITY_5,
    PRIORITY_MAX // 优先级枚举的最大值,用于数组大小
} LED_EventPriority_t;

#if (BLINK_ENABLE)
// LED 闪烁参数结构体
__packed typedef struct
{
    uint8_t orDer;    // 用于判断先开还是先关,1:先灭后亮,0:先亮后灭
    uint32_t onTime;  // 亮时间(毫秒)
    uint32_t offTime; // 灭时间(毫秒)
} LED_BlinkParams_t;
#endif

#if (ALTERNATING_BLINK_ENABLE)
#define ALTERNAT_GROUP 2
// LED交替闪烁参数结构体
__packed typedef struct
{
    uint16_t Group[ALTERNAT_GROUP]; // 交替组(2组)
    uint32_t Cycle;                 // 交替周期时间(毫秒)
} LED_AlternatingBlinkParams_t;

#endif

#if (BREATH_ENABLE)
// LED 呼吸参数结构体
typedef struct
{
    uint8_t maxCycle;                  // 最大占空比(0~100%)
    uint8_t minCycle;                  // 最小占空比(0~100%)
    uint8_t currentCycle;              // 当前占空比(0~100%)
    uint8_t step;                      // 增减梯度
    uint32_t onTime;                   // 呼吸亮时间(毫秒)
    uint32_t offTime;                  // 呼吸灭时间(毫秒)
    void (*pwmCallback)(uint8_t Duty); // PWM回调函数
} LED_BreathParams_t;
#endif

#if (RUNNING_ENABLE)
// LED 流水灯参数结构体
__packed typedef struct
{
    uint32_t cycleTime;     // 流水灯周期时间(毫秒)
    uint32_t intervalTime;  // 下次运行的间隔时间(毫秒)
    uint32_t lastCycleTime; // 上次周期运行完的记录时间戳
    uint32_t lastLEDTime;   // 上个 LED 点亮的记录时间戳
    uint32_t currentSite;   // 流水灯的当前位置
    uint32_t numLEDs;       // 流水灯的 LED 数量
} LED_RunningParams_t;
#endif

#if (MARQUEE_ENABLE)
// LED 跑马灯参数结构体
__packed typedef struct
{
    uint32_t cycleTime;     // 跑马灯周期时间(毫秒)
    uint32_t intervalTime;  // 下次运行的间隔时间(毫秒)
    uint32_t lastCycleTime; // 上次周期运行完的记录时间戳
    uint32_t lastLEDTime;   // 上个 LED 点亮的记录时间戳
    uint32_t currentSite;   // 跑马灯的当前位置
    uint32_t numLEDs;       // 跑马灯的 LED 数量
} LED_MarqueeParams_t;
#endif

// LED 配置结构体
__packed typedef struct
{
    LED_State_t state;    // LED状态
    uint16_t ledMask;     // LED掩码
    uint16_t runNum;      // 运行次数(0表示无限次)
    uint32_t currentTime; // 运行时的时间戳
#if (BLINK_ENABLE)
    LED_BlinkParams_t blinkParams; // 闪烁参数
#endif
#if (BREATH_ENABLE)
    LED_BreathParams_t breathParams; // 呼吸参数
#endif
#if (RUNNING_ENABLE)
    LED_RunningParams_t runningParams; // 流水灯参数
#endif
#if (ALTERNATING_BLINK_ENABLE)
    LED_AlternatingBlinkParams_t alternatingBlinkParams; // 交替闪烁参数
#endif
#if (MARQUEE_ENABLE)
    LED_MarqueeParams_t marqueeParams; // 跑马灯参数
#endif
} LED_Config_t;

// LED事件表项结构体
__packed typedef struct
{
    LED_Event_t event;                                // 事件
    LED_EventPriority_t priority;                     // 优先级
    LED_Config_t config;                              // LED配置
    uint8_t (*ledEventHandler)(LED_Config_t *config); // LED事件处理回调函数
} LED_EventTableItem_t;

// LED状态设置函数
typedef void (*LED_SetState_t)(uint16_t led, uint8_t state);
// 获取时间戳函数
typedef uint32_t (*TIME_Get_t)(void);

// 设置led状态回调函数
void LED_SetStateInit(LED_SetState_t setState);
// 设置获取时间戳回调函数
void SET_TimeGetInit(TIME_Get_t getTime);
// LED初始化函数
void LED_EventTableInit(LED_EventTableItem_t ledEvent[]);
// 将LED事件加入事件表
void LED_EventAdd(LED_Event_t ledEvent);
// 将LED事件从事件表删除
void LED_EventDelete(LED_Event_t ledEvent);
// LED事件处理函数
void LED_EventHandle(void);
// LED更新函数
uint8_t LED_Update(LED_Config_t *led);

#endif // LED_H

结语

通过以上设计和实现,我开发了一种基于事件驱动的LED控制框架,该框架将LED控制从底层解耦,只关注应用层,提供了一种通用的LED控制方案,使得开发人员可以轻松实现各种LED效果,极大地提高了开发效率和灵活性。该框架不仅简化了LED控制的代码编写,还提供了丰富的功能模块,可以满足不同项目的需求,具有较高的通用性和可扩展性。

以上是LED框架的设计思路、核心代码和使用示例,希望能够对嵌入式系统开发中的LED控制提供一种新的思路和解决方案。

  • 28
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值