文章目录
- 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
10void 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
16void 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
15void 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
7typedef struct { uint8_t port_num; uint16_t len; void* address; } USART_COB;
(2)存储队列定义和初始化
1
2
3QueueHandle_t USART_RxPort; //全局变量 USART_RxPort = xQueueCreate(4,sizeof(USART_COB));
(3)定义中断回调函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14uint32_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
12void 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
3SemaphoreHandle_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
22void 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
16void 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
21void 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
13void 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
11void 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
19void 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
22void 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
19void 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内容请搜索靠谱客的其他文章。
发表评论 取消回复