找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1172|回复: 12
收起左侧

一个freertos全局变量问题

[复制链接]
ID:404263 发表于 2023-8-1 14:22 | 显示全部楼层 |阅读模式
在freertos中,如果有一个变量会受到多个不同优先级的task读取或者写入,是否是需要每次读取或者写入都加一个递归互斥锁,原来想的话只是修改时候加一个互斥锁就行了,但是想了想好像读取也加锁才对,想了解一下这种实时系统全局变量是如何处理的
回复

使用道具 举报

ID:883242 发表于 2023-8-1 14:59 | 显示全部楼层
这就是个典型的原子操作问题,STM32要64位整形运算,没有FPU的单精度float运算,双精度float运算,才不是原子操作,需要加锁。
回复

使用道具 举报

ID:123289 发表于 2023-8-1 15:12 | 显示全部楼层
全局变量的目的,就是让大家都可以引用、修改。
否则,就需要变通一下:
如:将一个变量,切成两个A、B,部分程序用A,另一部分用B。
回复

使用道具 举报

ID:404263 发表于 2023-8-1 15:12 | 显示全部楼层
Hephaestus 发表于 2023-8-1 14:59
这就是个典型的原子操作问题,STM32要64位整形运算,没有FPU的单精度float运算,双精度float运算,才不是原 ...

大佬麻烦看看我下面那种使用情景该如何处理,因为看教程都是纸面内容,没有实际的应用场景不太懂
回复

使用道具 举报

ID:404263 发表于 2023-8-1 15:19 | 显示全部楼层
yzwzfyz 发表于 2023-8-1 15:12
全局变量的目的,就是让大家都可以引用、修改。
否则,就需要变通一下:
如:将一个变量,切成两个A、B, ...

你这个方式也可以解决我那个需求学习了
回复

使用道具 举报

ID:883242 发表于 2023-8-1 15:24 | 显示全部楼层
cokesu 发表于 2023-8-1 15:12
大佬麻烦看看我下面那种使用情景该如何处理,因为看教程都是纸面内容,没有实际的应用场景不太懂

你下面没有了,我就说说原理吧。

比如8位单片机,int类型16位,有个unsigned int i,那么
i++;
就会被拆分成
low(i)++; // 进位carry位变化
high(i)=high(i)+carry;
两步。
如果i=0xff而且在这两步之间被高优先级任务打断,那么i=0
高优先级任务读i,不管是0xff或者0x100都应该正确响应,如果不正确那是你软件写的不对。但!是!现在i是0,这是谁也无法意料的事情,高优先级任务就会发生异常。
那就要在i++之前加互斥锁,处理完毕解锁。如果操作之间切换到高优先级任务,会认为i的值不可用,那就等下次再用。
回复

使用道具 举报

ID:883242 发表于 2023-8-1 15:27 | 显示全部楼层
cokesu 发表于 2023-8-1 15:19
你这个方式也可以解决我那个需求学习了

他的说法不行!因为把一个变量变成A、B两变量,必须要交换这两个变量的值,而交换操作也不是原子的!!!
回复

使用道具 举报

ID:404263 发表于 2023-8-1 15:46 | 显示全部楼层
Hephaestus 发表于 2023-8-1 15:27
他的说法不行!因为把一个变量变成A、B两变量,必须要交换这两个变量的值,而交换操作也不是原子的!!!

void ErrorCtrl_task(void *pvParameters)
{
    while(1)
    {
                if(ADC <= 500)
                {
                        if(SystemMode == SF_WORK)
                        {
                                SystemMode = SF_ERROR;
                        }
                }
        vTaskDelay( pdMS_TO_TICKS(5));
    }
}

void ButtonCtrl_task(void *pvParameters)
{
    while(1)
    {
                switch(SystemMode)
                {
                        case SF_CLOSE:
                                if(按键按下)
                                {
                                        SystemMode = SF_WORK;
                                }
                        break;
                       
                        case SF_WORK:
                                if(按键按下)
                                {
                                        SystemMode = SF_CLOSE;
                                }
                        break;
                       
                        case SF_ERROR:
                                if(按键按下)
                                {
                                        SystemMode = SF_CLOSE;
                                }
                        break;
                }
        vTaskDelay( pdMS_TO_TICKS(5));
    }
}
比如说这样的一个应用,因为我是裸机开发的以前都是这样写,裸机开发的话程序都是一个固定的循序跑下来,所以我不需要考虑SystemMode这个变量的问题,但是RTOS的话因为有优先级的一个调度,所以存在一种情况,比如当前SystemMode = SF_WORK的情况,然后有按键按下,调度器执行完判断if(按键按下)后就开始切换到ErrorCtrl这个任务,这时候ADC也符合<=500的情况,那么SystemMode 会被赋值为SF_ERROR,当执行完这个ErrorCtrl任务后返回ButtonCtrl这个任务会把SystemMode 这个变量赋值为SF_CLOSE,这个不符合我的设计要求了,因为当运行完ErrorCtrl这个任务后如果是裸机开发就已经处于异常模式了不能响应按键,当然这是一种很极端的情况,所以我想知道这个应该要如何处理,是像这样加一个递归锁吗?
void ErrorCtrl_task(void *pvParameters)
{
    while(1)
    {
                if(ADC <= 500)
                {
                        xSemaphoreTakeRecursive(TaskSemaphoreHandle,portMAX_DELAY);
                        if(SystemMode == SF_WORK)
                        {
                                SystemMode = SF_ERROR;
                        }
                        xSemaphoreGiveRecursive(TaskSemaphoreHandle);
                       
                }
        vTaskDelay( pdMS_TO_TICKS(5));
    }
}

void ButtonCtrl_task(void *pvParameters)
{
    while(1)
    {
                xSemaphoreTakeRecursive(TaskSemaphoreHandle,portMAX_DELAY);
                switch(SystemMode)
                {
                        case SF_CLOSE:
                                if(按键按下)
                                {
                                        SystemMode = SF_WORK;
                                }
                        break;
                       
                        case SF_WORK:
                                if(按键按下)
                                {
                                        SystemMode = SF_CLOSE;
                                }
                        break;
                       
                        case SF_ERROR:
                                if(按键按下)
                                {
                                        SystemMode = SF_CLOSE;
                                }
                        break;
                }
                xSemaphoreGiveRecursive(TaskSemaphoreHandle);
        vTaskDelay( pdMS_TO_TICKS(5));
    }
}
回复

使用道具 举报

ID:404263 发表于 2023-8-1 19:28 | 显示全部楼层
Hephaestus 发表于 2023-8-1 15:27
他的说法不行!因为把一个变量变成A、B两变量,必须要交换这两个变量的值,而交换操作也不是原子的!!!

终于发出来了,大佬帮忙看看下面的那个例子,我裸机开发一般习惯就是下面那种写法,异常控制为一个函数,按键操作位另外一个函数,这里就涉及变量的读和写,现在不知道如何处理
回复

使用道具 举报

ID:883242 发表于 2023-8-1 22:31 | 显示全部楼层
当执行完这个ErrorCtrl任务后返回ButtonCtrl这个任务会把SystemMode 这个变量赋值为SF_CLOSE

你这句很让我无法理解,你显然只用到了vTaskDly来切换任务,那么ButtonCtrl这个任务执行时间为什么会那么长,长到时钟节拍都容纳不下了???
回复

使用道具 举报

ID:404263 发表于 2023-8-2 08:41 | 显示全部楼层
Hephaestus 发表于 2023-8-1 22:31
当执行完这个ErrorCtrl任务后返回ButtonCtrl这个任务会把SystemMode 这个变量赋值为SF_CLOSE

你这句很让 ...

不我的意思是存在一种极端情况,那个delay随便写而已只是说会存在一个阻塞的情况,比如我程序正在执行ButtonCtrl这个任务,且这时候SystemMode等于SF_WORK,且程序运行完if(按键按下)这个判断,然后给更高优先级的任务ErrorCtrl给中断了,程序会跑完ErrorCtrl这个任务后再返回ButtonCtrl这个任务里向下执行if语句里面的内容,这样就有一个问题我在ErrorCtrl里已经把SystemMode 赋值为SF_ERROR了,如果执行完这个ErrorCtrl任务后返回ButtonCtrl这个任务,会把SystemMode的值重新赋值为SF_CLOSE,这不是我需要的,我想知道的是这种情况该如何处理,像我上文最后那种加锁方法吗,习惯了裸机开发,跑系统的时候脑子还转不过来
回复

使用道具 举报

ID:404263 发表于 2023-8-2 10:45 | 显示全部楼层
Hephaestus 发表于 2023-8-1 22:31
当执行完这个ErrorCtrl任务后返回ButtonCtrl这个任务会把SystemMode 这个变量赋值为SF_CLOSE

你这句很让 ...

大佬或者是不是我的编程思路有问题,因为我是做小家电开发的,裸机开发的话一个流程下来都是线性的,大佬能不能说一下实时系统的编程思路,比如我小家电开发有数码管的一个显示,负载输出IO的控制,还有按键的控制,这3方面在实时系统该如何编写,如果用裸机开发的一个思维我感觉没办法很好的移植到系统里
回复

使用道具 举报

ID:883242 发表于 2023-8-2 14:45 | 显示全部楼层
cokesu 发表于 2023-8-2 10:45
大佬或者是不是我的编程思路有问题,因为我是做小家电开发的,裸机开发的话一个流程下来都是线性的,大佬 ...

小家电玩儿什么RTOS啊?连c都不能用,只能用汇编,一个字节一个字节的扣。量太大了,单片机省一分钱都能让整个项目省出几十万、
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表