我是靠谱客的博主 害怕篮球,最近开发中收集的这篇文章主要介绍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)定义变量及函数声明

/* 任务句柄 */
TaskHandle_t DeviceIMU_Handle;

/* 任务执行函数 */
void Device_IMU(void *arg);

(2)任务函数定义

/**
 *@brief IMU任务
 */ 
void Device_IMU(void *arg)
{
  /* Cache for Task */

  /* Pre-Load for task */
  
  /* Infinite loop */
  for(;;)
  {
	/* Code */
  }
}

(3)任务创建

void Service_Devices_Init(void)
{
xTaskCreate(Device_IMU, /* 任务函数 */
"Dev.IMU", 	        	/* 任务名称 */             
Large_Stack_Size, 		/* 堆栈大小 */
NULL, 	         		/* 任务参数 */
PriorityHigh,        	/* 优先级 */
&DeviceIMU_Handle);   	/* 任务句柄 */
}

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

// 该任务为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

  • 延时时间包括了任务执行时间,严格控制时序,但是要保证任务执行时间小于延时时间。
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

  • 延时时间不包括任务执行时间,任务执行结束后,经过设定的延时时间,再到下一个任务。
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)结构体定义

typedef struct
{
  uint8_t port_num;
  uint16_t len;
  void* address;
} USART_COB;

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

QueueHandle_t  USART_RxPort; //全局变量
USART_RxPort = xQueueCreate(4,sizeof(USART_COB));

(3)定义中断回调函数

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)定义处理函数

void Task_UsartRecieve(void *arg)
{
   USART_COB Usart_RxCOB;
   for(;;)
  {
    /* Usart Recevice Port */
    if(xQueueReceive(USART_RxPort,&Usart_RxCOB,portMAX_DELAY) == pdPASS) 
     {
 		/* Code */
     }
}

信号量

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

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

SemaphoreHandle_t SemaphoreHandle; //全局变量
SemaphoreHandle = xSemaphoreCreateBinary();

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

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)定义信号量接收函数

void SemaphoreRx_Task(void *arg)
{
  /* 任务等待变量 */
  BaseType_t wait = pdFALSE;
		
  /* Infinite loop */
  for(;;)
  {
    /* 等待数据更新 */
    wait = xSemaphoreTake(SemaphoreHandle, portMAX_DELAY); 
    if(wait == pdTRUE)
    {
      /* Code */		
    }
}

通知

(1)定义通知发送函数

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)定义通知接收函数

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)定义中断回调函数

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)定义接收处理任务

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)定义控制任务

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)定义数据发送任务

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的简介和定位2.FreeRTOS的主要内容3.FreeRTOS的常见用法4.FreeRTOS的注意事项所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部