当前位置: 代码迷 >> 综合 >> FreeRTOS--队列
  详细解决方案

FreeRTOS--队列

热度:57   发布时间:2023-11-25 14:35:35.0

在讲队列前,先思考一下这个问题:
下面这个程序,如果用RTOS实现会出问题吗?

c:
int a = 0;
void fun_a(){
    a++;
}
void fun_b(){
    a++;
}
int main(){
    while(1){
    fun_a();fun_b();}}
RTOS:
int a = 0;
void fun_a(){
    a++;
}
void fun_b(){
    a++;
}
int main()
{
    creat_Task(fun_a);creat_Task(fun_b);}

对RTOS代码分析:
我们的期望是运行一次fun_a后a++运行1次,运行1次fun_b后a++运行1次,a = 2
fun_a和fun_b的a++:
1)读a: R0寄存器,读RAM的a的地址,得到a的值
2)修改:R0 自加 1
3)写a:R0寄存器,写RAM的a的地址,修改a的值
接下来模拟一下 RTOS运行
t0:
fun_a:
1)R0寄存器,读RAM的a的地址,得到a的值,R0 = 0,
2)此时到下一个tick,保存现场R0 = 0.
t1:
fun_b:
1)读a: R0寄存器,读RAM的a的地址,得到a的值,R0 = 0;
2)修改:R0 自加 1,R0 += 1,R0 = 1;
3)写a:R0寄存器,写RAM的a的地址,修改a的值;a = 1
t2:
fun_a:
1)恢复现场 R0 = 0
2)修改:R0 自加 1 R0 += 1,R0 = 1;
3)写a:R0寄存器,写RAM的a的地址,修改a的值;a = 1

由上面可知,不符合我们的期望,运行结果为 a = 1
根本问题在于,多个任务一起修改没有互斥机制保护数据。

队列提供了解决的方法,使用QueueSend可以将任务的tick中断关闭,实现裸机运行,修改完数据后再打开中断

接下来再举个栗子

void fun_a(){
    while(1){
    ...达成某条件后flag = 1;...}
}
void fun_b(){
    ...if(flag = 1){
    }...
}

如果运行100w次就要判断100w次太过于浪费CPU

void fun_a(){
    while(1){
    ...达成某条件后写队列:{
    1)写Data2)唤醒Queue.list里的任务,并将DelayList里的任务放进ReadyList}...}
}
void fun_b(){
    ...读队列:{
    1)有Data,返回做事2)无Data,休眠:a.将该任务放进DelayList链表b.将该任务插入Queue.List队列}...
}

在这里插入图片描述
fun_a可以全速运行
fun_b可以不浪费CPU资源

通过链表队列实现唤醒休眠

环形缓冲区

在这里插入图片描述
在这里插入图片描述
这里很简单,就直接贴一下韦老师的图了

读队列

a.关中断
b.
有数据:
1)copy数据
2)唤醒Queue.list里的任务,移除Queue.list第一个任务
3)将DelayList里的任务放进ReadyList
无数据:
1.返回ERR
2.休眠:
1)将该任务放进DelayList链表
2)将该任务插入Queue.List队列

写队列

a.关中断
b.
有空间:
1)写数据
2)唤醒Queue.list里的任务,移除Queue.list第一个任务
3)将DelayList里的任务放进ReadyList
无空间:
1.返回ERR
2.休眠:
1)将该任务放进DelayList链表
2)将该任务插入Queue.List队列

超时唤醒

任务休眠,对于休眠的任务,每次tick中断都会累加计数,然后对DelayList的任务检查是否超时,超时则会移到ReadyList

  相关解决方案