2016-08-05 35 views
2

假設我有一個帶有主循環和1毫秒中斷的微控制器(如果你不知道它是什麼,它只是一箇中斷主循環執行的任務,而它做了一些事情......而它是1毫秒中斷,因爲它每毫秒發生一次)。部分易變的變量?

我有使用主循環和毫秒中斷之間進行通信的變量:

volatile status_t Status; 

現在我必須在主循環中的代碼段用於更新Status變量,它做了它噸的轉換:

cli(); // This temporarily turns off interrupts, so we don't 
      // modify the variable unsafely 
Status.UpdateStuff(); 
Status.UpdateOtherStuff(); 
//etc. 

sei(); // Turn interrupts back on 

的問題是,這些函數的調用Status重寫Status ......編譯器不能緩存在本地內存狀態的值。

一個可能的解決這個問題是這樣的:

cli(); 
status_t* localStatus = (status_t*)&Status; 
localStatus->UpdateStuff(); 
localStatus->UpdateOtherStuff(); 
//etc. 

Status = *localStatus; 
sei(); 

這裏真正的問題是:

這是打算做什麼,我希望它會做什麼或是否有更好的方式來獲得圍繞不斷刷新變量的問題,而不是讓優化器緩存變量?

+0

在第二個片段中,我想你是指'&狀態'。順便說一句,我不認爲有更好的選擇。 –

+0

讓計時器插入隊列中的作業,並且主線程讀取隊列並處理作業。您只需要在隊列操作上使用互斥鎖。 –

+0

@MatteoItalia是的,這就是我的意思...... – DarthRubik

回答

3

您的第二個版本可能仍會向微控制器寫入多次,因爲編譯器可能沒有意識到它可以緩存跨方法調用的值(如果方法是內聯,它可能只會確定這一點)。所以我建議製作一個明確的本地副本,而不僅僅是一個本地指針。

cli(); 
status_t localStatus = Status; 
localStatus.UpdateStuff(); 
localStatus.UpdateOtherStuff(); 
... 
Status = localStatus; 
sei(); 
+0

使用此方法,您可以減少必須在禁用中斷的情況下運行的代碼跨度,以及將新版本狀態移動到共享位置的代碼。 – nate

0

一個示例,用於最大限度地減少處理器在禁用中斷的情況下運行的時間。這隻適用於nextStatus沒有其他副作用。如果確實如此,那麼一旦狀態被成功提交,這些就必須被記錄和執行。

cli(); 
do { 
    auto lastStatus = Status; 
    sei(); 

    auto nextStatus = lastStatus; 
    nextStatus.UpdateStuff(); 
    nextStatus.UpdateOtherStuff(); 
    ... 

    cli(); 
} while (lastStatus != Status); 
Status = nextStatus; 
sei();