1月21:
学习的文档链接:
百问网《FreeRTOS入门与工程实践-基于STM32F103》教程-基于DShanMCU-103(STM32F103) | 百问网
一、对于单片机,他被称为SOC(System On Chip)
cpu:用来运行程序 Flash:用来保存程序 内存:ram
cpu在运行程序时要访问内存
所有的计算都在cpu中执行的
所以stm32的flash本质时rom,在系统初始化时会把flash中的一些值放入ram中
ram就充当内存,再配合flash和cpu完成程序运行
stm32中RAM地址是从0x2000 0000开始的,Flash地址是从0x8000 0000开始的
数据传输的三大要素:源,目的,长度
memcpy(源,目的,长度)
局部变量都保存在栈中,栈在ram中
1月22:
1、堆和栈
堆:是一块空闲的内存,你可以从这块内存中取出一部分,用完后再释放回去
栈:也是一块内存,cpu的sp寄存器指向它,它可以用于函数调用、局部变量、多任务系统里保护现场(是freertos基础)。每个任务都会有自己的栈。
2、
LR(存返回地址)
PC(存即将跳转的函数的地址)
在进行函数的嵌套调用时的三个问题(使用汇编码解读):
①LR被覆盖了怎么办:①使用堆栈的方式来实现保护LR不被破坏
②局部变量在栈中分配,如何分配
③为何每个rtos任务都有自己的栈
1月27:
②局部变量用栈保存,但有时编译器会给你优化,使它保存在了寄存器里面,不过你加上了volatile后就会避免优化,使它保存在栈里面了。
当你局部变量越来越多了的时候,它必定会在栈里给你分配空间。
2月16号:
③因为每个任务都有自己的调用关系,都有自己的局部变量,现场
2月27:
Heap_1到Heap_5一共有五种,只能选择使用其中的一种
大部分是使用Heap_4和Heap_5
P6:创建自己的freertos
选择TIM4做基准时钟
P16
P18:
(互斥问题)没有加延时函数时同时访问一个函数大概率会出现只有一个任务可以运行(普通方法)
P19:
频繁的创建、删除不好,会产生内存的碎片,后续可能就没法再创建任务了
删除任务后还需要进行一些任务的清除工作
P20:
两个步骤:1,提高优先级。2,把mdelay()替换为使用vTaskDelay()。
P21:
Ready/Running(就绪)(运行)
Blocked((阻塞状态)等待某些event)(调用阻塞函数进入阻塞状态如vTaskDelay)
Suspended(暂停)(要么自己调用暂停函数进入暂停状态(如xTaskSuspend),要么别人调用暂停函数(如xTaskSuspend)使它进入暂停状态)(恢复函数xTaskResume)
P22:
、
每次Tick中断都会从上到下遍历一遍链表找出一个任务运行
任务调用vTaskDelay()(延时)后会被放入DelayTaskList()
任务调用vTaskSuspend()(暂停)后会被放入
任务调用(恢复)后任务会被放入就绪链表
所以在调度(遍历就绪链表找到该执行的任务并执行,后把指针向下一级)之前会先判断DelayTaskList()中的任务是否可恢复,如果可恢复则会将其放回其原优先级链表
P23:
如果任务给的是有限循环,则任务会跳到错误处理函数,系统会死机。
因为任务不能使用有限循环,所以想结束任务(任务退出)循环只能删除
任务退出方法
例:
自杀(任务清除工作)
良好的编程习惯
1,事件驱动(比如我按下了某个按键之后,它才会做某些事情,没有得到按键他就会阻塞)
2,把mdelay()换成vTaskDelay(),避免系统进入死循环,让出cpu资源,使空闲任务可以执行,用于释放被删除任务的内存
P24:
xTaskDelayUntil()函数:
使用xTaskDelayUntil()函数,你要在前面获得他的起始时间
P25:
为什么g_calc_end改变了但是还是会一直卡在while()呢?
对于g_calc_end这个变量,因为编译器把它优化了,所以它一直读的是它存在寄存器的值(旧的值),我们要一直读它新的值(因为这个变量在其他函数里一直被修改),需要一直去读内存,所以为了避免优化,需要加上volatile
我们在处理同步任务时应该考虑的问题:让等待的任务阻塞,不要让他们参与cpu的调度
P26:
对于同时调用共享资源时
如果用这种全局变量来保护公共资源还是可能会出现问题
高效的运行方式
P27:
任务之间的通信:
怎么保证任务通信的结果是正确的
P29:
数据传输方法
P32:
中断中写队列不可阻塞(还有好多写函数,具体去看文档)
error:
1,在包含"include queue.h"之前必须先包含"include FreeRTOS.h"
2,右击文件弹出copy full path 可以获得文件的路径,然后在魔法棒中添加文件路径,这样可以解决路径问题。
P34:
如果你使用多个任务分别管理多个资源(底层驱动数据读取)会造成资源浪费
使用队列集来把多个队列联系在一起就可以使用一个任务,可以节省资源
整体框架:
良好的编程思维:
当你定义了一个static的全局变量时,如果你要在其他文件使用这个静态变量(根据static的规则是不能在其他文件引用这个全局变量)时你可以使用一个函数来封装它。
P39:
信号量的本质是队列,它是特殊的队列
如果有一个任务试图获得一个不可用(已经被占用)的信号量时,信号量会将其推进一个等待队列,然后让其睡眠。这时处理器能重获自由,从而去执行其他代码。当持有的信号量可用(被释放)后,处于等待队列中的那个任务将被唤醒,并获得该信号量。例如:当某个人到了门前(钥匙在门外,进去房间的人持有钥匙),此时房间(临界区)里没有人,于是他就进入房间并关上了门。最大的差异在于当另外一个人想进入房间,但无法进入时,这家伙不是在徘徊,而是把自己的名字写在一个列表中,然后去打盹。当里面的人离开房间(释放钥匙)时,就在门口查看一下列表。如果列表上有名字,他就对第一个名字仔细检查,并叫醒那个人让他进入房间
P40:
![](https://img-blog.csdnimg.cn/direct/3b334e32e09d4ad98cf24e3f56c7d902.png)
二进制信息量类似于互斥量
互斥信号量和二进制信号量的区别_二进制信号量和互斥信号量-CSDN博客
当一个想要获得信号量不成功,但它愿意等待,则他会被放入等待链表,获得信号量的优先级参考下图
在执行任务之前先获取信号量(Take),如果获得到了则执行下列任务,如果没有获得则不执行下列任务(进入阻塞)。
当然在执行完任务后(或者当前不需要再执行)需要释放信号量(Give)。
P41:优先级反转问题
关于任务反转的例子:
任务一先运行,任务二1s后运行,任务三2s后运行(任务2是一个不需要获得信号量就可以运行的任务,任务1,3需要)优先级任务一 < 任务二 < 任务三
任务2是一个不需要获得信号量就可以运行的任务,他阻塞了1,1 释放不了信号量,3就一直没法运行。
P42:使用互斥量来解决优先级反转的问题
互斥量(优先级继承,优先级恢复)是信号量的变种
记住:若有多个任务,其中1、2任务为互斥量触发类型,那么这两个任务的优先级将为1、2任务中最高优先级的优先级 ,这就是优先级继承。
解决方法:先提高1的优先级(继承3的优先级)使它的优先级大于2,这时3就可以在1(执行完任务,恢复优先级,释放完互斥量)后能够执行3
解释(如何用互斥量解决的):
使用互斥量把1,3两个任务设为互斥类型,当任务1运行时,1s后任务2运行,2s后任务3因为任务1未完成未释放信号量而不能运行。而任务1因为是和任务3为同一个互斥量触发类型,所以任务1继承了任务3的优先级并能优先与任务2运行,任务1运行完毕后释放互斥量,而任务3因为优先级大于任务二就先于任务二运行,当任务3运行完后任务2最后运行。