编辑
2024-03-27
学习记录
0
请注意,本文编写于 442 天前,最后修改于 428 天前,其中某些信息可能已经过时。

目录

STM32F1 + RTOS + HAL
1.堆和栈
2.任务的三要素:
3.创建任务:
4.创建不同的任务(传入参数)调用同一个函数;
5.任务的删除:用遥控器控制音乐;
6.增加任务优先级,将演示函数换成vTaskDelay即可改变音乐播放效果;
7.任务的状态:运行、就绪、阻塞、暂停
8.调度(每个tick后遍历ReadList,发起一次调度):
9.任务必须处于死循环中
10.任务如何退出:
11.为了避免空闲任务得不到机会执行,要有良好的编程习惯:
12.vTaskDelay和vTaskDelayUntil区别
13.同步与互斥方法:
14.遥控器和编码器多个设备玩游戏;
15.队列集,存放每个队列的句柄,目的便于业务和硬件解耦;
16.MPU6050玩游戏
17.三个任务读一个队列
18.信号量本质
19.信号量涉及的函数:
20.优先级反转:
21.优先级反转问题解决
22.事件组
23.事件组使用:
24.任务通知:
25.软件定时器:
26.两套函数的区别
27.资源管理
28.优化系统:
29.统计任务信息
30.统计CPU占比

STM32F1 + RTOS + HAL

1.堆和栈

  1. 堆是一块空闲的内存空间,用,户自己管理使用malloc取出内存,用完后free释放;
  2. 栈也是一块内存空间,CPU的SP寄存器指向它,可以用于函数调用、局部变量、多任务系统里保存现场;

2.任务的三要素:

  1. 函数
  2. 优先级

3.创建任务:

使用xTaskCreate和xTaskCreateStatic创建任务;

4.创建不同的任务(传入参数)调用同一个函数;

5.任务的删除:用遥控器控制音乐;

6.增加任务优先级,将演示函数换成vTaskDelay即可改变音乐播放效果;

7.任务的状态:运行、就绪、阻塞、暂停

image.png

8.调度(每个tick后遍历ReadList,发起一次调度):

  1. 相同优先级的任务轮流运行;
  2. 最高优先级的任务先运行:
    1. 如果为执行完放弃运行状态的话,低优先级任务永远无法运行;
    2. 一旦高优先级任务就绪,马上执行;
    3. 如果最高优先级任务有多,会轮流执行;

9.任务必须处于死循环中

如果一个任务不是死循环的话,执行完后会进入preTaskExitError()函数,该函数关闭中断进入死循环,这时所有任务都无法执行。

10.任务如何退出:

  1. 自杀:vTaskDelete(NULL);空闲任务收尸;
  2. 他杀:vTaskDelete(handle);杀人犯收尸(释放TCB、栈);

11.为了避免空闲任务得不到机会执行,要有良好的编程习惯:

  1. 事件驱动(有了某个事件触发后才运行,其他事件处于阻塞状态);
  2. 延时函数不要使用死循环;

12.vTaskDelay和vTaskDelayUntil区别

vTaskDelay阻塞函数和vTaskDelayUntil阻塞函数,前者绝对延时,后者在一个任务里相对延时(任务+延时固定等于设置的时间);

13.同步与互斥方法:

  1. 使用全局变量同步(需要使用volatile修饰),死等效率低;
  2. 全局变量保护共享资源,大概率没问题,但理论上运行上千万次后可能出现问题,可以使用关中断开中断的方式保证全局变量的值修改过程中不被打断,但效率还是不够高因为A运行过程中虽然B不能运行不能造成bug,但tick中断时总会到B任务里去判断一下,B没事就来插一脚,效率不高;
  3. 两个任务如果不考虑阻塞唤醒和效率,就可以使用环形缓冲区来实现资源的同步访问,一个只操作写,一个只操作读,不会产生资源竞争。
  4. 队列中,数据读写的本质是环形缓冲区的基础上增加了互斥措施、阻塞-唤机制;

14.遥控器和编码器多个设备玩游戏;

15.队列集,存放每个队列的句柄,目的便于业务和硬件解耦;

16.MPU6050玩游戏

创建初始化、获取数据,写队列函数,然后将改队列加入队列集,统一处理三个队列;

17.三个任务读一个队列

如果三个任务都要读一个队列,可以在写队列是进行内容分发(写多个队列),写那些队列可以由应用程序调用驱动程序里的一个注册函数(自己创建一个数组存队列句柄);

18.信号量本质

也是一个队列,只不过不涉及数据的真正传输,只涉及队列里数据的个数;

19.信号量涉及的函数:

  1. 创建信号量
    或者xSemaphoreCreateCountion;
  2. 获得信号量
    (handle,超时时间);
  3. 释放信号量
    (handle);

20.优先级反转:

低优先级任务运行,高优先级任务不运行,可以是因为高优先级任务在等待信号量;

21.优先级反转问题解决

互斥量解决优先级反转的问题;也可以解决全局变量作为资源保护的方法存在的问题;

22.事件组

高八位不用,其余位每位表示一个事件,由程序决定; 还有一个链表,里面存放等待的事件(等待什么事件、等待事件的关系:或还是与);

23.事件组使用:

定义事件组; 写事件; 等待事件;

24.任务通知:

队列/信号量/事件组是都不知道是哪个任务提供的数据的,也不知道要唤醒什么任务; 任务通知是在中断或者某个任务中明确知道要通知哪个任务;

25.软件定时器:

  1. 定时器就是一个结构体,定义了一次性还是周期性、周期是多少、执行的函数、参数、链表
  2. 每个tick中断都会判断软件定时器链表的第一个有没有到时间,如果有则执行函数;

26.两套函数的区别

一个在中断中使用,一个在普通任务中使用,因为中断要求快速执行完,不会阻塞,只会记录是否有更高优先级的任务要执行而不切换,执行完中断处理函数后再进行切换;

27.资源管理

谁和我抢,我就毙掉谁;中断来了屏蔽中断,其他任务来了关闭任务调度;

28.优化系统:

精准的调整栈空间:栈由堆得来的,栈初始化时写入0xa5a5a5a5,函数调用过程中栈指针从上往下移动,会写入不同的数值,大概率与初始值不同,所以从栈最低端往上遍历值为0xa5a5a5a5的栈,栈的大小就是空闲的栈。

29.统计任务信息

可以在钩子函数中调用函数一次获得所有任务的栈空闲大小、优先级、任务序号等信息

30.统计CPU占比

通过统计任务的时间在每个tick中占比累加;

本文作者:zzw

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 License 许可协议。转载请注明出处!