我有一个易失性的无符号字符数组LedState9变量,它在线程之间共享。数组中的每个索引表示一个状态。根据每种状态,LED将以不同的顺序闪烁。一个线程设置数组中的状态,另一个基于数组索引的线程将使LED闪烁。每个状态维护一组ontimer和offtimer数组。
unsigned long TimersForBlueLedOn[] = {100,200,500,1,0,0,100,200,500};
unsigned long TimersForBlueLedOff[] = {100,200,500,0,0,0,100,200,500};
在主线程中,我遍历数组中的每个状态,并检查状态是否打开。如果state为on,我会使LED闪烁,以获得与该状态对应的计时器值。
例如:状态2必须在500ms内打开,在ms内关闭。我们继续处于状态2,直到状态3被设置。状态3的ON定时器为1,没有OFF定时器,这意味着LED应始终亮起。
状态3是基本状态,也就是状态3之后的任何状态,应该根据定时器闪烁,并且应该返回到状态3。
例如,在状态3之后,Led蓝色被点亮,当状态6被设置时,Led应该闪烁100ms on和100ms OFF。leds应该闪烁,直到状态6关闭并返回到状态3。因此,基本上它是基于优先级的。如果状态7也是打开的,则在完成状态6之后,它应该闪烁状态7,直到状态7关闭,并且应该返回到状态3。
我的问题是,当状态3总是被设置时,闪烁看起来像闪烁。我需要进行无状态转换。我无法根据下一个状态关闭状态3。
void TurnOnLed(ModemState state) {
LEDState[state] = 1;
}
void TurnOffLed(ModemState state) {
LEDState[state] = 0;
}
unsigned char CheckLedState(unsigned char state) {
return LEDState[state];
}
void GetLedStateVar(LEDStateVar *pLS) {
unsigned char state = pLS->State;
pLS->LongflashCode = INVALID_VAL;
switch(state) {
case ModemTurnOn:
pLS->LED = Blue;
pLS->OnTimer = TimersForBlueLedOn[state];
pLS->OffTimer = TimersForBlueLedOff[state];
break;
case ModemInit:
pLS->LED = Blue;
pLS->OnTimer = TimersForBlueLedOn[state];
pLS->OffTimer = TimersForBlueLedOff[state];
break;
case GSMConnected:
pLS->LED = Blue;
pLS->OnTimer = TimersForBlueLedOn[state];
pLS->OffTimer = TimersForBlueLedOff[state];
break;
case GPRSOn:
pLS->LED = Blue;
pLS->OnTimer = TimersForBlueLedOn[state];
pLS->OffTimer = TimersForBlueLedOff[state];
break;
case ServerNotConnected:
pLS->LED = Green;
pLS->OnTimer = TimersForGreenLedOn[state];
pLS->OffTimer = TimersForGreenLedOff[state];
break;
case SwUpdateDownload:
pLS->LED = Blue;
pLS->OnTimer = TimersForBlueLedOn[state];
pLS->OffTimer = TimersForBlueLedOff[state];
break;
case SwUpdateRestart:
pLS->LED = Blue;
pLS->OnTimer = TimersForBlueLedOn[state];
pLS->OffTimer = TimersForBlueLedOff[state];
break;
case SwUpdateNewVersion:
pLS->LED = Blue;
pLS->OnTimer = TimersForBlueLedOn[state];
pLS->OffTimer = TimersForBlueLedOff[state];
break;
}
void FlashBlueLed(LEDStateVar *pLSV) {
if(pLSV->OnTimer == 1) {
SetLEDBlue(1);
}else {
if(GetElapsedTime(&BlueFlashTimer) > pLSV->OnTimer * MILLI_SECONDS) {
if(!GetLEDBlue()) {
SetLEDBlue(1);
StartTimer(&BlueFlashTimer);
}
}
if(GetElapsedTime(&BlueFlashTimer) > pLSV->OffTimer * MILLI_SECONDS) {
if(GetLEDBlue()) {
SetLEDBlue(0);
StartTimer(&BlueFlashTimer);
}
}
}
}
for(unsigned char i=0; i< FLASHSTATES; ++i) {
LF.State = i;
GetLedStateVar(&LF);
//Flashcode not complete but the state has been reset
if(i == LastBlueState || i == LastGreenState) {
if(LF.LED == Blue) { // BLUE LED
FlashBlueLed(&LF);
}else if(LF.LED == Green) {
FlashGreenLed(&LF);
}
} else if(CheckLedState(i) && LF.OnTimer) {
if(LF.LED == Blue) { // BLUE LED
if(LastBlueState == INVALID_VAL) {
FlashBlueLed(&LF);
}
} else if(LF.LED == Green) { // GREEN LED
if(LastGreenState == INVALID_VAL) {
FlashGreenLed(&LF);
}
} else if(LF.LED == Both) { //BOTH GREEN AND BLUE LED
FlashBothLeds(&LF);
}
}
}发布于 2018-11-30 22:23:34
在这一点上,仍然缺少完整分析的信息,但目前可以提出这些改进建议。
1)通过将0值赋给LEDState变量,您将写入volatile:
void TurnOffLed(ModemState state) {
LEDState[state] = 0;
}你不应该那样做。。无论如何,在您所描述的方法中,没有任何内容表明需要volatile。(除非您的硬件或应用程序外部的某些其他进程正在访问LEDState[i]。)
这个变量数组需要由程序中的各个线程进行更新,这一事实并不要求将其设为volatile。您的数组为每个线程都有一个专用元素就足够了,并且只要您严格限制对每个元素的访问仅限于其各自的线程,就可以使用此方法更新状态。但是这种方法不支持使用volatile。
2)您声明数组中的每个索引表示一个状态。易失性数组只有5个状态的空间,但您在描述中提到了最多7个状态。(后来,在评论中,您说有9个州。)明确定义有多少个状态,然后更改数组以支持所有状态:(请注意,数组不是作为volatile创建的,也不需要是)。
#define MAX_STATES 9
unsigned char array LedState[MAX_STATES];3)考虑对state machine使用switch()语句。
...
switch(i) {
case LastBlueState:
case LastGreenState:
// do something
break;
case <some other state>
// do something
break;
...https://stackoverflow.com/questions/53558845
复制相似问题