/*
源代码以及其他一切形式的知识转述均出自百问网课程,仅供参考,请勿用作商业用途。
【FreeRTOS入门与工程实践 --由浅入深带你学习FreeRTOS(FreeRTOS教程 基于STM32,以实际项目为导向)】 https://www.bilibili.com/video/BV1Jw411i7Fz/?p=8&share_source=copy_web&vd_source=bab35cd72a6b7a3ffd3c77e664d802f1
*/
第15讲 内存管理
内存管理即是如何使用FreeRTOS中的堆。对于堆中的内存,CubeMX做出如下图管理,首先内存分配既可以是静态的也可以是动态的,其次堆的总容量大约为3072字节,最后使用的内存调度算法是heap_4 。
不同内存调度算法对比:
一般使用heap_4,有多块内存使用heap_5。有关heap的函数,大家可以参考韦老师编撰的手册。
第16讲 创建任务_声光色影
这一讲的目的是分别用静态、动态的方式创建多个任务。
一个任务至少需要三个要素:函数、栈空间和任务优先级。当它被挂起之后我们又应该如何寻找它呢?FreeRTOS对于被被挂起的任务提供了查询链表,找到头节点之后就可以顺藤摸瓜,这个链表中存放着任务结构体(TCB:TaskControlBlock)。
主要学习任务就是学会使用这两个API,xTaskCreate与xTaskCreateStatic的用法。我按照老师思路编程并且改掉了所有的error和warning,不然后面越积越多。贴一下代码:
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : freertos.c
* Description : Code for freertos applications
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "Music.h"
#include "driver_led.h"
#include "driver_lcd.h"
#include "driver_mpu6050.h"
#include "driver_timer.h"
#include "driver_ds18b20.h"
#include "driver_dht11.h"
#include "driver_active_buzzer.h"
#include "driver_passive_buzzer.h"
#include "driver_color_led.h"
#include "driver_ir_receiver.h"
#include "driver_ir_sender.h"
#include "driver_light_sensor.h"
#include "driver_ir_obstacle.h"
#include "driver_ultrasonic_sr04.h"
#include "driver_spiflash_w25q64.h"
#include "driver_rotary_encoder.h"
#include "driver_motor.h"
#include "driver_key.h"
#include "driver_uart.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
StackType_t g_pucStackofLightTask[128];
StaticTask_t g_TCBofLightTask;
StackType_t g_pucStackofColourTask[128];
StaticTask_t g_TCBofColourTask;
/* USER CODE END Variables */
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
/* USER CODE END FunctionPrototypes */
void StartDefaultTask(void *argument);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
/**
* @brief FreeRTOS initialization
* @param None
* @retval None
*/
void MX_FREERTOS_Init(void) {
/* USER CODE BEGIN Init */
TaskHandle_t xSoundTaskHandle;
BaseType_t ret1;
TaskHandle_t ret2,ret3;
/* USER CODE END Init */
/* USER CODE BEGIN RTOS_MUTEX */
/* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Create the thread(s) */
/* creation of defaultTask */
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/*创建任务:声*/
do{
ret1=xTaskCreate(PlayMusic,"SoundTask",128,NULL,osPriorityNormal,&xSoundTaskHandle);
}while(ret1==pdFAIL);
/*创建任务:光*/
do{
ret2=xTaskCreateStatic(Led_Test,"lightTask",128,NULL,osPriorityNormal,g_pucStackofLightTask,&g_TCBofLightTask);
}while(ret2==pdFAIL);
/*创建任务:色*/
do{
ret3=xTaskCreateStatic(ColorLED_Test,"ColorLEDTask",128,NULL,osPriorityNormal,g_pucStackofColourTask,&g_TCBofColourTask);
}while(ret3==pdFAIL);
/* USER CODE END RTOS_THREADS */
/* USER CODE BEGIN RTOS_EVENTS */
/* add events, ... */
/* USER CODE END RTOS_EVENTS */
}
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* @brief Function implementing the defaultTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
LCD_Init();
LCD_Clear();
for(;;)
{
LCD_Test();
osDelay(5);
}
/* USER CODE END StartDefaultTask */
}
/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
/* USER CODE END Application */
仅供大家参考吧,实际上用do while循环判断是不合理的。
第17讲 创建任务_估算栈的大小
栈里面保存着返回地址(LR寄存器等,用来存储函数的调用关系等)、局部变量、现场(任务发生切换时保留16✖4字节)。调用程度越深,需要的栈就越大。
第18讲 创建任务_使用任务参数
这节课的任务是用同一个函数互斥地使用访问OLED屏幕。
首先为了完成需求,我们抽象出一个打印函数,需要传递的参数有x、y坐标轴以及打印内容。
然后设置一个全局变量保护LCD屏幕的访求权限,这实际上是一种不可靠的方式。这节课老师留下了两个疑问,怎么样才能可靠地互斥使用LCD以及为什么单片机先执行了最后创建地任务三。
贴一下我改的0错误0警告代码:
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : freertos.c
* Description : Code for freertos applications
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "Music.h"
#include "driver_led.h"
#include "driver_lcd.h"
#include "driver_mpu6050.h"
#include "driver_timer.h"
#include "driver_ds18b20.h"
#include "driver_dht11.h"
#include "driver_active_buzzer.h"
#include "driver_passive_buzzer.h"
#include "driver_color_led.h"
#include "driver_ir_receiver.h"
#include "driver_ir_sender.h"
#include "driver_light_sensor.h"
#include "driver_ir_obstacle.h"
#include "driver_ultrasonic_sr04.h"
#include "driver_spiflash_w25q64.h"
#include "driver_rotary_encoder.h"
#include "driver_motor.h"
#include "driver_key.h"
#include "driver_uart.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
/* USER CODE END Variables */
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
struct TaskPrintInfo{
uint8_t x;
uint8_t y;
char name[16];
};
struct TaskPrintInfo g_Task1Info={0,0,"Task1"};
struct TaskPrintInfo g_Task2Info={0,3,"Task2"};
struct TaskPrintInfo g_Task3Info={0,6,"Task3"};
int g_LCDCanUse=1;
void LcdPrintfTask(void * params)
{
struct TaskPrintInfo *pInfo=params;
uint32_t count=0;
int len;
for(;;)
{
if (g_LCDCanUse)
{
g_LCDCanUse = 0;
len = LCD_PrintString(pInfo->x, pInfo->y, pInfo->name);
len += LCD_PrintString(len, pInfo->y, ":");
LCD_PrintSignedVal(len, pInfo->y, count++);
g_LCDCanUse = 1;
}
mdelay(500);
}
}
/* USER CODE END FunctionPrototypes */
void StartDefaultTask(void *argument);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
/**
* @brief FreeRTOS initialization
* @param None
* @retval None
*/
void MX_FREERTOS_Init(void) {
/* USER CODE BEGIN Init */
LCD_Init();
LCD_Clear();
/* USER CODE END Init */
/* USER CODE BEGIN RTOS_MUTEX */
/* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Create the thread(s) */
/* creation of defaultTask */
// defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/*使用同一个函数常见不同的任务*/
xTaskCreate(LcdPrintfTask,"Task1",128,&g_Task1Info,osPriorityNormal,NULL);
xTaskCreate(LcdPrintfTask,"Task2",128,&g_Task2Info,osPriorityNormal,NULL);
xTaskCreate(LcdPrintfTask,"Task3",128,&g_Task3Info,osPriorityNormal,NULL);
/* USER CODE END RTOS_THREADS */
/* USER CODE BEGIN RTOS_EVENTS */
/* add events, ... */
/* USER CODE END RTOS_EVENTS */
}
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* @brief Function implementing the defaultTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
LCD_Init();
LCD_Clear();
for(;;)
{
osDelay(1);
}
/* USER CODE END StartDefaultTask */
}
/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
/* USER CODE END Application */
第19讲 删除任务_用遥控器控制音乐
/*我的遥控器电池没电了,所以后面和遥控器有关的代码我只能说没有逻辑错误。*/
这一讲要掌握的API是:
void vTaskDelete( TaskHandle_t xTaskToDelete );
其中的参数pvTaskCode是指一个任务句柄,使用 xTaskCreate 创建任务时可以得到一个句柄。
第20讲 优先级与阻塞_改善播放状态
在FreeRTOS中,vTaskDelay函数是用于使当前任务延迟一段相对时间的方法。这是实时操作系统中任务调度的一个重要部分,它允许任务暂停执行一段时间,以便其他任务可以执行。
函数的原型如下:
void vTaskDelay( TickType_t xTicksToDelay );
其中,xTicksToDelay
参数表示任务需要延迟的时间量,以时钟节拍(tick)为单位。这个时间是从当前时间开始计算的。举个例子,如果你设置xTicksToDelay
为100,那么当前任务将会被延迟100个时钟节拍。在这段时间内,该任务不会执行任何代码,而其他任务则可以在这段时间内执行。当100个时钟节拍过去后,该任务将自动从延返回到其被vTaskDelay
调用之前的位置,并继续执行。请注意,任务的延迟时间是以FreeRTOS的时钟节拍为单位的,而不是以通常的秒或毫秒为单位。你可以使用FreeRTOS的xPortSysTickHandler
函数获取当前的时钟节拍值。这个函数是线程/任务调度的基础,它允许你控制任务的执行顺序和时间,从而实现复杂的实时应用程序。
第21讲 任务状态_改进播放控制
这一讲我们的任务是解析任务管理的内部机制(链表、优先级管理、任务的挂起与恢复),实验现象上是为孤泳者(big胆!)的播放增加暂停与恢复的功能。
一个任务可能有这么几种状态:挂起(suspended)、阻塞(blocked)、运行(running)、就绪(ready)态。如下图所示:
一个任务被创建之后默认处于Ready状态,进入运行态时可能被带有阻塞作用的API(例如vTaskDelay)带入Blocked态,然后等待预设时间的发生回到就绪态。想要进入挂起态的方法只有一种,就是调用vTaskSuspend(既可以是自身调用,也可能是处于running态的任务调用)。
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : freertos.c
* Description : Code for freertos applications
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "Music.h"
#include "driver_led.h"
#include "driver_lcd.h"
#include "driver_mpu6050.h"
#include "driver_timer.h"
#include "driver_ds18b20.h"
#include "driver_dht11.h"
#include "driver_active_buzzer.h"
#include "driver_passive_buzzer.h"
#include "driver_color_led.h"
#include "driver_ir_receiver.h"
#include "driver_ir_sender.h"
#include "driver_light_sensor.h"
#include "driver_ir_obstacle.h"
#include "driver_ultrasonic_sr04.h"
#include "driver_spiflash_w25q64.h"
#include "driver_rotary_encoder.h"
#include "driver_motor.h"
#include "driver_key.h"
#include "driver_uart.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
StackType_t g_pucStackofLightTask[128];
StaticTask_t g_TCBofLightTask;
StackType_t g_pucStackofColourTask[128];
StaticTask_t g_TCBofColourTask;
/* USER CODE END Variables */
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
/* USER CODE END FunctionPrototypes */
void StartDefaultTask(void *argument);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
/**
* @brief FreeRTOS initialization
* @param None
* @retval None
*/
void MX_FREERTOS_Init(void) {
/* USER CODE BEGIN Init */
TaskHandle_t xSoundTaskHandle;
BaseType_t ret1;
TaskHandle_t ret2,ret3;
/* USER CODE END Init */
/* USER CODE BEGIN RTOS_MUTEX */
/* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Create the thread(s) */
/* creation of defaultTask */
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/*创建任务:声*/
do{
ret1=xTaskCreate(PlayMusic,"SoundTask",128,NULL,osPriorityNormal,&xSoundTaskHandle);
}while(ret1==pdFAIL);
/*创建任务:光*/
do{
ret2=xTaskCreateStatic(Led_Test,"lightTask",128,NULL,osPriorityNormal,g_pucStackofLightTask,&g_TCBofLightTask);
}while(ret2==pdFAIL);
/*创建任务:色*/
do{
ret3=xTaskCreateStatic(ColorLED_Test,"ColorLEDTask",128,NULL,osPriorityNormal,g_pucStackofColourTask,&g_TCBofColourTask);
}while(ret3==pdFAIL);
/* USER CODE END RTOS_THREADS */
/* USER CODE BEGIN RTOS_EVENTS */
/* add events, ... */
/* USER CODE END RTOS_EVENTS */
}
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* @brief Function implementing the defaultTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
uint8_t dev, data;
BaseType_t ret;
TaskHandle_t xSoundTaskHandle=NULL;
int bRunning;
LCD_Init();
LCD_Clear();
IRReceiver_Init();
LCD_PrintString(0,0,"Waiting control");
for(;;)
{
/*读取红外遥控器键值*/
if(IRReceiver_Read(&dev,&data)==0)
{
if(data==0xa8)/*play按键*/
{
/*创建播放音乐的任务*/
if(xSoundTaskHandle==NULL)
{
LCD_ClearLine(0,0);
LCD_PrintString(0,0,"Create Task");
do{
xTaskCreate(PlayMusic,"SoundTask",128,NULL,osPriorityNormal+1,&xSoundTaskHandle);
}while(ret==pdFAIL);
bRunning=1;
}else{
/*要么suspemd、要么resume*/
if(bRunning==1)
{
vTaskSuspend(xSoundTaskHandle);
LCD_ClearLine(0,0);
LCD_PrintString(0,0,"Suspend Task");
PassiveBuzzer_Control(0);//停止蜂鸣器
bRunning=0;
}else
{
vTaskResume(xSoundTaskHandle);
LCD_ClearLine(0,0);
LCD_PrintString(0,0,"Resume Task");
bRunning=1;
}
}
}else if(data==0xa2)/*power按键*/
{
/*删除播放音乐的任务*/
if(xSoundTaskHandle!=NULL)
{
LCD_ClearLine(0,0);
LCD_PrintString(0,0,"Delete Task");
vTaskDelete(xSoundTaskHandle);
PassiveBuzzer_Control(0);//停止蜂鸣器
xSoundTaskHandle=NULL;
}
}
}
}
/* USER CODE END StartDefaultTask */
}
/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
/* USER CODE END Application */