LEDs状态灯任务(线程)设计(基于RTOS)
我们学习MCU开发,大部分都是面向过程的开发,但实际项目一般要求我们有面向对象(模块化)的方式来开发。
刚学习C语言开发的朋友,应该常常听说面向对象,但实际对于面向对象开发可能还是不太了解。
为了初学者进一步理解,本文结合实际项目(LEDs状态灯)给大家带来比较基础的模块化设计。
对于MCU的开发,大部分人都还是习惯性用的C语言,原因之一在于C语言具有高效的特点。
可以了解一下,许多操作系统的内核使用的编程语言,其实都用到了C语言,这就是C语言的优点,也是C语言这么多年不衰败的原因。
说回来,对于MCU的开发,除了C语言,当然还可以其它语言,像C++有许多人就用上了。
C++语言本身就是面向对象的开发语言,定义一个类,可以包含许多成员。站在C语言的角度,可以理解成定义一个结构体,里面包含许多数据类型。 如下面要说的LEDs数据结构体:
typedef struct
{
uint8_t Mode; //模式(常灭 常亮 闪烁)
uint8_t Status; //当前状态(灭 亮)
uint16_t OffTimes; //灭时间(xLED_COUNT_PERIOD毫秒)
uint16_t OnTimes; //亮时间
uint16_t Counter; //计数(计时)
void (*OffFun)(void); //灭函数接口
void (*OnFun)(void); //亮函数接口
}LED_TypeDef;
可以看到,结构体里面包含整型变量,函数指针。
补充,指针函数与函数指针的区别:
1、指针函数:本质是一个函数,函数返回类型是某一类型的指针。
格式: 类型标识符 *函数名(参数表)
如:int *f(x,y);
2、函数指针:本质是一个指针,指向函数的指针变量。
格式:类型说明符 (*函数名)(参数)
如:int (*f) (int x);
假如一个系统中做的事情非常多,比如:采集两个增量式编码器、两个绝对值编码器、控制4个电机、控制多个LED状态灯、通信收发数据,采集温度、湿度、超声波雷达等···许多模块,那么问题来了,这么多模块,你的软件该如何设计?
答案就是需要模块化设计。
模块化设计,包含底层驱动,中间接口函数,应用程序等。对于MCU级别的开发,为了规范,建议大家从底层设计到应用层设计都按照模块化的方式来设计。
简单的来说,模块化就是源文件、数据结构、变量、函数命名等需要按照模块的方式来设计。比如LEDs状态灯:IO口的定义用LED(模块),文件名用led,变量、函数名抬头用LED,定义一个LED数据结构(模块的数据结构)等。
模块化的设计优点在于:便于源代码管理、移植、理解等等。(相信有许多自己写的代码,放一段时间之后,重新再次阅读,可能看了半天都不明白源代码的意思。)
为方便大家理解,拿一个简单的LEDs状态灯的实例来分析。里面使用到了RTOS简单系统延时(本文不讲述关于RTOS的知识)。文末提供例程下载地址。
1.描述
绿、黄、红三个(可以自己添加许多个)LED状态灯,可独自实现常灭、常亮、闪烁三个模式。
闪烁:灭、亮时间可设置(提供函数接口修改)。
在一个线程(任务)里面执行。
3个LED不同亮灭时间效果:
2.数据结构
typedef struct
{
uint8_t Mode; //模式(常灭 常亮 闪烁)
uint8_t Status; //当前状态(灭 亮)
uint16_t OffTimes; //灭时间(xLED_COUNT_PERIOD毫秒)
uint16_t OnTimes; //亮时间
uint16_t Counter; //计数(计时)
void (*OffFun)(void); //灭函数接口
void (*OnFun)(void); //亮函数接口
}LED_TypeDef;
为了方便理解,只使用一个数据结构(实际大的项目可能有多个包含,类似C++继承关系)。
3.底层LED函数接口
void LEDGreen_Off(void);
void LEDGreen_On(void);
void LEDYellow_Off(void);
void LEDYellow_On(void);
void LEDRed_Off(void);
void LEDRed_On(void);
主要就是亮灭函数接口,这里提供三组LED(根据需求可添加)。
4.定义局部变量
static LED_TypeDef sLEDG_Structure; //绿灯
static LED_TypeDef sLEDY_Structure; //黄灯
static LED_TypeDef sLEDR_Structure; //红灯
5.初始化变量
/************************************************
函数名称 : LED_Data_Init
功 能 : 数据初始化
参 数 : 无
返 回 值 : 无
作 者 : strongerHuang
*************************************************/
static void LED_Data_Init(void)
{
/* 绿灯 */
sLEDG_Structure.Mode = LED_MODE_FLICKER; //初始化为闪烁
sLEDG_Structure.OffTimes = 50; //灭亮时间
sLEDG_Structure.OnTimes = 50;
sLEDG_Structure.Counter = 0; //计数归零
sLEDG_Structure.OffFun = LEDGreen_Off; //灭函数接口
sLEDG_Structure.OnFun = LEDGreen_On; //亮函数接口
/* 黄灯 */
sLEDY_Structure.Mode = LED_MODE_ON; //初始化为常亮
sLEDY_Structure.OffTimes = 0; //灭亮时间
sLEDY_Structure.OnTimes = 0;
sLEDY_Structure.Counter = 0; //计数归零
sLEDY_Structure.OffFun = LEDYellow_Off; //灭函数接口
sLEDY_Structure.OnFun = LEDYellow_On; //亮函数接口
/* 红灯 */
sLEDR_Structure.Mode = LED_MODE_ON; //初始化为常亮
sLEDR_Structure.OffTimes = 0; //灭亮时间
sLEDR_Structure.OnTimes = 0;
sLEDR_Structure.Counter = 0; //计数归零
sLEDR_Structure.OffFun = LEDRed_Off; //灭函数接口
sLEDR_Structure.OnFun = LEDRed_On; //亮函数接口
/* 对外调用接口(例子) */
LEDG_Set(LED_MODE_FLICKER, 50, 50);
LEDY_Set(LED_MODE_FLICKER, 50, 10);
LEDR_Set(LED_MODE_FLICKER, 20, 30);
}
这里重要的就是要初始化灭亮函数接口。
6.LEDs任务(线程)
/************************************************
函数名称 : LED_Task_Proc
功 能 : 状态灯任务程序
参 数 : pvParameters --- 可选参数
返 回 值 : 无
作 者 : strongerHuang
*************************************************/
static void LED_Task_Proc(void *pvParameters)
{
static TickType_t xLastWakeTime;
xLastWakeTime = xTaskGetTickCount(); for(;;)
{
//间隔固定计数周期(采样时间)
vTaskDelayUntil(&xLastWakeTime, LED_COUNT_PERIOD); /* 浏览LEDs */
LED_Scan(&sLEDG_Structure);
LED_Scan(&sLEDY_Structure);
LED_Scan(&sLEDR_Structure);
}
}
流程图:
7.LED浏览(或者说处理)
/************************************************
函数名称 : LED_Scan
功 能 : 状态灯扫描(修改状态)
参 数 : LED_Struct --- 状态灯数据结构
返 回 值 : 无
作 者 : strongerHuang
*************************************************/
static void LED_Scan(LED_TypeDef *LED_Struct)
{
/* 1.常灭模式 */
if(LED_MODE_OFF == LED_Struct->Mode)
{
LED_Struct->Status = LED_STATUS_OFF; //状态置为"灭"
LED_Struct->OffFun(); //灭灯
}
/* 2.常亮模式 */
else if(LED_MODE_ON == LED_Struct->Mode)
{
LED_Struct->Status = LED_STATUS_ON; //状态置为"亮"
LED_Struct->OnFun(); //亮灯
}
/* 3.闪烁模式 */
else if(LED_MODE_FLICKER == LED_Struct->Mode)
{
/* 在灭的状态 */
if(LED_STATUS_OFF == LED_Struct->Status)
{
LED_Struct->Counter++; if(LED_Struct->Counter >= LED_Struct->OffTimes)
{
LED_Struct->Counter = 0;
LED_Struct->OnFun(); //亮灯
LED_Struct->Status = LED_STATUS_ON; //状态置为"亮"
}
}
/* 在亮的状态 */
else if(LED_STATUS_ON == LED_Struct->Status)
{
LED_Struct->Counter++; if(LED_Struct->Counter >= LED_Struct->OnTimes)
{
LED_Struct->Counter = 0;
LED_Struct->OffFun(); //灭灯
LED_Struct->Status = LED_STATUS_OFF; //状态置为"灭"
}
}
else
{
LED_Struct->Status = LED_STATUS_OFF; //状态置为"灭"
}
}
/* 4.未知模式 */
else
{
LED_Struct->Status = LED_STATUS_OFF; //状态置为"灭"
LED_Struct->OffFun(); //灭灯
}
}
源代码工程下载地址:
链接:https://pan.baidu.com/s/1cNtwJDdCOfyYwsvKCclFyw
密码:kk74
推荐阅读:
置顶公众号,不怕找不到我;
记得给我点赞哦!
微信搜索“strongerHuang” 或者扫描下面二维码、关注,在我的底部菜单查看更多精彩内容!
长按识别二维码 关注