这个是全网最详细的STM32项目教学视频。
第一篇在这里:
视频在这里
**V3:HAL库开发、手把手教学下面功能:PID速度控制、PID循迹、PID跟随、遥控、避障、PID角度控制、openmv视觉控制、电磁循迹、FreeRTOS、K210视觉智能车(更新中)、K230视觉智能车(更新中)、MSPM0G3507视觉智能车(更新中)**
21.1-RTOS和任务的一些概念
多任务运行基本机制(重点理解 这是RTOS精髓)
理解RTOS的调度算法是如何安排调度的
21.1.0-任务里面写什么
在FreeRTOS中一个任务就是一个某种功能的函数,任务函数内部的一般是一个死循环结构。任何时候不允许从任务函数退出。
可以把RTOS的任务理解成是裸机里面main的while循环,一个任务就是一个裸机里面main的while循环,他们在适合的时机切换执行。
// 温度传感器任务
void vTemperatureSensorTask(void *pvParameters) {
for (;;) {
/*************下面是温度控制****************/
//读取传感器数值
readTemperatureSensor();
/*************上面是温度控制****************/
vTaskDelay(1000); // 1秒
}
}
21.1.0-多个任务如何在单核MCU"同时运行"
PPT 78页到115页是动画讲解说明如何实现"分时复用"
如果某个任务延时时间达到,则称为这个任务进入就绪状态。
如果任务获得CPU使用权,则称之为进入运行态。
21.1.1-如果两个任务同时要运行 应该运行那个?
假设某一个时刻按键扫描任务和温度传感器任务的阻塞延时时间同时达到,CPU会选择那个任务先执行?
- 优先级不同执行,优先级高的。
- 优先级相同,执行先创建的
使用下面的PPT图片讲解
因为温度传感器任务和按键扫描任务优先级一样,所以CPU会根据任务创建先后顺序执行会先执行温度传感器任务!
21.1.1-如果有任务十分耗时且不释放CPU怎么办
PPT从119页到136页
这里我们假设如果在传感器读取任务中,如果传感器读取函数一直超时阻塞获得传感器数据,那么将无法执行VtaskDelay()函数,任务就一直占用CPU 无法让出CPU
其他任务将迟迟得不到执行,我们称之为**“任务饥饿”**
如何解决这个问题那? 既然任务不让出CPU,我们就每隔一段时间检测,是否有同优先级或者高优先级任务就绪,然后进行调度,这就是FreeRTOS 的时间片轮转调度机制
21.1.1-如何让重要任务获得更多CPU使用权
写过按键检测扫描的同学,应该都知道按键程序要求一定的实时性和及时性,程序设计时要尽力保证按键程序的快速相应。
所以我们可以把前面设计程序里面的按键扫描任务的优先级提高
这样CPU就会在两个同时执行需要执行的任务中,先执行按键扫描任务(因为任务优先级高的)—这就叫做基于优先级的抢占式任务调度方法。
!!!总结:前面我们介绍了时间片轮转调度机制和基于优先级的抢占式任务调度方法,其实FreeRTOS调度方式:采用使用时间片的抢占式任务调度方式
下面这段是刚刚演示的伪代码。
#include "FreeRTOS.h"
//...省略头文件
// 温度传感器任务
void vTemperatureSensorTask(void *pvParameters) {
for (;;) {
/*************下面是温度控制****************/
//读取传感器数值
readTemperatureSensor();
/*************上面是温度控制****************/
vTaskDelay(1000); // 1秒
}
}
// 温度控制任务
void vTemperatureControllerTask(void *pvParameters) {
for (;;) {
/*************下面是温度控制****************/
//根据阈值 控制加热器
if (temperature > 50)
printf("Cooling system ON.n");
else
printf("Cooling system OFF.n");
/*************上面是温度控制****************/
vTaskDelay(2000); // 2秒
}
}
// 按键扫描任务
void vButtonScanTask(void *pvParameters) {
for (;;) {
/*************下面是按键扫描内容****************/
//通过GPIO输入查询 按键是否按下
state = HAL_GPIO_ReadPin(BUTTON_GPIO_PORT, BUTTON_GPIO_PIN);
/*************上面是按键扫描内容****************/
vTaskDelay(100); // 100毫秒
}
}
int main(void) {
// 创建任务
xTaskCreate(vTemperatureSensorTask, "Temp Sensor", 1000, NULL, 1, NULL);
xTaskCreate(vTemperatureControllerTask, "Temp Controller", 1000, NULL, 1, NULL);
xTaskCreate(vButtonScanTask, "Button Scan", 1000, NULL, 1, NULL);
// 启动调度器
vTaskStartScheduler();
// 如果调度器启动失败,则进入死循环
for (;;) {}
return 0;
}