我是靠谱客的博主 害怕篮球,这篇文章主要介绍FreeRTOS学习1.FreeRTOS的简介和定位2.FreeRTOS的主要内容3.FreeRTOS的常见用法4.FreeRTOS的注意事项,现在分享给大家,希望可以做个参考。

文章目录

  • 1.FreeRTOS的简介和定位
    • 定位
    • 配置
  • 2.FreeRTOS的主要内容
    • 延时
    • 队列
    • 信号量
    • 通知
  • 3.FreeRTOS的常见用法
  • 4.FreeRTOS的注意事项
    • 优先级
    • 内存大小
    • 初始化
    • 常见错误

1.FreeRTOS的简介和定位

定位

  • 嵌入式操作系统
    一个免费,轻量级的操作系统,可以使代码框架清晰,更具有层次感。
  • 任务调度器内核—双向链表
    链表内核使任务查询速度加快,使用上理解为队列的架构。
  • 任务操作和任务间通信方式多样
    挂起,延时,队列,信号量,通知…

配置

配置步骤

1.CubeMX的参数配置

2.任务创建

3.初始化及启动

  • 配置前首先需要将单片机的主定时器配置为普通定时器,即Timer1,Timer2…,(默认为Systick,CubeMX会警告)

1.CubeMX的配置

(1)选择接口标准
在这里插入图片描述
(2)配置任务最大优先级
在这里插入图片描述
(3)使能固定延时
在这里插入图片描述
2.任务创建
----以创建陀螺仪(IMU)任务为例

(1)定义变量及函数声明

复制代码
1
2
3
4
5
6
/* 任务句柄 */ TaskHandle_t DeviceIMU_Handle; /* 任务执行函数 */ void Device_IMU(void *arg);

(2)任务函数定义

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/** *@brief IMU任务 */ void Device_IMU(void *arg) { /* Cache for Task */ /* Pre-Load for task */ /* Infinite loop */ for(;;) { /* Code */ } }

(3)任务创建

复制代码
1
2
3
4
5
6
7
8
9
10
void Service_Devices_Init(void) { xTaskCreate(Device_IMU, /* 任务函数 */ "Dev.IMU", /* 任务名称 */ Large_Stack_Size, /* 堆栈大小 */ NULL, /* 任务参数 */ PriorityHigh, /* 优先级 */ &DeviceIMU_Handle); /* 任务句柄 */ }

3.启动任务调度器
(1)任务初始化

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 该任务为CubeMX自动生成,不需要用户创建,只要填充内容即可。 void StartDefaultTask(void const * argument) { /* USER CODE BEGIN StartDefaultTask */ /* Infinite loop */ for(;;) { /* 初始化任务 */ Task_Init(); /* 删除任务 */ vTaskDelete(defaultTaskHandle); } /* USER CODE END StartDefaultTask */ }

(2)启动任务调度器(自动生成)
在这里插入图片描述

2.FreeRTOS的主要内容

延时

(1)DelayUntil

  • 延时时间包括了任务执行时间,严格控制时序,但是要保证任务执行时间小于延时时间。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void DelayUntil_Task(void *arg) { /* Cache for Task */ TickType_t xLastWakeTime_t = xTaskGetTickCount(); TickType_t _xTicksToWait = pdMS_TO_TICKS(1); /* Pre-Load for task */ /* Infinite loop */ for(;;) { vTaskDelayUntil(&xLastWakeTime_t, _xTicksToWait); /* Code */ } }

(2)Delay

  • 延时时间不包括任务执行时间,任务执行结束后,经过设定的延时时间,再到下一个任务。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Delay_Task(void *arg) { /* Cache for Task */ TickType_t _xTicksToWait = pdMS_TO_TICKS(1); /* Pre-Load for task */ /* Infinite loop */ for(;;) { vTaskDelay(_xTicksToWait); /* Code */ } }

队列

----以串口接收为例

(1)结构体定义

复制代码
1
2
3
4
5
6
7
typedef struct { uint8_t port_num; uint16_t len; void* address; } USART_COB;

(2)存储队列定义和初始化

复制代码
1
2
3
QueueHandle_t USART_RxPort; //全局变量 USART_RxPort = xQueueCreate(4,sizeof(USART_COB));

(3)定义中断回调函数

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
uint32_t User_UART1_RxCpltCallback(uint8_t* Recv_Data, uint16_t ReceiveLen) { static USART_COB Usart_RxCOB; //Send To UART Receive Queue if(USART_RxPort != NULL) { Usart_RxCOB.port_num = 1; Usart_RxCOB.len = ReceiveLen; Usart_RxCOB.address = Recv_Data; xQueueSendFromISR(USART_RxPort,&Usart_RxCOB,0); } return 0; }

(4)定义处理函数

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
void Task_UsartRecieve(void *arg) { USART_COB Usart_RxCOB; for(;;) { /* Usart Recevice Port */ if(xQueueReceive(USART_RxPort,&Usart_RxCOB,portMAX_DELAY) == pdPASS) { /* Code */ } }

信号量

----以二值信号量为例

(1)信号量定义和初始化

复制代码
1
2
3
SemaphoreHandle_t SemaphoreHandle; //全局变量 SemaphoreHandle = xSemaphoreCreateBinary();

(2)定义信号量发送函数

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void SemaphoreTx_Task(void *arg) { /* Cache for Task */ TickType_t xLastWakeTime_t = xTaskGetTickCount(); TickType_t _xTicksToWait = pdMS_TO_TICKS(1); /* Pre-Load for task */ /* Infinite loop */ for(;;) { /* 数据更新 */ data.Update(); /* 发送二值信号量,表示数据更新 */ xSemaphoreGive(SemaphoreHandle); /* Pass control to the next task */ vTaskDelayUntil(&xLastWakeTime_t,_xTicksToWait); } }

(3)定义信号量接收函数

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void SemaphoreRx_Task(void *arg) { /* 任务等待变量 */ BaseType_t wait = pdFALSE; /* Infinite loop */ for(;;) { /* 等待数据更新 */ wait = xSemaphoreTake(SemaphoreHandle, portMAX_DELAY); if(wait == pdTRUE) { /* Code */ } }

通知

(1)定义通知发送函数

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void NotifyTx_Task(void *arg) { /* Cache for Task */ TickType_t xLastWakeTime_t = xTaskGetTickCount(); TickType_t _xTicksToWait = pdMS_TO_TICKS(1); /* Pre-Load for task */ /* Infinite loop */ for(;;) { /* Code */ /* 发送通知 */ xTaskNotifyGive(NotifyRx_Handle); /* Pass control to the next task */ vTaskDelayUntil(&xLastWakeTime_t,_xTicksToWait); } }

(2)定义通知接收函数

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
void NotifyRx_Task(void *arg) { /* Cache for Task */ /* Pre-Load for task */ /* Infinite loop */ for(;;) { /* 等待通知 */ ulTaskNotifyTake(pdTRUE,portMAX_DELAY); /* Code */ } }

3.FreeRTOS的常见用法

实战:电机驱动
1.电机以固定频率f1反馈数据给单片机。
2.单片机解算数据包,更新电机数据。
3.单片机以固定频率f2计算控制输出,并发送给电机。

实现流程图
在这里插入图片描述
实现源码(只给出框架部分)

(1)定义中断回调函数

复制代码
1
2
3
4
5
6
7
8
9
10
11
void CAN1_CallBack(CAN_RxBuffer *CAN_RxMessage) { static CAN_COB CAN_RxCOB; /* 数据标准化处理 */ Convert_Data(CAN_RxMessage,&CAN_RxCOB); /* 发送数据到队列中 */ if(CAN1_RxPort != NULL) xQueueSendFromISR(CAN1_RxPort,&CAN_RxCOB,0); }

(2)定义接收处理任务

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void Task_CAN1Receive(void *arg) { /* Cache for Task */ CAN_COB CAN_RxMsg; /* Pre-Load for task */ /* Infinite loop */ for(;;) { /* 等待CAN数据包更新 */ if(xQueueReceive(CAN1_RxPort,&CAN_RxMsg,portMAX_DELAY) == pdPASS) { /* 更新电机数据 */ Update_Motor_Data(&CAN_RxMsg); } } }

(3)定义控制任务

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void Task_GimabalCtrl(void *arg) { /* Cache for Task */ TickType_t xLastWakeTime_t = xTaskGetTickCount(); TickType_t _xTicksToWait = pdMS_TO_TICKS(1); CAN_COB CAN_TxMsg; /* Pre-Load for task */ /* Infinite loop */ for(;;) { /* 固定延时时间 */ vTaskDelayUntil(&xLastWakeTime_t, _xTicksToWait); /* 计算电机的控制输出 */ Motor_Ctrl(&CAN_TxMsg); /* 发送数据到发送队列 */ xQueueSend(can1_port, &CAN_TxMsg, 0); } }

(4)定义数据发送任务

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void Task_CAN1Transmit(void *arg) { /* Cache for Task */ CAN_COB CAN_TxMsg; /* Pre-Load for task */ /* Infinite loop */ for(;;) { /* 等待发送的数据包更新 */ if(xQueueReceive(CAN1_TxPort,&CAN_TxMsg,portMAX_DELAY) == pdPASS) { /* 发送数据给电机 */ CANx_SendData(&hcan1,CAN_TxMsg.ID,CAN_TxMsg.Data,CAN_TxMsg.DLC); } } }

4.FreeRTOS的注意事项

优先级

原则:
1.轮询任务优先级低,等待任务优先级高。
2.轮询任务中,需严格控制时序的任务优先级相对较高。

内存大小

原则:
1.评估任务所需的内存量来分配内存。

内存过小会进硬件中断。
内存过大会浪费内存,且增加不必要的任务执行时间。

2.对大部分情况而言,内存宜大不宜小。

初始化

原则:
1.通知接收任务要先于通知发送任务创建。

初始化方式:
1.在任务调度器开启前创建任务: 初始化函数放在main函数MX_FREERTOS_Init()前面。
2.在任务调度器开启后创建任务: 初始化函数放在 StartDefaultTask任务中。

常见错误

硬件错误
1.检查内存分配大小
2.检查是否使用了未初始化的外设

某个任务不执行
1.检查优先级配置
2.检查内存分配大小

最后

以上就是害怕篮球最近收集整理的关于FreeRTOS学习1.FreeRTOS的简介和定位2.FreeRTOS的主要内容3.FreeRTOS的常见用法4.FreeRTOS的注意事项的全部内容,更多相关FreeRTOS学习1.FreeRTOS内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(91)

评论列表共有 0 条评论

立即
投稿
返回
顶部