什么是FreeRTOS

本人大四就读于双非院校的物联网工程专业,想要做嵌入式软件工程师。基于身边小伙伴求职过程的信息共享,发现RTOS是公司喜欢提问的对象,作为嵌入式操作系统RTOS,在嵌入式板块占据着浓妆厚抹的一笔。这篇文章是我的处女作,也是我学习RTOS的过程,如果有错误的地方请多多指教。

既然做嵌入式,相信大家应该都很清楚离不开STM32,我们需要进行裸机开发。这时候可能大家会有点疑惑不是要介绍RTOS,怎么介绍裸机了,大家先不要急,我们本章目标主要有两点,第一个理解裸机程序设计模式,第二个了解多任务系统中程序设计的不同,内容包含RTOS的。

1. 裸机程序设计模式

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

我提供一个场景,假如有一位妈妈需要同时解决两个问题:给小孩喂饭、回复工作信息,场景如图所示。

1.1 轮询模式

//经典单片机程序,轮询
void main()
{
    while(1)
    {
        喂一口饭();
        回一个消息();
    }
}

里面一次调用两个函数,函数之间相互有影响,如果“喂一口饭”太花时间,就会导致迟迟无法“回一个信息”;如果“回一个消息”太花时间,就会导致迟迟“喂下一口饭”,孩子就会饿的哇哇哭!轮询模式编写程序看起来很简单,但是要求while循环里调用到的函数要执行的非常快,在复杂的场景里反而增加了编程难度。

1.2 前后台

前后台就是使用中断程序。假设收到同事的消息,电脑发出滴的一声,妈妈才需要去回消息。

//前后台程序
void main()
{
    while(1)
    {
        //后台程序
        喂一口饭();
    }
}

//前台程序
void 中断()
{
    回一个消息();
}

缺陷如果回一个消息太久就会导致“喂一口饭”迟迟无法进行,我们来改进一下

//前后台程序
void main()
{
    while(1)
    {
        //后台程序
        喂一口饭();
    }
}

//前台程序
void 滴_中断()
{
    回一个消息();
}

//前台程序
void 啊_中断()
{
    喂一口饭();
}

如果电脑的的一声,小孩的的声音没有同时、相近发出,那么两个中断函数之间不会相互影响,如果滴、啊同时发生,则会跟轮询一样的缺点,相互影响。

1.3 定时器驱动

定时器驱动模式,是前后台模式的一种,可以按照不同的频率执行各种函数。比如每隔2分钟给宝宝喂一口饭,每隔5分钟回同事消息。那么我们就启动一个定时器吧,让它每1分钟就产生一个中断,让中断函数在合适的时间调用对应函数。(我写的是伪代码,代码也都很简单的,大家静下心都能看懂的)

//定时器驱动
void main()
{
    while(1)
    {
        //后台程序
    }
}

//前台程序:每一分钟触发一次中断
void 定时器_中断()
{
    static int count = 0;
    count++;    //加1代表过了一分钟
    if(count % 2 == 0)//这里就是判断是过了2分钟还是5分钟
    {
        喂一口饭();
    }
    else if(count % 5 == 0)
    {
        回消息();
    }
}

这种模式适合周期性的函数,并且每一个函数执行的时间不能超过一个定时器周期。如果“喂一口饭”很花时间,那就会影响“回同事消息”,反之亦然。这种场景下程序遭遇到了轮询一样的缺点:函数之间相互影响。

1.4 基于状态机

那怎么解决函数之间相互影响的问题呢?使用状态机可以解决这个缺点

//状态机
void main()
{
    while (1)
    {
        喂一口饭();
        回一个消息();
    }
}

main函数中还是使用轮询模式依次调用2个函数,关键在于这2两个函数的内部实现:使用状态机,每次只执行一个状态的代码,减少每次执行的时间。

void 喂一口饭(void)
{
    static int status = 0;
    switch (status)
    {
    case 0:
        /* 舀饭 */
        /*进入下一个状态*/
        status++;
        break;
    
    case 1:
        /*喂饭*/
        /*进入下一个状态*/
        status++;
        break;

    case 2:
        /*舀菜*/
        /*进入下一个状态*/
        status++;
        break;

    case 3:
        /*喂菜*/
        /*进入下一个状态*/
        status++;
        break;
    }
}

void 回一个消息(void)
{
    static int status = 0;
    switch (status)
    {
    case 0:
        /* 查看信息 */
        /*进入下一个状态*/
        status++;
        break;
    
    case 1:
        /*打字*/
        /*进入下一个状态*/
        status++;
        break;

    case 2:
        /*发送*/
        /*进入下一个状态*/
        status++;
        break;
    }
}

以“喂一口饭”为例,函数内部拆分为4个状态:舀饭、喂饭、舀菜、喂菜。每次执行“喂一口饭”函数时,都只会执行其中某一状态对应的代码。以前执行一次“喂一口饭”,以前可能需要函数需要4s,现在可能需要1s,就降低了对后面的“回一个消息”的影响。同样的,“回一个消息”也是这拆分成多种状态:查看信息、打字、发送,每次执行这个函数时,都只是执行其中一小部分代码,降低了对“喂一口饭”的影响。

使用状态机模式,可以解决裸机程序的问题:假设A,B两个函数都很耗时,那怎么降低它们相互之间的一个影响呢?很多场景中,其实A,B并不容易拆分成多个状态的,并且这些状态执行时间也不好控制。所以这并不是最优的解决方法,需要多任务系统(重点)。

2. 多任务系统

2.1 多任务模式

对于裸机程序,无论使用哪种模式进行精心的设计,在最差的情况下都无法避免函数之间相互影响。本质原因:函数是轮流执行的。假设“喂一口饭”需要t1-t5这5段时间,“回一个消息”需要ta-te这5段时间,轮流执行时:先执行完t1-t5,紧接着ta-te,交替执行。我们写完程序一定要考虑极端环境下代码的可行性,很明显无论拆分成多少块,只要轮流进行,就避免不掉函数之间相互影响!

那么到底要如何解决呢?????

假如职场妈妈是一个眼疾手快的人,可以一心多用!

1.左手拿勺子,给宝宝喂饭;右手敲键盘,给同事回消息

2.两不耽误,小孩以为“妈妈专心喂饭”;同事以为“在专心回消息”

3.但是脑子只有一个啊,虽然说“一心多用”,但是谁能同时思考两件事情呢?只是她反应快,上衣秒在考虑夹什么菜给小孩,下一秒考虑给同事回复什么信息

本质:交叉执行,t1-t5和ta-te交叉执行

下面咱们上一段伪代码,示例代码如下:

//RTOS程序
喂饭任务()
{
    while (1)
    {
        喂一口饭();
    }
}

回信息任务()
{
    while (1)
    {
        回一个信息();
    }
}


//RTOS程序
void main()
{
    //创建两个任务
    create_task(喂饭任务);
    create_task(回信息任务);

    //启动调度器
    start_scheduler();
}

之后两个任务就会交叉执行;

多任务系统会依次给这些任务分配时间:你执行一会,我执行一会,如此循环。只要切换的时间足够短,我们就会感觉这些任务“像是同时进行的”。如下图所示:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值