当前位置: 首页 > news >正文

基于队列构建优先级抢占机制的LED灯框架设计与实现

文章目录

  • 前言
  • 一、LED 显示框架概述
    • 1. 框架结构图
    • 2. 基本机制
  • 二、核心结构与接口设计
    • 1. 状态命令结构
    • 2. 状态项结构
    • 3. LED框架配置结构
    • 4. LED运行控制器
  • 三、LED框架逻辑流程
    • 1. 初始化逻辑
    • 2. 优先级抢占判断与处理逻辑
    • 3. 执行队列命令并处理tick
    • 4. 队列为空时的默认状态回滚
  • 四、LED状态模块封装样例
    • 1. 颜色定义与显示
    • 2. 定义状态项数组与配置
  • 五、框架使用接口
  • 六、总结与展望


前言

在嵌入式系统中,RGB LED状态指示常用于设备运行状态、故障信息或工作模式的直观提示。在多个状态同时存在的情况下,我们希望能让更紧急或重要的状态信息抢占当前的LED显示内容,同时又能保留各状态的独立性和易于扩展的逻辑。

本文将详细解析该LED显示框架的设计思路、核心组件及其实现方式,并对关键代码进行深入剖析,帮助读者理解如何在嵌入式系统中高效地管理LED状态显示。它具有以下核心特性:

  • ✅ 支持多个状态模块

  • ✅ 支持不同状态的优先级判断

  • ✅ 状态判断函数独立,便于维护

  • ✅ 状态优先级支持抢占式切换

  • ✅ 同一优先级的状态为先进先出

  • ✅ 支持插队队列管理显示时序

一、LED 显示框架概述

该LED显示框架的设计目标是实现对LED状态的智能化管理,具体包括:​

  • 任务优先级管理:​不同的LED状态具有不同的优先级,高优先级的状态可以抢占低优先级的状态显示。​

  • 队列机制:​同一优先级的状态按照先进先出的原则进行显示,确保状态切换的有序性。​

  • 模块化设计:​将LED状态的检测、插入、执行等功能模块化,提升代码的可读性和可维护性。​

1. 框架结构图

+---------------------------+
|     led_arch_t 控制器     |
+---------------------------+
|   config 配置结构体       |
|   cmd_queue 指令队列       |
|   cur_led_id 当前状态ID    |
|   tick 计数器              |
+---------------------------+
         |
         | 调用周期函数
         v
+---------------------------+
|     led_on_tick()         |
+---------------------------+
        |
        | 查询各状态check函数(按优先级)
        v
+---------------------------+
|   判断是否抢占并更新状态   |
+---------------------------+
        |
        | 出队并执行 color_exec()
        v
+---------------------------+
|     LED 实际颜色控制逻辑  |
+---------------------------+

2. 基本机制

  • 每个LED状态模块对应一个 led_arch_t 实例;

  • 每个状态定义一个 led_item_t,包含状态ID、优先级、检测函数;

  • led_cmd_t 用于表示某一颜色状态及持续时长;

  • 状态变化以命令队列形式插入,每周期执行一个命令;

  • 高优先级状态抢占低优先级状态,并清空其未执行完的命令;

  • 同一优先级状态不会抢占,而是先进先出轮流执行。

二、核心结构与接口设计

1. 状态命令结构

typedef struct {
    uint8_t color;  // 颜色枚举值
    uint8_t ticks;  // 显示该颜色的周期数
} led_cmd_t;

每条命令定义一种颜色在一定时间内保持显示。

2. 状态项结构

typedef struct {
    uint16_t id;                    // 状态 ID
    uint8_t  prio;                  // 优先级,值越小优先级越高
    bool_t (*led_sta_check)(void);  // 检查函数,判断当前状态是否激活
} led_item_t;

每种状态都可配置一个 check 函数,若返回 true 表示状态应被激活。

3. LED框架配置结构

typedef struct {
	char      *name;                  // 名称
	led_cmd_t  *cmd_buf;              // 命令缓冲区(循环队列)
	uint16_t   cmd_buf_size;          // 命令缓冲区大小

	const led_item_t    *led_item;    // 所有状态定义数组
	const uint16_t      led_item_num;// 状态总数

	void (*color_exec)(uint8_t color); // 执行颜色显示函数
} led_arch_config_t;

4. LED运行控制器

typedef struct {
    const led_arch_config_t *config;

	ring_queue_t cmd_queue;   // 实际的命令队列结构(环形队列)

	uint32_t tick;            // 当前命令已经执行的tick数
	uint16_t cur_led_id;      // 当前正在运行的状态ID
	uint8_t  init_flag;       // 是否已经初始化
} led_arch_t;

三、LED框架逻辑流程

1. 初始化逻辑

if(p->init_flag == 0)
{
    p->init_flag = 1;
    init_queue(&p->cmd_queue, NULL, p->config->cmd_buf_size);

    p->tick = 0;
    p->cur_led_id = LED_STA_ID_DEFAULT;

    if(p->config->led_item[LED_ID_INIT].led_sta_check)
    {
        p->cur_led_id = LED_ID_INIT;
        p->config->led_item[LED_ID_INIT].led_sta_check();
    }
}

首次调用 led_on_tick() 时自动初始化,并调用 INIT 状态的 check 函数插入初始命令。

2. 优先级抢占判断与处理逻辑

for(uint16_t id=(LED_ID_INIT+1); id<p->config->led_item_num; ++id)
{
    if(p->config->led_item[id].prio < p->config->led_item[p->cur_led_id].prio)
    {
        if(p->config->led_item[id].led_sta_check && p->config->led_item[id].led_sta_check())
        {
            // 抢占当前低优先级状态
            for(uint16_t i=0; i<queue_length(&p->cmd_queue); ++i)
                rdIdx_add(&p->cmd_queue); // 清空现有命令

            p->cur_led_id = id;  // 切换当前状态
            break;
        }
    }
    else break;
}
  • 只检测优先级更高的状态

  • 如果检测为真,则清除命令队列,实现抢占

  • 切换当前状态ID

3. 执行队列命令并处理tick

if(queue_empty(&p->cmd_queue) == FALSE)
{
    uint16_t rdIdx = get_queue_rdIdx_index(&p->cmd_queue);
    p->config->color_exec(p->config->cmd_buf[rdIdx].color);

    ++p->tick;
    if(p->tick >= p->config->cmd_buf[rdIdx].ticks)
    {
        rdIdx_add(&p->cmd_queue);
        p->tick = 0;
    }
}

每次 tick 调用:

  • 从队头读取一条命令

  • 调用 color_exec 真实点灯

  • 达到tick数后出队

4. 队列为空时的默认状态回滚

else 
{
    if (p->config->led_item[p->cur_led_id].led_sta_check() != TRUE)
    {
        p->cur_led_id = p->config->led_item_num - 1; // 默认态
        for(uint16_t id=(LED_ID_INIT+1); id<p->config->led_item_num; ++id) 
        {
            if(p->config->led_item[id].led_sta_check && p->config->led_item[id].led_sta_check())
            {
                p->cur_led_id = id;
                break;
            }
        }
    }
}

若当前状态失效且队列为空,回退到默认状态。

四、LED状态模块封装样例

1. 颜色定义与显示

typedef enum {
    LED_OFF,
    LED_RED,
    LED_GREEN,
    LED_BLUE,
    LED_YELLOW,
    LED_WHITE,
} color_t;

void sta_led_color_exec(uint8_t color)
{
    switch(color)
    {
        case LED_RED:   LED_show(RED); break;
        case LED_GREEN: LED_show(GREEN); break;
        case LED_BLUE:  LED_show(BLUE); break;
        case LED_YELLOW:LED_show(YELLOW); break;
        case LED_WHITE: LED_show(WHITE); break;
        case LED_OFF:   LED_show(0); break;
        default:        break;
    }
}

2. 定义状态项数组与配置

const static led_item_t led_sta_item[] = {
    {LED_INIT,    0, led_init},
    {LED_TASK1,   1, led_task1},
    {LED_TASK2,   2, led_task2},
    {LED_TASK3,   3, led_task3},
    {LED_TASK4,   4, led_task4},
};

const static led_arch_config_t led_sta_config = {
    .name = "sys sta led",
    .cmd_buf = led_sta_cmd_buf,
    .cmd_buf_size = 16,
    .led_item = led_sta_item,
    .led_item_num = sizeof(led_sta_item) / sizeof(led_item_t),
    .color_exec = sta_led_color_exec,
};

static led_arch_t led_sta_arch = {
    .config = &led_sta_config,
};

五、框架使用接口

void led_sta_on_tick(void)
{
    led_on_tick(&led_sta_arch);  // 每周期调用
}

void led_sta_clean(void)
{
    led_on_clean(&led_sta_arch); // 清除命令
}

六、总结与展望

本框架结合优先级调度、命令队列、颜色执行解耦等技术手段,构建了一个灵活而强大的LED指示灯状态控制方案。其特点如下:

  • 支持多个状态同时注册;

  • 通过优先级实现紧急状态的插队处理;

  • 支持FIFO队列展示同优先级下的多个状态指示;

  • 支持动态插入状态指令,适应复杂系统场景;

  • 框架通用,可在多个产品中复用。

后续可扩展功能包括:

  • 状态时间动态可调;

  • LED闪烁模式定义;

  • 多灯协同控制(如多个LED协同构成特定图案);

  • 低功耗模式下的灯效优化等。

相关文章:

  • 中国建设银行新闻网站郑州seo推广外包
  • 做网站用java关键词爱站网关键词挖掘工具
  • python做爬虫和做网站/口碑营销案例2022
  • 免费建筑设计素材网站/百度官方入口
  • 网站正在建设 英文翻译/福建seo学校
  • 新闻发稿软文发布投稿选择媒体时几大注意
  • 企业使用文档加密系统的两个重要原因。
  • 【OSG学习笔记】Day 2: 场景图(Scene Graph)的核心概念
  • CUDA 工具链将全面原生支持 Python
  • Odrive0.5.1-FOC电机控制 arm_cos_f32.cpp arm_sin_f32.cpp代码实现(二)
  • ChatGPT的GPT-4o创建图像Q版人物提示词实例展示
  • `mpi4py` 是什么; ModuleNotFoundError: No module named ‘mpi4py
  • SQL练习题
  • 智慧医院常用的子系统介绍 51-100
  • C语言学习记录(14)自定义类型:联合和枚举
  • ABAP小白开发操作手册+(十)验证和替代——下
  • velero
  • Lua 函数使用的完整指南
  • 操作符详解(下)——包含整形提升
  • 深入解析Java内存与缓存:从原理到实践优化
  • 将 CrewAI 与 Elasticsearch 结合使用
  • 蓝桥杯-小明的彩灯(Java-差分)
  • 网络稳定性--LCA+最大生成树+bfs1/dfs1找最小边
  • 996引擎-实战笔记:小地图传送【PC右键/手机长按】
  • Python Cookbook-5.10 选取序列中最小的第 n个元素