1. 程式人生 > >sdcc man閱讀筆記(六)——中斷

sdcc man閱讀筆記(六)——中斷

一、關鍵字

1.1 interrupt&using

sdcc中,中斷程式使用的關鍵字和keil一樣:

void timer_isr (void) __interrupt (1) __using (1)
{
...
}

interrupt指定中斷號,using指定register bank。

中斷程式可以寫在任意一個原始檔裡,但在包含main程式的原始檔裡,必須要有一份中斷程式的宣告。

如果使用register bank 0,那麼系統會將當前程式用到的暫存器全都儲存進堆疊。如果用到其他register bank,那麼只會儲存類似dptr這樣的特殊暫存器。

1.2 critical

critical用於表示一個程式不能被中斷打算,sdcc會在執行__critical修飾的程式前儲存當前中斷使能狀態,並關閉所有中斷,執行完了之後再開啟。

int foo () __critical
{
...
...
}

同樣對單獨的語句也可以使用

__critical{ i++; }

二、使用中斷時的常見bug

2.1 變數沒有被定義為volatile

這是個常見的錯誤,沒有宣告為volatele的變數,會使編譯器對變數的讀取採取優化。

2.2 非原子指令

有些c語句並非對應一句彙編指令,比如在c51下16位變數讀取,可能需要2到3條指令來執行。如果在執行第一條指令時發生了中斷,很有可能會產生意想不到的後果,而且這種bug很難reproduce。

2.3 堆疊溢位

中斷程式的返回地址和保留的暫存器值全都存在堆疊裡。如果在呼叫中斷程式時,程式正好呼叫了多層的子程式裡最深的一層,很有可能會沒有足夠的堆疊給中斷使用。

2.4 使用了不可重入的函式

如果中斷程式裡對16位/32位的變數進行了乘除、取餘等操作,其實是額外呼叫了一些子函式,要使用–stack-auto將這些都編譯為可重入函式。

另外,如果在中斷程式中呼叫了其他函式(不推薦這麼做),那麼要使用#pragma nooverlay來避免子程式使用可覆蓋的變數。