FreeRTOS学习笔记

裸机开发

  • 裸机程序的设计模式可以分为:轮询、前后台、定时器驱动、基于状态机。
  • 前面三种方法都无法解决一个问题:假设有A、B两个都很耗时的函数,无法降低它们相互之间的影响。第4种方法可以解决这个问题,但是实践起来有难度。

RTOS开发

创建多个任务,音乐播放,灯,屏幕显示等

实现功能:

  • 当监测到遥控器的播放按键被按下后,创建音乐播放任务。
  • 当监测到遥控器的Power按键被按下后,删除音乐播放任务

提问:频繁地创建、删除任务,好吗?有什么坏处?如何解决?

  • 频繁创建可能导致内存被频繁动态分配,产生内存碎片,浪费资源
  • 新增加一个暂停Suspended功能,通过提高音乐播放的优先级,使用vTaskDelay进行延时。
    • 多任务不会卡顿,优先处理,可以暂停和开始
    • vTaskDelay为阻塞Blocked状态,不会一直占用cpu

任务管理与调度

  • FreeRTOS任务状态转换图:

在这里插入图片描述

  • 重点是:优先级、链表的管理、任务切换、Tick中断

    • 同优先级的任务轮流运行
    • 高优先级的任务先运行
  • 任务以链表的形式保存任务,共56个,默认等级为24,空闲任务优先级为0。

    • 高优先级的任务未执行完,低优先级的任务无法执行
    • 一旦高优先级的任务就绪,马上执行
    • 最高优先级的任务有多个,轮流运行
      在这里插入图片描述
  • 具体调度顺序为:从上往下,遍历第一个非空链表,取出任务执行。

    1. 首先指针指向任务3,执行任务3,指针移到下一位任务1;
    2. Tick中断,再次从ReadyList从上往下遍历找到第一个非空链表,此时指针在任务1,执行任务1;
    3. Tick中断,再次从ReadyList从上往下遍历找到优先级24非空链表,此时指针在任务2,执行任务2;
    4. 。。。
      任务调度顺序
  • 空闲任务(Idle任务)的作用:

    • 释放被删除的任务的内存(做垃圾回收,释放内存等)
    • 一个良好的程序,它的任务都是事件驱动的。平时大部分时间处于阻塞状态。有可能我们自己创建的所有任务都无法执行,但是调度器必须能找到一个可以运行的任务。所以,我们要提供空闲任务。在使用vTaskStartScheduler0函数来创建、启动调度器时,这个函数内部会创建空闲任务:
    • 空闲任务优先级为0:它不能阻碍用户任务运行
      空闲任务要么处于就绪态,要么处于运行态,永远不会阻塞
    • 空闲任务的优先级为0,这意味着一旦某个用户的任务变为就绪态,那么空闲任务马上被切换出去,让这个用户任务运行。在这种情况下,我们说用户任务“抢占”(pre·empt)了空闲任务,这是由调度器实现的。

参考学习来源

游戏项目

  • 功能:红外遥控左右控制挡球板,接球。
  • 核心:如何绘制各类图标
  • 改进:

在这里插入图片描述

任务之间如何传输数据

在这里插入图片描述

队列的操作

  1. 创建队列
  2. 读队列
  3. 写队列

改进、队列实验 多设备游戏

实验目的

  • 使用红外遥控器、旋转编码器玩游戏。

共两个任务:
在这里插入图片描述
在这里插入图片描述

  1. game1_draw为球的任务(不用改)
  2. platform为挡球板任务:主要修改读取红外遥控部分,将读环形缓冲区改进为读队列的框架。
  • 环形缓冲区无阻塞,效率低。一直循环消耗cpu资源,导致其他任务如音乐播放会卡顿。
  • 队列的方式如果里面没有数据会阻塞,其他任务可以去做别的事情,提高效率。

实现方案一:

  1. 游戏任务: 读取队列A获得控制信息,用来控制游戏。
  2. 红外遥控器驱动: 在中断函数里解析出按键后,写队列A

改进任务思路这里是引用

  1. 旋转编码器:
    • 它的中断函数里解析出旋转编码器的状态,写队列B;
    • 它的任务函数里,读取队列B,构造好数据后写队列A

    改进的思路:在这里插入图片描述

实现方案一改进:

  1. 不足: 假设有2个输入设备:红外遥控器、旋转编码器,它们的驱动程序应该专注于“产生硬件数据”,不应该跟“业务有任何联系”。比如:红外遥控器驱动程序里,它只应该把键值记录下来、写入某个队列,它不应该把键值转换为游戏的控制键。在红外遥控器的驱动程序里,不应该有游戏相关的代码,这样,切换使用场景时,这个驱动程序还可以继续使用。
  • 把红外遥控器的按键转换为游戏的控制键,应该在游戏的任务里实现。像旋转编码器那样创建任务,驱动->队列->任务。
  • 但是,假设再增加MPU6050设备,又得增加任务,而任务会使用栈,这会消耗很多内存在这里插入图片描述
  1. 改进: 要支持多个输入设备时,我们需要实现一个“InputTask”,它读取各个设备的队列,得到数据后再分别转换为游戏的控制键。

InputTask如何及时读取到多个队列的数据?
要使用队列集。队列集的本质也是队列,只不过里面存放的是“队列句柄”。使用过程如下:

  • a. 创建队列A,它的长度是n1
  • b. 创建队列B,它的长度是n2
  • c. 创建队列集S,它的长度是“n1+n2”
  • d. 把队列A、B加入队列集S
  • e. 这样,写队列A的时候,会顺便把队列A的句柄写入队列集S
  • f. 这样,写队列B的时候,会顺便把队列B的句柄写入队列集S
  • g. InputTask先读取队列集S,它的返回值是一个队列句柄,这样就可以知道哪个队列有有数据了 然后InputTask再读取这个队列句柄得到数据。

框架思路: 程序分层设计,下面那层跟任务没有关系,​并且可以容易拓展添加其他硬件(写相关驱动->写队列->添加到队列集,上层任务InputTask添加相应操作)。
在这里插入图片描述

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值