基于队列构建优先级抢占机制的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;                    // 状态 IDuint8_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;      // 当前正在运行的状态IDuint8_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协同构成特定图案);

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/75149.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PyQt6实例_A股财报数据维护工具_解说并数据与完整代码分享

目录 1 20250403之前的财报数据 2 整个项目代码 3 工具使用方法 3.1 通过akshare下载 3.2 增量更新 3.3 查看当前数据情况 3.4 从数据库中下载数据 视频 1 20250403之前的财报数据 通过网盘分享的文件&#xff1a;财报三表数据20250403之前.7z 链接: https://pan.ba…

React 之 Redux 第三十一节 useDispatch() 和 useSelector()使用以及详细案例

使用 Redux 实现购物车案例 由于 redux 5.0 已经将 createStore 废弃&#xff0c;我们需要先将 reduxjs/toolkit 安装一下&#xff1b; yarn add reduxjs/toolkit// 或者 npm install reduxjs/toolkit使用 vite 创建 React 项目时候 配置路径别名 &#xff1a; // 第一种写法…

Spring Boot 中集成 Knife4j:解决文件上传不显示文件域的问题

Spring Boot 中集成 Knife4j&#xff1a;解决文件上传不显示文件域的问题 在使用 Knife4j 为 Spring Boot 项目生成 API 文档时&#xff0c;开发者可能会遇到文件上传功能不显示文件域的问题。本文将详细介绍如何解决这一问题&#xff0c;并提供完整的解决方案。 Knife4j官网…

OpenCV 图形API(17)计算输入矩阵 src 中每个元素的平方根函数sqrt()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 描述 计算数组元素的平方根。 cv::gapi::sqrt 函数计算每个输入数组元素的平方根。对于多通道数组&#xff0c;每个通道会独立处理。其精度大约与内置的 …

大学论文书写规范与格式说明

大学论文书写规范与格式说明 (适用于人文社科、理工科通用框架) 一、论文整体结构 1. 基本组成部分 封面 包含论文标题、作者姓名、学院/专业、学号、指导教师、提交日期等(按学校模板填写)。 中英文摘要 中文摘要:300~500字,概述研究背景、方法、结论与创新点,末尾附…

C# 串口通信

1. 导入 using System.IO.Ports;2. 初始化定义 SerialPort sp new SerialPort(); // 设置串口 sp.PortName "COM3"; // 串口 sp.BaudRate 9600; // 波特率 sp.Parity Parity.None; // 校验位 sp.DataBits 8; // 数据位 sp.StopBits StopBits.One; // 停…

android14 keycode 上报 0 解决办法

驱动改完后发现上报了keycode=0 04-07 13:02:33.201 2323 2662 D WindowManager: interceptKeyTq keycode=0 interactive=false keyguardActive=true policyFlags=2000000 04-07 13:02:33.458 2323 2662 D WindowManager: interceptKeyTq keycode=0 interactive=false key…

C++day9

思维导图 牛客练习 练习&#xff1a; 将我们写的 myList 迭代器里面 operator[] 和 operator 配合异常再写一遍 #include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> #include <sstream> #include <vector>…

批量合并多张 jpg/png 图片为长图或者 PDF 文件,支持按文件夹合并图片

我们经常会碰到需要将多张图片拼成一张图片的场景&#xff0c;比如将多张图片拼成九宫格图片&#xff0c;或者将多张图片拼成一张长图。还有可能会碰到需要将多张图片合并成一个完整的 PDF 文件来方便我们进行打印或者传输等操作。那这些将图片合并成一张图片或者一个完整的文档…

程序化广告行业(73/89):买卖双方需求痛点及应对策略深度剖析

程序化广告行业&#xff08;73/89&#xff09;&#xff1a;买卖双方需求痛点及应对策略深度剖析 大家好&#xff01;一直以来&#xff0c;我都热衷于在技术领域探索学习&#xff0c;也深知知识的分享能让我们共同进步。写这篇博客的目的&#xff0c;就是希望能和大家一起深入了…

[随笔] nn.Embedding的前向传播与反向传播

nn.Embedding的前向传播与反向传播 nn.Embedding的前向计算过程 embedding module 的前向过程其实是一个索引&#xff08;查表&#xff09;的过程 表的形式是一个 matrix&#xff08;embedding.weight, learnable parameters&#xff09; matrix.shape: (v, h) v&#xff1a;…

构建实时、融合的湖仓一体数据分析平台:基于 Delta Lake 与 Apache Iceberg

1. 执行摘要 挑战&#xff1a; 传统数据仓库在处理现代数据需求时面临诸多限制&#xff0c;包括高昂的存储和计算成本、处理海量多样化数据的能力不足、以及数据从产生到可供分析的端到端延迟过高。同时&#xff0c;虽然数据湖提供了低成本、灵活的存储&#xff0c;但往往缺乏…

Maven error:Could not transfer artifact

问题描述 当项目从私有仓库下载依赖时&#xff0c;Maven 报错&#xff0c;无法从远程仓库下载指定的依赖包&#xff0c;错误信息如下&#xff1a; Could not transfer artifact com.ding.abcd:zabk-java:pom from/to releases (http://192.1122.101/repory/mavenleases/): 此…

Dify 生成提示词的 Prompt

Dify 生成提示词的 Prompt **第1次提示词****第2次提示词****第3次提示词**总结 Dify 生成提示词是&#xff0c;会和LLM进行3次交互&#xff0c;下面是和LLM进行交互是的Prompt。 以下是每次提示词的概要、目标总结以及原始Prompt&#xff1a; 第1次提示词 概要&#xff1a; …

sqli-labs靶场 less4

文章目录 sqli-labs靶场less 4 联合注入 sqli-labs靶场 每道题都从以下模板讲解&#xff0c;并且每个步骤都有图片&#xff0c;清晰明了&#xff0c;便于复盘。 sql注入的基本步骤 注入点注入类型 字符型&#xff1a;判断闭合方式 &#xff08;‘、"、’、“”&#xf…

【什么是动态链接?这里的动态是什么意思?链接了什么?】

动态链接&#xff08;Dynamic Linking&#xff09;详解 1. 什么是动态链接&#xff1f; 动态链接是 Java 虚拟机&#xff08;JVM&#xff09;在运行时将字节码中的符号引用&#xff08;Symbolic Reference&#xff09;转换为直接引用&#xff08;Direct Reference&#xff09;…

AWS S3深度剖析:云存储的瑞士军刀

1. 引言 在当今数据驱动的世界中,高效、可靠、安全的数据存储解决方案至关重要。Amazon Simple Storage Service (S3)作为AWS生态系统中的核心服务之一,为企业和开发者提供了一个强大而灵活的对象存储平台。本文将全面解析S3的核心特性,帮助读者深入理解如何充分利用这一&q…

【Game】Powerful——Martial Arts Challenge(6)

文章目录 攻略关卡一&#xff08;虎子&#xff09;关卡二关卡三关卡四关卡五关卡六——奇穷 攻略 关卡一&#xff08;虎子&#xff09; 参战选手 出手顺序 关卡二 参战选手 出手顺序 关卡三 参战选手 出手顺序 关卡四 参战选手 出手顺序 关卡五 参战选手 出手顺序 关卡六…

PPIO × UI-TARS:用自然语言操控电脑,AI Agent 的极致体验

Manus的爆火预示着AI 正在从单纯的文本生成和图像识别迈向更复杂的交互场景。字节跳动近期推出的开源项目 UI-TARS Desktop 为我们展示了一种全新的可能性&#xff1a;能够通过自然语言理解和处理来控制计算机界面。这款工具代表了人工智能与人机交互领域的重大突破&#xff0c…

电脑屏保壁纸怎么设置 桌面壁纸设置方法详解

电脑桌面壁纸作为我们每天面对的第一视觉元素&#xff0c;不仅能够彰显个人品味&#xff0c;还能营造舒适的工作或娱乐氛围。电脑桌面壁纸怎么设置呢&#xff1f;下面本文将为大家介绍Windows和macOS两大主流操作系统中设置电脑桌面壁纸的方法&#xff0c;帮助大家快速设置个性…