[FreeRTOS learning - common function records]

Follow Wei Dongshan's FreeRTOS teaching materials learning record
FreeRTOS all project code links (updating)
https://gitee.com/chenshao777/free-rtos_-study


[FreeRTOS Learning - Section Record]


Commonly used functions: create tasks, create queues, write queues, read queues, create semaphores, etc.
Some attention to details

Introduction to common functions

1. Create a task function

BaseType_t xTaskCreate(	TaskFunction_t pxTaskCode,
							const char * const pcName,
							const uint16_t usStackDepth,
							void * const pvParameters,
							UBaseType_t uxPriority,
							TaskHandle_t * const pxCreatedTask )

BaseType_t is actually a long type. The meaning of the parameters of the xTaskCreate function is pxTaskCode: task function (function pointer) pcName: descriptive task name usStackDepth: stack depth pvParameters: task priority pxCreatedTask: task handle






2. Task scheduling function

vTaskStartScheduler();          //开启任务调度

Usually written at the end of the main function, it is used to start the task scheduler.
The task scheduler will start idle tasks and initialize timer services, etc.


3. Relative delay function

void vTaskDelay( const TickType_t xTicksToDelay )

TickType_t is actually a macro of uint32_t.
If the timing is 10ms, you can write it like this

void Task(void *pvParameters)
{
    
    
	const TickType_t xDelay_10ms = 10 / portTICK_PERIOD_MS;
	for(;;)
	{
    
    
		// ......
		// 该任务执行到下面这句,会阻塞10ms
		vTaskDelay(xDelay_10ms);
	}
}

portTICK_PERIOD_MS represents the time of a time slice, in milliseconds
portTICK_PERIOD_MS is defined in portmacro.h

#define portTICK_PERIOD_MS			( ( TickType_t ) 1000 / configTICK_RATE_HZ )

configTICK_RATE_HZ is defined in FreeRTOSConfig.h, which indicates the system tick frequency of RTOS, that is, the number of operations in 1 second, here is 1000 times, that is, 1ms

//RTOS系统节拍中断的频率。即一秒中断的次数,每次中断RTOS都会进行任务调度
#define configTICK_RATE_HZ						  (( TickType_t )1000)

So the Tick of the RTOS here is 1ms


4. Absolute delay function

/* 获取当前系统时间 */
void Task(void *pvParameters)
{
    
    
	/* 获取当前系统时间 */
	u32 lastWakeTime = xTaskGetTickCount();  
	const TickType_t xDelayUntil_10ms = 10 / portTICK_PERIOD_MS;
	for(;;)
	{
    
    
		// ......
		// 该任务会以每10ms运行一次的频率运行
		vTaskDelayUntil(&lastWakeTime, xDelayUntil_10ms); //100Hz(10ms控制一次)
	}
}

The difference between vTaskDelayUntil and vTaskDelay

  • Relative delay means that each delay starts from the task execution function vTaskDelay() and ends at the time specified by the delay;
  • Absolute delay means that the task that calls the vTaskDelayUntil() function is executed every specified time, that is, it runs at a fixed frequency.

Example: create multiple tasks

#include "stm32f10x.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "SysTick.h"

/*
 * 环境检测
*/
void Huanjing_Task(void *pvParameters)
{
    
    
	const TickType_t xDelay_10ms = 10 / portTICK_PERIOD_MS;
	for(;;)
	{
    
    
		/* 循环执行任务 */
		// ......
		// ......
		
		vTaskDelay(xDelay_10ms);  //阻塞10ms
	}
}

/*
 * LED闪烁,表示系统正在运行
*/
void LED_Task(void *pvParameters)
{
    
    
	const TickType_t xDelay_1000ms = 1000 / portTICK_PERIOD_MS;
	for(;;)
	{
    
    
		/* LED灯翻转 */
		GPIOC->ODR ^= (1<<13);
		vTaskDelay(xDelay_1000ms);  //阻塞1000ms
	}
}

/*
 * 处理UWB数据
*/
void LED_Task(void *pvParameters)
{
    
    
	const TickType_t xDelay_10ms = 10 / portTICK_PERIOD_MS;
	for(;;)
	{
    
    
		/* 处理UWB数据 */
		// ......
		// ......
		vTaskDelay(xDelay_10ms);  //阻塞10ms
	}
}

int main()
{
    
    
	systemInit();   //初始化各个模块
	
	// DHT11温湿度模块
	xTaskCreate(Huanjing_Task, "Huanjing_Task", 200, NULL, 2, NULL);
	
	// LED 显示系统正在运行 
	xTaskCreate(LED_Task, "LED_Task", 200, NULL, 1, NULL);
	
	// 处理UWB数据
	xTaskCreate(UWB_vSemphr_Task, "UWB_vSemphr_Task", 200, NULL, 3, NULL);
	
	vTaskStartScheduler();          //开启任务调度
}
  • LED_Task will cause the LED to blink at a certain frequency, with the lowest priority, and can only be executed during the blocking period of the other two tasks;
  • The Huanjing_Task task is responsible for detecting environmental data and can only be executed during the blocking period of the UWB_vSemphr_Task task;
  • UWB_vSemphr_Task has the highest priority, and will preempt other tasks and execute them after the delay ends

5. Queue creation function

xQueueCreate( const UBaseType_t uxQueueLength, 
			  const UBaseType_t uxItemSize )

The meaning of the parameters of the xQueueCreate function is
uxQueueLength: queue length
uxItemSize: the length of the queue data unit


Example:

/* 1. 创建队列返回句柄 */
QueueHandle_t Queue_t;

//......
//......

int main()
{
    
    
	//......
	
	/*  创建队列, 每个数据单元类型为 int */
	Queue_t = xQueueCreate(20, sizeof(int));
	if(Queue_t != NULL)
		printf("队列创建成功!\r\n");
		
	//......
}


5.1 Write queue function

// 写队列(写到队尾)
xQueueSendToBack( QueueHandle_t xQueue, 
				  const void * const pvItemToQueue, 
				  TickType_t xTicksToWait )

The meaning of the parameters of the xQueueSendToBack function is
xQueue: queue handle
pvItemToQueue: pointer to send data
xTicksToWait: blocking timeout


5.2 Read queue function

xQueueReceive( QueueHandle_t xQueue, 
			   void * const pvBuffer, 
			   TickType_t xTicksToWait )

The meaning of the parameters of the xQueueReceive function is
xQueue: queue handle
pvBuffer: pointer to receive data
xTicksToWait: blocking timeout


Example: write queue - read queue

#include "stm32f10x.h"
#include "led.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "SysTick.h"
#include "queue.h"
#include "string.h"

/* 创建队列返回句柄 */
QueueHandle_t Queue_t;

/*
  写队列
*/
void TaskSend(void *pvParameters)
{
    
    
	int param;
	BaseType_t status;
	/* 该任务被创建了两个实例,需将传递参数强转为 int 型 */
	param = (int)pvParameters;

	for(;;)
	{
    
    
		/* 写队列,参数:目标队列的句柄, 发送数据的指针, 阻塞超时时间*/
		status = xQueueSendToBack(Queue_t, &param, 0);
		
		/* 允许其它发送任务执行。 taskYIELD()通知调度器现在就切换到其它任务,而不必等到本任务的时间片耗尽 */ 
		taskYIELD(); 
		
		/* 不能使用该延时函数,否则当队列满后,只有第一个写任务可以得到调度,第二个写任务会被饿死 */
//		vTaskDelay(1); 
	}
}

/*
  读队列
*/
void TaskRead(void *pvParameters)
{
    
    
	int read_data;
	BaseType_t result;
	BaseType_t count;
	for(;;)
	{
    
    
		/* 查询队列中数据个数 */
		count = uxQueueMessagesWaiting(Queue_t);
		printf("c = %d\r\n", count);
		
		/* 读队列 */
		result = xQueueReceive(Queue_t, &read_data, 50);
		if(result == pdPASS)
			printf("Read:  %d\r\n", read_data);
		else
			printf("Read NULL\r\n");
	}
}

int main()
{
    
    
	SysTick_Init(72);
	USART1_Init(115200);
	printf("串口初始化成功!\r\n");
	
	/*  创建队列, 每个数据单元类型为 int */
	Queue_t = xQueueCreate(20, sizeof(int));
	if(Queue_t != NULL)
		printf("队列创建成功!\r\n");
	
	/* 创建三个任务写队列 */
	xTaskCreate(TaskSend, "taskSend1", 200, (void*)100, 1, NULL);
	xTaskCreate(TaskSend, "taskSend2", 200, (void*)110, 1, NULL);
	xTaskCreate(TaskSend, "taskSend3", 200, (void*)120, 1, NULL);
	
	/* 创建一个任务读队列 */
	xTaskCreate(TaskRead, "TaskRead", 200, NULL, 2, NULL);
	
	/* 启动调度器,任务开始执行 */
	vTaskStartScheduler();          //开启任务调度
}

PS: 1. The same task function can be reused, as long as the task name is different 2. taskYIELD(): When the task is finished running, it directly notifies the scheduler to switch to other tasks, without waiting for the time slice of this task to run out

6. Binary semaphore

vSemaphoreCreateBinary( QueueHandle_t xSemaphore )

xSemaphore : the created semaphore

Example:

QueueHandle_t xSemaphore;      // 定义信号量句柄

//......
//......

/* 初始化二值信号量 */
vSemaphoreCreateBinary(xSemaphore);  
/* 经过测试,初始化二值信号量后,默认信号量是满状态,可以先Take一下,把信号量清空 */
xSemaphoreTake(xSemaphore, 0);   

Get a binary semaphore

/* 获取信号量结果变量 */
BaseType_t result;  

//......
//......

/*
 * portMAX_DELAY:表示没有超时限制
 * 尝试获取信号量,如果没有获取到则进入阻塞态
 * 如果设置了超时时间,超时时间内获取到了信号量,则返回pdPASS,如果没有获取到,则返回pdFALSE
*/
result = xSemaphoreTake(xSemaphore, portMAX_DELAY);  
if(result == pdPASS)
{
    
    
		printf("读取到二值信号量\r\n");
}

6.1 The serial port interrupt adopts binary semaphore synchronization

A binary semaphore can occur on a particular interrupt, allowing the task to unblock

串口中给出二值信号量代码(中断中需要使用 xSemaphoreGiveFromISR 函数)

串口初始化时,要将抢占优先级设置成大于等于5,因为在串口中断里使用了FreeRTOS的函数操作

/*
	串口初始化时,要将抢占优先级设置成大于等于5,因为在串口中断里使用了FreeRTOS的操作
	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;//串口2中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=9;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;		//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化NVIC寄存器
*/

int USART2_IRQHandler(void)                	//串口2中断服务程序
{
    
    
	uint8_t r;
	BaseType_t xHigherPriorityTaskWoken;
	
	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)   //接收中断
	{
    
    
		USART_ClearFlag(USART2, USART_FLAG_RXNE);
		r = USART2->DR;        //读取接收到的数据
		
		//......
		//......
		
		xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken);  //给出二值信号量,解除UWB任务
		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的话进行一次任务切换
	}
}

Guess you like

Origin blog.csdn.net/HuangChen666/article/details/129938768