前言

        在平时实际开发过程中,其实只要会调用API函数就可以了,因为这些都是验证过没有特别离奇的情况下一般不会出错,所以开发者只要了解API的作用,调用格式,参数输入等就行了。

        但是呢,这样老感觉心底里没底气,空空的,一但问题出现就感觉如临大敌,虚得要死。所以呢,要想让自己有把握应对很多情况,还是得深入了解滴

1. 只会跟着流程走的“CV”工程师

        这其实是我们每个人开始的样子。

        现在假设咱们跟着教程或者视频,初步的认识了FreeRTOS这一个只需要我们配置头文件和调用函数就行的OS。

        从网上下载了一个Demo,看到main()里面一大堆看不懂的代码,我们不改乱动,生怕动了就跑不起来,小心翼翼的把自己的LED代码粘贴上去;编译下载,达成成就点亮第一颗LED灯。

        我们现在信心满满,想着以后可以在别人面前装一下了,我会用OS,哈哈以后都不用愁了。

void main( void )
{
    static StaticTask_t exampleTaskTCB;
    static StackType_t exampleTaskStack[ configMINIMAL_STACK_SIZE ];

    ( void ) printf( "Example FreeRTOS Project\n" );

    ( void ) xTaskCreateStatic( exampleTask,
                                "example",
                                configMINIMAL_STACK_SIZE,
                                NULL,
                                configMAX_PRIORITIES - 1U,
                                &( exampleTaskStack[ 0 ] ),
                                &( exampleTaskTCB ) );

    /* Start the scheduler. */
    vTaskStartScheduler();

    for( ; ; )
    {
        /* Should not reach here. */
    }
}

        然而,做到电脑前,打开IDE,开始写代码,环境配置完了,开始创建任务,实际应用FreeRTOS,就突然发现,完蛋这个函数叫什么?参数是什么东东?我这个任务创建完之后要干嘛?

        只能重新打开官方文档或者别人已经写好的流程创建代码,用上程序员专属被动技能“Ctrl + CV”,打出一套连招,欧克,第一个任务闪烁灯完成啦,接下去开始打印日志....

        把文档和资料看完了,把所有程序跑完了以后,好像也算入了门,一到实际项目运用直接见光死。

        这时候我们其实本质是在做填空题,资料说这里该初始化,我们就初始化,这里放“循环”,我们就循环,如果工程报错或者现象没出来,我们最好的解决方法就是:把工程删了,重新解压下载Demo,重新开始。

        我们对代码没有掌控权,只是代码在掌控我们

                              

2. 只会调用“API”的搬运工

        在一段时间的“CV”训练以后,来到了第二步,现在熟悉了使用频率比较高的API函数例如:

xTaskCreate() 任务创建、vTaskDelay() 任务延时、xQueueCreate() 队列创建;xQueueSend() 队列发送。

        

        我们不需要翻资料就知道,创建任务需要调用xTaskCreate(),知道哪个参数传指针,哪个传栈大小 。要延时这个任务就调用vTaskDelay(),要发送数据就调用xQueueSend()。

        我们是熟练的API搬运工,哪里需要搬哪里。

        可是呢,我们被别人问到:

        “为什么这个任务栈你要设置256字节,而不是128字节啊?”

        “为什么调用vTaskDelay延时以后就可以切换到其他函数啊?凭什么?”

我们就回答说:“管那些干啥,教程和文档是这么写的,能跑就行

                                          

3. 只会觉得“好厉害”的魔法观众

        我们慢慢要使用高级功能,觉得简直就是魔法

        我要保护一个全局变量或者数据,网上说要用"互斥锁(Mutex)",调用xSemaphoreTake(),数据就被保护了,调用xSemaphoreGive(),保护就解除了。我们感慨到:“FreeRTOS好厉害,一行代码就解决了竞态问题

        要接收连续数据,使用“队列 (Queue)”,真方便啊,也不用自己写接收逻辑了。

        现在FreeRTOS像四次元口袋,我们想要什么就拿什么。

        直到某一天,系统死掉了(死锁、栈溢出、越界);或者高优先级任务卡了一下(优先级反转);中断处理时间很长(中断中调用了阻塞函数、中断中内存分配)......

                                              

        魔法不在像之前那样"言出法行",我们不知道魔法的原理,只能看着死掉的主板发呆。

破局

        写这整个系列的内容就是为了打破这种尴尬的局面。

        我们要做的不在是“CV”或者背文档。而是进行"推导"。

        我们要像设计者一样思考:

                        "如果我可以用标志位,为什么要用互斥锁呢?"

                        "如果我切换任务,那我切换回原任务,还会和原来的一样吗?"

                        "如果我可以用数组缓冲区,为什么要用队列呢?"

        然后我们就可以慢慢发觉:

                        "任务就是结构体+栈内存"

                        "任务调度,就是判断+切换"

                        "那些魔法,其实就是工具和逻辑的排列组合"

        希望我们可以关闭"滤镜",重新认识FreeRTOS

                                              

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐