C++抽象化封装FreeRTOS,一种多人并行开发方案1
前置要求:FreeRTOS C++环境开发单片机
兼容标准库,HAL库
此文章介绍抽象化FreeRTOS模板的简单使用
git仓库:git clone https://github.com/12379biu/C-FreeRTOS.git
目录
freeRTOS自带隔离属性,调用任务调度器osKernelStart()后会自动启动所有已创建的任务函数,利用这个属性,可以做到多人文件隔离,并行开发项目,大大提高项目的简洁性和可维护性。
加上c++对c的兼容性,项目成员在使用时写纯c语言即可运行,无需c++门槛
这里先介绍应用部分,对源码感兴趣的话请看系列的文章2和3部分
代码使用
首先,我们先对比一下没有使用freeRTOS的任务创建,我们以cubemx生成的默认任务为例,首先创建任务定义好一些任务参数,然后调用创建任务的API,最后实现任务。我学习时,老师创建任务更是分散,还有创建启动任务的任务,写一个启动此任务的函数并在主函数调用,啧啧啧。
对比:使用模板前
//1.定义任务
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
//2.创建任务
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
//3.实现任务
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
for(;;)
{
osDelay(1);
}
/* USER CODE END StartDefaultTask */
}
咳咳有点跑题了,使用freeRTOS你肯定不只创建一个任务,你要创建多个任务,那么到时候代码就不是这样排好的结构了。可能是下面这样的结构,虽然也是大致有序,但找起参数来总有种两眼一黑的感觉......
//1.任务属性
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for maintask */
osThreadId_t maintaskHandle;
const osThreadAttr_t maintask_attributes = {
.name = "maintask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityLow,
};
/* Definitions for uarttask */
osThreadId_t uarttaskHandle;
const osThreadAttr_t uarttask_attributes = {
.name = "uarttask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityLow,
};
/* Definitions for oledtask */
osThreadId_t oledtaskHandle;
const osThreadAttr_t oledtask_attributes = {
.name = "oledtask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityLow,
};
//2.任务创建
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
/* creation of maintask */
maintaskHandle = osThreadNew(Main, NULL, &maintask_attributes);
/* creation of uarttask */
uarttaskHandle = osThreadNew(Uart, NULL, &uarttask_attributes);
/* creation of oledtask */
oledtaskHandle = osThreadNew(Oled, NULL, &oledtask_attributes);
//3.任务创建
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
for(;;)
{
osDelay(1);
}
/* USER CODE END StartDefaultTask */
}
void Main(void *argument)
{
/* USER CODE BEGIN Main */
/* Infinite loop */
for(;;)
{
osDelay(1);
}
/* USER CODE END Main */
}
void Uart(void *argument)
{
/* USER CODE BEGIN Uart */
/* Infinite loop */
for(;;)
{
osDelay(1);
}
/* USER CODE END Uart */
}
void Oled(void *argument)
{
/* USER CODE BEGIN Oled */
/* Infinite loop */
for(;;)
{
osDelay(1);
}
/* USER CODE END Oled */
}
对比:使用模板后
这里你需要知道c++的类class,只需要知道最基础的属性就足够了,两分钟就能学会,可以看我的博客c++ Class的简单入门https://blog.csdn.net/weixin_71306050/article/details/151288644?fromshare=blogdetail&sharetype=blogdetail&sharerId=151288644&sharerefer=PC&sharesource=weixin_71306050&sharefrom=from_link
这里我们创建一个类,继承,虚函数什么的都不用管,只是使用的话也不需要知道是什么。
我们需要创建一个类,就叫它Main_Task(名字随意)吧。
#include "my_task.h"//将我们的文件导入
class Main_Task:public TaskBase{
public:
Main_Task():TaskBase("main_task",32,1){};
virtual void task(void*arg)
{
while(1)
{
LL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
};
Main_Task maintask;
1.就像创建一个结构体那样struct Main_Task---> class Main_Task,然后在TaskBase()括号里填写参数
任务的函数名称,任务的字大小,任务的优先级。
2.在函数task()中填写我们的业务逻辑,比如用LL库点个灯。
3.最后,创建出这个类就像结构体struct Main_Task maintask-->Main_Task maintask
好了,任务创建完成。
回顾一下我们需要修改的地方

然后在主函数,如果是CubeMX,那么什么都不用改,直接启动
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM7_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Init scheduler */
osKernelInitialize(); /* Call init function for freertos objects (in cmsis_os2.c) */
MX_FREERTOS_Init();
/* Start scheduler */
osKernelStart();
.......
如果你是自己手写,直接掉官方API就好了,完全隔离,任务直接就启动了
int main(void)
{
// 优先级分组4,因为 FreeRTOS 只支持抢占优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
// 启动任务调度器
vTaskStartScheduler();
while (1);
}
如此,一个任务就创建好了,好了,用同样的方法创建4个任务做一下对比
创建一个任务一路复制粘贴下去就好了,这可比CubeMX快多了,而且信息高度集中,参数就在里面。
class Default_Task:public TaskBase{
public:
Default_Task():TaskBase("default_Task",32,1){};
virtual void task(void*arg)
{
while(1)
{
vTaskDelay(pdMS_TO_TICKS(100));
}
}
};
Default_Task defaultTask;
/*Task------------------------------------------------------*/
class Main_Task:public TaskBase{
public:
Main_Task():TaskBase("main_task",128,1){};
virtual void task(void*arg)
{
while(1)
{
vTaskDelay(pdMS_TO_TICKS(100));
}
}
};
Main_Task maintask;
/*Task------------------------------------------------------*/
class Uart_Task:public TaskBase{
public:
Uart_Task():TaskBase("uart_Task",128,1){};
virtual void task(void*arg)
{
while(1)
{
vTaskDelay(pdMS_TO_TICKS(100));
}
}
};
Uart_Task uartTask;
/*Task------------------------------------------------------*/
class Oled_Task:public TaskBase{
public:
Oled_Task():TaskBase("oled_Task",128,1){};
virtual void task(void*arg)
{
while(1)
{
vTaskDelay(pdMS_TO_TICKS(100));
}
}
};
Oled_Task oledTask;
/*--------------------------------------------------------*/
先介绍到这里,下一期文章2介绍一些此模板API的使用
更多推荐



所有评论(0)