分享一款嵌入式开源LED指示灯控制代码框架cotLed

一、工程简介

        cotLed是一款轻量级的LED控制软件框架,可以十分方便地控制及自定义LED的各种状态,移植方便,无需修改,只需要在初始化时实现单片机硬件GPIO初始化,同时为框架接口提供GPIO写函数即可。

        框架代码工程地址:https://gitee.com/cot_package/cot_led

        工程代码结构也很精简,只用两个文件cot_led.c和cot_led.h实现具体功能,对外提供API接口函数,适用于裸机和带操作系统的应用代码。

图片

        通过该软件框架API,可以实现的LED控制接口功能有:

        (1)、单个LED的亮灭、翻转、闪烁、呼吸灯、自定义(如多少秒快闪几次等)等多种功能;

        (2)、多个LED组合的跑马灯、流水灯等功能;

        (3)、上述各个功能模式功能实现的次数设置。


二、工程代码分析

        在头文件cot_led.h中包括:

        (1)定义了LED亮灭的枚举cotLedState_e;

        (2)定义了写入IO状态的函数指针cotLedCtrl_f;

        (3)定义了LED核心控制功能成员变量的结构体cotLedProc_t;

        (4)外部声明的LED控制接口函数。

/* Define to prevent recursive inclusion -----------------------------------------------------------------------------*/
#ifndef _COT_LED_H_
#define _COT_LED_H_/* Includes ----------------------------------------------------------------------------------------------------------*/
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>/* Exported types ----------------------------------------------------------------------------------------------------*/// 状态bit位所使用的byte数,bit之间的控制时间为时间颗粒度
#define LED_STATE_BYTE_NUM       4/*** @brief  LED亮灭枚举定义*/
typedef enum{COT_LED_OFF = 0,                     /*!< (0)灯灭 */COT_LED_ON = !COT_LED_OFF            /*!< (1)灯亮 */
} cotLedState_e;typedef void (*cotLedCtrl_f)(cotLedState_e state);
typedef uint16_t led_t;typedef struct
{uint8_t validBits;                 /*!< 状态有效bit位 */uint8_t offset;                    /*!< 状态bit位偏移 */uint8_t count;                     /*!< 控制次数 */uint8_t isSetCount : 1;            /*!< 是否设置了控制次数 */uint8_t defState : 1;              /*!< 默认状态 */uint8_t curState : 1;              /*!< 当前状态 */uint8_t pwmDir : 1;                /*!< PWM增减方向 */uint8_t isPwm : 1;                 /*!< PWM模式 */uint16_t tic;                      /*!< 时间计数器 */uint16_t interval;                 /*!< 每次控制的时间颗粒度,单位为1ms */union{struct{uint16_t onTime;               /*!< 亮的时长 */uint16_t tic;                  /*!< PWM计时 */} pwm;uint8_t state[LED_STATE_BYTE_NUM];  /*!< 状态bit位 */} data;
} cotLedProc_t;typedef struct
{cotLedProc_t proc;cotLedCtrl_f pfnLedCtrl;
} cotLedCfg_t;/* Exported constants ------------------------------------------------------------------------------------------------*/
/* Exported macro ----------------------------------------------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------------------------------------------------*/extern int cotLed_Init(cotLedCfg_t pCfgTable[], size_t num);extern int cotLed_SetState(led_t led, cotLedState_e state);
extern int cotLed_SetStateWithTime(led_t led, cotLedState_e state, uint16_t time);extern int cotLed_ON(led_t led);
extern int cotLed_OFF(led_t led);
extern int cotLed_Toggle(led_t led);extern int cotLed_Twinkle(led_t led, uint16_t time);
extern int cotLed_TwinkleWithCount(led_t led, uint16_t time, uint8_t count, cotLedState_e defState);extern int cotLed_Breathe(led_t led, uint16_t period);
extern int cotLed_BreatheWithCount(led_t led, uint16_t period, uint8_t count, cotLedState_e defState);extern int cotLed_Custom(led_t led, ...);
extern int cotLed_CustomWithCount(led_t led, uint8_t count, cotLedState_e defState, ...);extern int cotLed_Marquee(led_t led[], uint8_t ledNum, int32_t time);
extern int cotLed_MarqueeWithCount(led_t led[], uint8_t ledNum, int32_t time, uint8_t count, cotLedState_e defState);
extern int cotLed_Waterfall(led_t led[], uint8_t ledNum, int32_t time);
extern int cotLed_WaterfallWithCount(led_t led[], uint8_t ledNum, int32_t time, uint8_t count, cotLedState_e defState);extern int cotLed_Ctrl(uint32_t sysTime);#endif

        由于cot_led.c中代码比较多,这里暂时就不贴出,可以参考具体文件中的函数定义和注释内容。

        在头文件cot_led.c中包括:

        (1)呼吸灯软件模拟PWM频率;

        (2)在LED控制接口中需要用到的一些宏定义;

        (3)各类型的LED控制接口。

图片


三、工程代码应用

        工程代码的使用可以参考工程代码包中的examples和readme文件。这里以在stm32平台上使用带有freertos的应用代码中进行各个LED接口函数的测试,测试时使用宏开关TEST_LED_MODE控制分别进行接口功能测试。在应用代码中进行了接口使用的注释。

        应用的流程顺序为:

        (1)初始化各个LED对应GPIO口驱动。

        (2)定义各个LED的IO状态控制函数,调用LED控制初始化函数cotLed_Init,入参为各个LED的IO状态控制函数和LED数量。

        (3)创建周期执行逻辑代码,在带操作系统的代码中创建周期任务;而在裸机系统代码中则创建周期计数逻辑或定时器逻辑。

        (4)在周期执行逻辑代码中周期调用LED控制函数cotLed_Ctrl,入参为当前时间戳ms级的系统时长。

        (5)条件触发调用执行对应的各个LED控制接口函数。

        应用时的一些注意点如下:

        (1)调用接口函数时,不要重复调用,重复调用设置函数相关信息会复位,使用触发式调用即达到某一触发条件时调用接口一次。在实际测试时LED翻转接口cotLed_Toggle需要在循环中重复调用。

        (2)在调用的带时间设置入参的LED控制接口时,该时间需要设置为任务调度周期的倍数;裸机调用时设置为定时器或计数器周期的倍数。比如调度周期或计数器周期为500ms,为该接口设置的时间参数就为500*N。

        (3)如果设置某个LED为呼吸灯模式,则需要保证cotLed_Ctrl调用周期为1ms(优先级需要最高,或者定时器调度效果最好)。

        (4)在操作系统下使用时非线程安全,最好可以使用读写锁,如果没有读写锁则至少使用互斥锁。

#include "sys.h"
#include "delay.h"
#include "FreeRTOS.h"
#include "task.h"
#include "cot_led.h"//任务优先级
#define START_TASK_PRIO     1
//任务堆栈大小    
#define START_STK_SIZE      128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);//任务优先级
#define LED0_TASK_PRIO      2
//任务堆栈大小    
#define LED0_STK_SIZE       50  
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);//任务优先级
#define LED1_TASK_PRIO      3
//任务堆栈大小    
#define LED1_STK_SIZE       50  
//任务句柄
TaskHandle_t LED1Task_Handler;
//任务函数
void led1_task(void *pvParameters);typedef enum
{LED_0 = 0,LED_1,/* 勿删除,用来统计LED的数目 */LED_MAX_NUM
} LedType_e;//LED的IO驱动初始化
void LED_Init(void)
{       GPIO_InitTypeDef  GPIO_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);  //使能GPIOF时钟//GPIOF9,F10初始化设置GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;  //LED0和LED1对应IO口GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;      //普通输出模式GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;    //100MHzGPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;      //上拉GPIO_Init(GPIOF, &GPIO_InitStructure);          //初始化GPIOGPIO_SetBits(GPIOF,GPIO_Pin_9 | GPIO_Pin_10);      //GPIOF9,F10设置高,灯灭}void CtrlLed0(cotLedState_e state) //LED0的IO状态控制函数
{state == COT_LED_ON ? GPIO_ResetBits(GPIOF, GPIO_Pin_9) :  GPIO_SetBits(GPIOF, GPIO_Pin_9);
}void CtrlLed1(cotLedState_e state) //LED1的IO状态控制函数
{state == COT_LED_ON ? GPIO_ResetBits(GPIOF, GPIO_Pin_10) :  GPIO_SetBits(GPIOF, GPIO_Pin_10);
}void FML_LED_Init(void)
{static cotLedCfg_t s_ledTable[LED_MAX_NUM] = {{.pfnLedCtrl = CtrlLed0},{.pfnLedCtrl = CtrlLed1},};LED_Init();             //初始化LED驱动IO端口cotLed_Init(s_ledTable, LED_MAX_NUM); //LED控制初始化
}int main(void)
{ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4delay_init(168);        //初始化延时函数FML_LED_Init();//创建开始任务xTaskCreate((TaskFunction_t )start_task,            //任务函数(const char*    )"start_task",          //任务名称(uint16_t       )START_STK_SIZE,        //任务堆栈大小(void*          )NULL,                  //传递给任务函数的参数(UBaseType_t    )START_TASK_PRIO,       //任务优先级(TaskHandle_t*  )&StartTask_Handler);   //任务句柄              vTaskStartScheduler();          //开启任务调度
}#define TEST_LED_MODE  1   //用于测试各个LED控制接口的宏开关//开始任务任务函数
void start_task(void *pvParameters)
{taskENTER_CRITICAL();           //进入临界区
#if ((TEST_LED_MODE >= 1) && (TEST_LED_MODE <= 6))//创建LED0任务xTaskCreate((TaskFunction_t )led0_task,         (const char*    )"led0_task",       (uint16_t       )LED0_STK_SIZE, (void*          )NULL,              (UBaseType_t    )LED0_TASK_PRIO,    (TaskHandle_t*  )&LED0Task_Handler);                        vTaskDelete(StartTask_Handler); //删除开始任务
#else                               //创建LED1任务xTaskCreate((TaskFunction_t )led1_task,     (const char*    )"led1_task",   (uint16_t       )LED1_STK_SIZE, (void*          )NULL,(UBaseType_t    )LED1_TASK_PRIO,(TaskHandle_t*  )&LED1Task_Handler);    
#endif                              taskEXIT_CRITICAL();            //退出临界区
}//LED任务函数 
void led0_task(void *pvParameters)
{       
#if (TEST_LED_MODE == 1)cotLed_Twinkle(LED_0, 2000); //设置LED0每隔2s进行闪烁(亮灭间隔时间)cotLed_Twinkle(LED_1, 5000); //设置LED1每隔5s进行闪烁(亮灭间隔时间
#elif (TEST_LED_MODE == 2)//设置LED0每隔2s秒进行闪烁,共5次(一亮一灭为一次),次数完成后灯灭cotLed_TwinkleWithCount(LED_0, 2000, 5, COT_LED_ON);//设置LED1每隔1s秒进行闪烁,共4次(一亮一灭为一次),次数完成后点亮cotLed_TwinkleWithCount(LED_1, 1000, 4, COT_LED_OFF);
#elif (TEST_LED_MODE == 3)cotLed_SetStateWithTime(LED_0, COT_LED_ON, 5000);//设置LED0亮持续5秒后熄灭cotLed_SetStateWithTime(LED_1, COT_LED_OFF, 3000);//设置LED1灭持续5秒后点亮
#endif      while(1){
#if (TEST_LED_MODE == 4)cotLed_Toggle(LED_0);//周期翻转LED0cotLed_Toggle(LED_1);//周期翻转LED1   
#elif (TEST_LED_MODE == 5)          if (xTaskGetTickCount() == 0) {cotLed_ON(LED_0);//点亮LED0cotLed_ON(LED_1);//点亮LED1} else if (xTaskGetTickCount() == 5000) {cotLed_OFF(LED_0);//熄灭LED0cotLed_OFF(LED_1);//熄灭LED1} else if(xTaskGetTickCount() == 10000) {cotLed_ON(LED_0);cotLed_ON(LED_1);}
#elif (TEST_LED_MODE == 6)              if (xTaskGetTickCount() == 0) {cotLed_SetState(LED_0, COT_LED_ON);//点亮LED0cotLed_SetState(LED_1, COT_LED_ON);//点亮LED1} else if(xTaskGetTickCount() == 5000) {cotLed_SetState(LED_0, COT_LED_OFF);//熄灭LED0cotLed_SetState(LED_1, COT_LED_OFF);//熄灭LED1} else if(xTaskGetTickCount() == 10000) {cotLed_SetState(LED_0, COT_LED_ON);cotLed_SetState(LED_1, COT_LED_ON);}
#endif//周期调用LED控制函数,入参为当前时间戳ms级的系统时长cotLed_Ctrl(xTaskGetTickCount());vTaskDelay(100);}
} //LED1任务函数 
void led1_task(void *pvParameters)
{
#if (TEST_LED_MODE == 7)//LED0在2秒内1次快闪,亮100ms,灭1900ms,无限制次数cotLed_Custom(LED_0, 100, -1900, 0);//LED1在3秒内1次快闪,亮200ms,灭2800ms,无限制次数cotLed_Custom(LED_1, 200, -2800, 0);
#elif (TEST_LED_MODE == 8)//LED0在2秒内3次快闪,总共5次,次数完成后灯灭  cotLed_CustomWithCount(LED_0, 5, COT_LED_OFF, 100, -100, 100, -100, 100, -100, -1400, 0);//LED1在3秒内2次快闪,总共8次,次数完成后灯亮  cotLed_CustomWithCount(LED_1, 8, COT_LED_ON, 200, -200, 200, -200, -2200, 0);
#elif (TEST_LED_MODE == 9)      cotLed_Breathe(LED_0, 2000);//LED0在2秒内完成一次呼吸亮灭操作,一直执行不限次数cotLed_Breathe(LED_1, 3000);//LED1在3秒内完成一次呼吸亮灭操作,一直执行不限次数
#elif (TEST_LED_MODE == 10)//LED0在2秒内完成一次呼吸亮灭操作,总共3次,次数完成后灯灭cotLed_BreatheWithCount(LED_0, 2000, 3, COT_LED_OFF);//LED1在3秒内完成一次呼吸亮灭操作,总共5次,次数完成后灯亮cotLed_BreatheWithCount(LED_1, 3000, 5, COT_LED_ON);
#elif (TEST_LED_MODE == 11)led_t led[] = {LED_0, LED_1};cotLed_Waterfall(led, 2, 300);//流水灯一直执行,LED之间亮间隔300ms
#elif (TEST_LED_MODE == 12)led_t led[] = {LED_0, LED_1};//流水灯执行8次,LED之间亮间隔300ms,执行完后熄灭cotLed_WaterfallWithCount(led, 2, 300, 8, COT_LED_OFF);
#elif (TEST_LED_MODE == 13) led_t led[] = {LED_0, LED_1};cotLed_Marquee(led, 2, 500);//跑马灯一直执行,LED之间亮间隔500ms
#elif (TEST_LED_MODE == 14) led_t led[] = {LED_0, LED_1};//跑马灯执行5次,LED之间亮间隔500ms,执行完后熄灭cotLed_MarqueeWithCount(led, 2, 500, 5, COT_LED_OFF);
#endifwhile(1){//周期调用LED控制函数,入参为当前时间戳ms级的系统时长cotLed_Ctrl(xTaskGetTickCount());vTaskDelay(1);}
}

↓↓↓更多技术内容和书籍资料获取,入群技术交流敬请关注“明解嵌入式”↓↓↓ 

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

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

相关文章

Apache Dubbo与Nacos整合过程

Dubbo服务发现 Dubbo 提供的是一种 Client-Based 的服务发现机制&#xff0c;依赖第三方注册中心组件来协调服务发现过程&#xff0c;支持常用的注册中心如 Nacos、Consul、Zookeeper 等。 以下是 Dubbo 服务发现机制的基本工作原理图&#xff1a; 服务发现包含提供者、消费者…

LabVIEW中使用 DAQmx Connect Terminals作用意义

该图展示了如何在LabVIEW中使用 DAQmx Connect Terminals.vi 将一个信号从一个源端口连接到一个目标端口。这种处理有以下几个主要目的和作用&#xff1a; 同步操作&#xff1a; 在多任务、多通道或多设备系统中&#xff0c;可能需要不同的组件在同一时刻执行某些操作。通过将触…

redis相关知识记录

redis基本数据类型 Redis⽀持五种主要数据结构&#xff1a;字符串&#xff08;Strings&#xff09;、列表&#xff08;Lists&#xff09;、哈希表&#xff08;Hashes&#xff09;、集合&#xff08;Sets&#xff09;和有序集合&#xff08;Sorted Sets&#xff09;。这些数据结…

winform4

json using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; //导入json第三方库 使用nuget搜索 …

断电的固态硬盘数据能放多久?

近日收到一个网友的提问&#xff0c;在这里粗浅表达一下见解&#xff1a; “网传固态硬盘断电后数据只能放一年&#xff0c;一年之后就会损坏。但是我有一个固态硬盘已经放了五六年了&#xff08;上次通电还是在2018年左右&#xff0c;我读初中的时候&#xff09;&#xff0c;…

《长相思》第二季回归:好剧质量,永恒的王牌

在万千剧迷的翘首以盼中&#xff0c;《长相思》第二季终于携着前作的辉煌与期待&#xff0c;缓缓拉开了序幕。这部自播出以来便以其精湛的剧情、出色的演员阵容以及独到的宣传策略&#xff0c;赢得了广泛好评与持续关注。如今&#xff0c;第二季的回归&#xff0c;无疑再次证明…

Linux 初识

目录 ​编辑 1.Linux发展史 1.1UNIX发展历史 1.2Linux发展历史 2.Linux的开源属性 2.1 开源软件的定义 2.2 Linux的开源许可证 2.3 开源社区与协作 3.Linux的企业应用现状 3.1 服务器 3.1.1 Web服务器 3.1.2 数据库服务器 3.1.3 文件服务器 3.1.4 电子邮件服务器 …

某客户管理系统Oracle RAC节点异常重启问题详细分析记录

一、故障概述 某日10:58分左右客户管理系统数据库节点1所有实例异常重启&#xff0c;重启后业务恢复正常。经过分析发现&#xff0c;此次实例异常重启的是数据库节点1。 二、故障原因分析 1、数据库日志分析 从节点1的数据库日志来看&#xff0c;10:58:49的时候数据库进程开始…

新火种AI|微软和苹果放弃OpenAI董事会观察员席位

作者&#xff1a;一号 编辑&#xff1a;美美 微软苹果双双不做OpenAI“观察员”&#xff0c;OpenAI能更自由吗&#xff1f; 7月10消息&#xff0c;微软当地时间周一宣布将放弃在OpenAI董事会的观察员席位&#xff0c;他们称&#xff0c;OpenAI在过去八个月中取得了“重大进展…

国内的几款强大的智能—AI语言模型

AI 绘图 链接&#xff1a;点我进入 1、国内百度研发的&#xff0c;文心一言&#xff1a; https://yiyan.baidu.com/welcome 大家如果像我的界面一样有【开始体验】就是可以使用的&#xff0c;否则就是说明在等待中&#xff01; 优点&#xff1a;会画画&#xff0c;暂无次数限…

回归树模型

目录 一、回归树模型vs决策树模型&#xff1a;二、回归树模型的叶结点&#xff1a;三、如何决定每个非叶结点上的特征类型&#xff1a; 本文只介绍回归树模型与决策树模型的区别。如需了解完整的理论&#xff0c;请看链接&#xff1a;决策树模型笔记 一、回归树模型vs决策树模…

Linux设备驱动的并发控制

一、概述 Linux设备驱动中必须解决的一个问题就是多个进程对共享资源(如全局变量、静态变量、硬件资源等)的并发访问&#xff0c;会导致竟态&#xff0c;如可能会出现以下情况&#xff1a;导致执行单元C独处的数据不符合预期 导致竟态发生有如下几种情况&#xff1a; 对称多处…

int类型变量表示范围的计算原理

文章目录 1. 了解2. 为什么通常情况下int类型整数的取值范围是-2147483648 ~ 21474836473. int类型究竟占几个字节4. 推荐 1. 了解 通常情况下int类型变量占4个字节&#xff0c;1个字节有8位&#xff0c;每位都有0和1两种状态&#xff0c;所以int类型变量一共可以表示 2^32 种状…

【全面介绍Oracle】

🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步! 目录 🎥前言🎥基本概念和安装🎥SQL语言🎥PL/SQL编程🎥数据库…

【计算机组成原理 | 第三篇】各个硬件的组成部分

前言&#xff1a; 在前面的文章中&#xff0c;我们介绍了计算机架构的基本组成。可以知道计算机的基本架构由“存储器”&#xff0c;“运算器”&#xff0c;“控制器”&#xff0c;“输入设备”&#xff0c;“输出设备”这五部分组成。 在这片文章中&#xff0c;我们来深入的了…

【斯坦福因果推断课程全集】2_无混淆和倾向分1

目录 Beyond a single randomized controlled trial Aggregating difference-in-means estimators Continuous X and the propensity score 随机试验的一个最简单的扩展是无约束下的干预效果估计。从定性上讲&#xff0c;当我们想估计一种并非随机的治疗效果&#xff0c;但一…

数列分块<2>

本期是数列分块入门<2>。该系列的所有题目来自hzwer在LOJ上提供的数列分块入门系列。 Blog:http://hzwer.com/8053.html sto hzwer orz %%% [转载] 好像上面的链接↑打不开&#xff0c;放一个转载:https://www.cnblogs.…

tensorflow卷积层操作

全连接NN&#xff1a; 每个神经元与前后相邻层的每一个神经元都有全连接关系。输入是特征&#xff0c;输出为预测结果。 参数个数(前层*后层后层&#xff09; 实际应用时&#xff0c;会先对原始图像进行特征提取&#xff0c;再把提取到的特征送给全连接网络 会先进行若干层提…

C嘎嘎类与对象上篇

类的定义 1. class为定义类的关键字&#xff0c;Stack为类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后⾯分号不能省略 。类体中内容称为类的成员&#xff1a;类中的变量称为类的属性或成员变量; 类中的函数称为类的⽅法或者成员函数。 2. C中struct也可以…

【C语言】C语言-学生籍贯信息记录系统(源码+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…