找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 2264|回復(fù): 12
收起左側(cè)

一個(gè)freertos全局變量問(wèn)題

[復(fù)制鏈接]
ID:404263 發(fā)表于 2023-8-1 14:22 | 顯示全部樓層 |閱讀模式
在freertos中,如果有一個(gè)變量會(huì)受到多個(gè)不同優(yōu)先級(jí)的task讀取或者寫(xiě)入,是否是需要每次讀取或者寫(xiě)入都加一個(gè)遞歸互斥鎖,原來(lái)想的話(huà)只是修改時(shí)候加一個(gè)互斥鎖就行了,但是想了想好像讀取也加鎖才對(duì),想了解一下這種實(shí)時(shí)系統(tǒng)全局變量是如何處理的
回復(fù)

使用道具 舉報(bào)

ID:883242 發(fā)表于 2023-8-1 14:59 | 顯示全部樓層
這就是個(gè)典型的原子操作問(wèn)題,STM32要64位整形運(yùn)算,沒(méi)有FPU的單精度f(wàn)loat運(yùn)算,雙精度f(wàn)loat運(yùn)算,才不是原子操作,需要加鎖。
回復(fù)

使用道具 舉報(bào)

ID:123289 發(fā)表于 2023-8-1 15:12 | 顯示全部樓層
全局變量的目的,就是讓大家都可以引用、修改。
否則,就需要變通一下:
如:將一個(gè)變量,切成兩個(gè)A、B,部分程序用A,另一部分用B。
回復(fù)

使用道具 舉報(bào)

ID:404263 發(fā)表于 2023-8-1 15:12 | 顯示全部樓層
Hephaestus 發(fā)表于 2023-8-1 14:59
這就是個(gè)典型的原子操作問(wèn)題,STM32要64位整形運(yùn)算,沒(méi)有FPU的單精度f(wàn)loat運(yùn)算,雙精度f(wàn)loat運(yùn)算,才不是原 ...

大佬麻煩看看我下面那種使用情景該如何處理,因?yàn)榭唇坛潭际羌埫鎯?nèi)容,沒(méi)有實(shí)際的應(yīng)用場(chǎng)景不太懂
回復(fù)

使用道具 舉報(bào)

ID:404263 發(fā)表于 2023-8-1 15:19 | 顯示全部樓層
yzwzfyz 發(fā)表于 2023-8-1 15:12
全局變量的目的,就是讓大家都可以引用、修改。
否則,就需要變通一下:
如:將一個(gè)變量,切成兩個(gè)A、B, ...

你這個(gè)方式也可以解決我那個(gè)需求學(xué)習(xí)了
回復(fù)

使用道具 舉報(bào)

ID:883242 發(fā)表于 2023-8-1 15:24 | 顯示全部樓層
cokesu 發(fā)表于 2023-8-1 15:12
大佬麻煩看看我下面那種使用情景該如何處理,因?yàn)榭唇坛潭际羌埫鎯?nèi)容,沒(méi)有實(shí)際的應(yīng)用場(chǎng)景不太懂

你下面沒(méi)有了,我就說(shuō)說(shuō)原理吧。

比如8位單片機(jī),int類(lèi)型16位,有個(gè)unsigned int i,那么
i++;
就會(huì)被拆分成
low(i)++; // 進(jìn)位carry位變化
high(i)=high(i)+carry;
兩步。
如果i=0xff而且在這兩步之間被高優(yōu)先級(jí)任務(wù)打斷,那么i=0
高優(yōu)先級(jí)任務(wù)讀i,不管是0xff或者0x100都應(yīng)該正確響應(yīng),如果不正確那是你軟件寫(xiě)的不對(duì)。但!是!現(xiàn)在i是0,這是誰(shuí)也無(wú)法意料的事情,高優(yōu)先級(jí)任務(wù)就會(huì)發(fā)生異常。
那就要在i++之前加互斥鎖,處理完畢解鎖。如果操作之間切換到高優(yōu)先級(jí)任務(wù),會(huì)認(rèn)為i的值不可用,那就等下次再用。
回復(fù)

使用道具 舉報(bào)

ID:883242 發(fā)表于 2023-8-1 15:27 | 顯示全部樓層
cokesu 發(fā)表于 2023-8-1 15:19
你這個(gè)方式也可以解決我那個(gè)需求學(xué)習(xí)了

他的說(shuō)法不行!因?yàn)榘岩粋(gè)變量變成A、B兩變量,必須要交換這兩個(gè)變量的值,而交換操作也不是原子的。!
回復(fù)

使用道具 舉報(bào)

ID:404263 發(fā)表于 2023-8-1 15:46 | 顯示全部樓層
Hephaestus 發(fā)表于 2023-8-1 15:27
他的說(shuō)法不行!因?yàn)榘岩粋(gè)變量變成A、B兩變量,必須要交換這兩個(gè)變量的值,而交換操作也不是原子的!。

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));
    }
}
比如說(shuō)這樣的一個(gè)應(yīng)用,因?yàn)槲沂锹銠C(jī)開(kāi)發(fā)的以前都是這樣寫(xiě),裸機(jī)開(kāi)發(fā)的話(huà)程序都是一個(gè)固定的循序跑下來(lái),所以我不需要考慮SystemMode這個(gè)變量的問(wèn)題,但是RTOS的話(huà)因?yàn)橛袃?yōu)先級(jí)的一個(gè)調(diào)度,所以存在一種情況,比如當(dāng)前SystemMode = SF_WORK的情況,然后有按鍵按下,調(diào)度器執(zhí)行完判斷if(按鍵按下)后就開(kāi)始切換到ErrorCtrl這個(gè)任務(wù),這時(shí)候ADC也符合<=500的情況,那么SystemMode 會(huì)被賦值為SF_ERROR,當(dāng)執(zhí)行完這個(gè)ErrorCtrl任務(wù)后返回ButtonCtrl這個(gè)任務(wù)會(huì)把SystemMode 這個(gè)變量賦值為SF_CLOSE,這個(gè)不符合我的設(shè)計(jì)要求了,因?yàn)楫?dāng)運(yùn)行完ErrorCtrl這個(gè)任務(wù)后如果是裸機(jī)開(kāi)發(fā)就已經(jīng)處于異常模式了不能響應(yīng)按鍵,當(dāng)然這是一種很極端的情況,所以我想知道這個(gè)應(yīng)該要如何處理,是像這樣加一個(gè)遞歸鎖嗎?
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));
    }
}
回復(fù)

使用道具 舉報(bào)

ID:404263 發(fā)表于 2023-8-1 19:28 | 顯示全部樓層
Hephaestus 發(fā)表于 2023-8-1 15:27
他的說(shuō)法不行!因?yàn)榘岩粋(gè)變量變成A、B兩變量,必須要交換這兩個(gè)變量的值,而交換操作也不是原子的。!

終于發(fā)出來(lái)了,大佬幫忙看看下面的那個(gè)例子,我裸機(jī)開(kāi)發(fā)一般習(xí)慣就是下面那種寫(xiě)法,異?刂茷橐粋(gè)函數(shù),按鍵操作位另外一個(gè)函數(shù),這里就涉及變量的讀和寫(xiě),現(xiàn)在不知道如何處理
回復(fù)

使用道具 舉報(bào)

ID:883242 發(fā)表于 2023-8-1 22:31 | 顯示全部樓層
當(dāng)執(zhí)行完這個(gè)ErrorCtrl任務(wù)后返回ButtonCtrl這個(gè)任務(wù)會(huì)把SystemMode 這個(gè)變量賦值為SF_CLOSE

你這句很讓我無(wú)法理解,你顯然只用到了vTaskDly來(lái)切換任務(wù),那么ButtonCtrl這個(gè)任務(wù)執(zhí)行時(shí)間為什么會(huì)那么長(zhǎng),長(zhǎng)到時(shí)鐘節(jié)拍都容納不下了???
回復(fù)

使用道具 舉報(bào)

ID:404263 發(fā)表于 2023-8-2 08:41 | 顯示全部樓層
Hephaestus 發(fā)表于 2023-8-1 22:31
當(dāng)執(zhí)行完這個(gè)ErrorCtrl任務(wù)后返回ButtonCtrl這個(gè)任務(wù)會(huì)把SystemMode 這個(gè)變量賦值為SF_CLOSE

你這句很讓 ...

不我的意思是存在一種極端情況,那個(gè)delay隨便寫(xiě)而已只是說(shuō)會(huì)存在一個(gè)阻塞的情況,比如我程序正在執(zhí)行ButtonCtrl這個(gè)任務(wù),且這時(shí)候SystemMode等于SF_WORK,且程序運(yùn)行完if(按鍵按下)這個(gè)判斷,然后給更高優(yōu)先級(jí)的任務(wù)ErrorCtrl給中斷了,程序會(huì)跑完ErrorCtrl這個(gè)任務(wù)后再返回ButtonCtrl這個(gè)任務(wù)里向下執(zhí)行if語(yǔ)句里面的內(nèi)容,這樣就有一個(gè)問(wèn)題我在ErrorCtrl里已經(jīng)把SystemMode 賦值為SF_ERROR了,如果執(zhí)行完這個(gè)ErrorCtrl任務(wù)后返回ButtonCtrl這個(gè)任務(wù),會(huì)把SystemMode的值重新賦值為SF_CLOSE,這不是我需要的,我想知道的是這種情況該如何處理,像我上文最后那種加鎖方法嗎,習(xí)慣了裸機(jī)開(kāi)發(fā),跑系統(tǒng)的時(shí)候腦子還轉(zhuǎn)不過(guò)來(lái)
回復(fù)

使用道具 舉報(bào)

ID:404263 發(fā)表于 2023-8-2 10:45 | 顯示全部樓層
Hephaestus 發(fā)表于 2023-8-1 22:31
當(dāng)執(zhí)行完這個(gè)ErrorCtrl任務(wù)后返回ButtonCtrl這個(gè)任務(wù)會(huì)把SystemMode 這個(gè)變量賦值為SF_CLOSE

你這句很讓 ...

大佬或者是不是我的編程思路有問(wèn)題,因?yàn)槲沂亲鲂〖译婇_(kāi)發(fā)的,裸機(jī)開(kāi)發(fā)的話(huà)一個(gè)流程下來(lái)都是線(xiàn)性的,大佬能不能說(shuō)一下實(shí)時(shí)系統(tǒng)的編程思路,比如我小家電開(kāi)發(fā)有數(shù)碼管的一個(gè)顯示,負(fù)載輸出IO的控制,還有按鍵的控制,這3方面在實(shí)時(shí)系統(tǒng)該如何編寫(xiě),如果用裸機(jī)開(kāi)發(fā)的一個(gè)思維我感覺(jué)沒(méi)辦法很好的移植到系統(tǒng)里
回復(fù)

使用道具 舉報(bào)

ID:883242 發(fā)表于 2023-8-2 14:45 | 顯示全部樓層
cokesu 發(fā)表于 2023-8-2 10:45
大佬或者是不是我的編程思路有問(wèn)題,因?yàn)槲沂亲鲂〖译婇_(kāi)發(fā)的,裸機(jī)開(kāi)發(fā)的話(huà)一個(gè)流程下來(lái)都是線(xiàn)性的,大佬 ...

小家電玩兒什么RTOS啊?連c都不能用,只能用匯編,一個(gè)字節(jié)一個(gè)字節(jié)的扣。量太大了,單片機(jī)省一分錢(qián)都能讓整個(gè)項(xiàng)目省出幾十萬(wàn)、
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表