AVR復位和中斷處理及中斷嵌套【轉載】

AVR復位和中斷處理及中斷嵌套【轉載】

                             ----------------非常感謝原作者,謝謝。

AVR提供了幾種不同的中斷源。這些中斷和復位向量在程序存儲器空間內都有自己單獨的程序向量。所有中斷都被分配一個私有的使能位,要想使能某一中斷,就要向其使能位寫入邏輯1,而且要把狀態寄存器中的全局中斷使能位置1。

    程序存儲器空間最低的一些地址,被默認定義爲復位和中斷向量。完整的向量列表見“中斷”部分。該列表也決定了不同中斷的優先級。地址越小,優先級越高。RESET具有最高的優先級,其次是INT0——外部中斷請求0。詳細討論見“中斷”部分。

    當某個中斷產生時,全局中斷使能位I被清零,所有中斷都被禁止。用戶程序可以向I位寫入1,以實現中斷嵌套。所有已使能的中斷就可以中斷當前的中斷程序。當從中斷指令——RETI——的執行返回時,I位被自動置位。

    基本上有兩種類型的中斷。 第一種是由事件觸發的,把中斷標誌置位。對於這些中斷,程序計數器被引導到實際的中斷向量,以執行中斷處理程序,同時硬件把相應的中斷標誌清除。 通過向要清除的標誌位位置寫一個邏輯1,也可以被清除中斷標誌。如果中斷使能位被清除後,相應的中斷條件發生時,中斷標誌將被設置,而後保持到中斷被使能爲止,或者由軟件把標誌清除。類似地,如果 在全局中斷使能位被清除後,一個或多箇中斷條件產生時,相應的中斷標誌將被設置,並保持到全局中斷使能位被設置爲止,然後按優先級順序執行。

    第二種中斷,只要中斷條件存在,就會被觸發。這些中斷沒有必要具有中斷標誌。如果中斷條件在中斷被使能前消失,那麼中斷將不被觸發。

    當AVR從一箇中斷中退出時,它一般會返回主程序,並且執行再執行一條指令後,纔會響應後續的中斷。

    注意,當進入中斷程序時狀態寄存器不會自動保存,當從中斷程序返回時,它也不會自動恢復。這必須由用戶軟件來完成。

    當使用CLI指令禁能中斷時,中斷將立即被禁能。當CLI指令執行後,將沒有中斷再被執行,即使中斷在CLI執行的同時發生。下例所示爲怎樣使用CLI指令來避免在定時的EEPROM寫時序期間避免產生中斷。

 彙編代碼例子   in       r16, SREG              ; 保存SREG值 
  cli             ; 在定時程序中禁能中斷
  sbi     EECR, EEMWE    ; 開始寫入EEPROM
  sbi     EECR, EEWE
  out     SREG, R16            ; 恢復SREG值(I位) C代碼例子   char     cSREG;
  cSREG = SREG;     /* 保存SREG值*/ 
  /* 在定時程序中禁能中斷 */
  _CLI ();
  EECR  |= (1<
  EECR  |= (1<
  SREG  =  cSREG;                /* 恢復SREG值(I位) */

當使用SEI指令來使能中斷時,緊跟在SEI後面的指令將在任何後續的中斷前被執行,示例如下。

 彙編代碼例子  sei      ; 置位全局中斷使能
 sleep ; 進入休眠,等待中斷
 ; 注意:將在任意中斷前進入休眠  C代碼例子    _SEI();         /* 置位全局中斷使能
   _SLEEP();  /* 進入休眠,等待中斷 */
  /* 注意:將在任意中斷前進入休眠 */

中斷響應時間

    對於所有使能的AVR中斷,中斷執行響應最少爲四個時鐘週期。在四個時鐘週期之後,實際中斷處理程序的向量地址被執行。在這四個時鐘週期內,程序指針 (PC)被壓入堆棧。該失量正常爲一到中斷程序的跳轉,並且該跳轉花費三個時鐘週期。如果中斷髮生在一個多週期指令的執行期間,在中斷被響應前,該指令要 執行完畢。如果當MCU在休眠模式中有中斷產生,那麼該中斷響應時間要再增加四個時鐘週期。這是由於從選擇的睡眠模式中喚醒需要啓動時間。

    從中斷處理程序返回需要四個時鐘週期。在這四個時鐘週期內,程序指針(兩個字節)從堆棧中被彈出,堆棧指針加2,SREG的I位被置位。

    這篇文章是我對AVR單片機中斷的總結。因爲在設計中遇到了這個問題(我頻繁地使用了定時中斷,並且使用了串口中斷(一次)),憑着調試出現的現象以及我 的經驗,我覺得定時器出現了自身嵌套的情況。這在51單片機中是根本不可能出現的。於是我到網上尋求幫助。在QQ羣裏問過很多人,有些不知道,有些嗤之以 鼻,說太簡單了,追問之下,纔不屑一顧地說標誌位要等執行完中斷程序才清除的,只能執行高優先級中斷。我覺得他們是錯的,但是他們在羣裏都是AVR的牛人 了,我用AVR纔不到6個月,跟他們爭辯沒有結果(也許他們沒有遇到過我這種情況,實時性要求並不是很高,所以沒有注意到這個問題)。我想到了佟老師 (《AVR單片機與GCC編程》的作者,網名芯藝),於是向他諮詢了這個問題,下面是他的回答:


中斷嵌套的問題
請問進入中斷服務程序後,中斷標誌位(非全局標誌位)會立刻清零嗎?還是等中斷服務程序執行完了才自動清零?中斷可不可以自己嵌套自己?
芯藝:
一般數據手冊中寫着"進入中斷服務程序之後該標誌自動清零".說明一進入中斷程序硬件自動清除標記志. 關於第二個問題,主頁上已貼出一篇文章,請參考!

文章:中斷可不可以自己嵌套自己

  下面是我做的一個串口接收中斷自已嵌套自己的例子.

#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>

//初始化
void uart_init(void)
{
  UBRRH=0;
  UBRRL=47;//9600 7.3728MHz  
  UCSRB=_BV(RXEN)|_BV(TXEN)|_BV(RXCIE);
}

//串行口寫一字節
void uart_putc(uint8_t c)
{
  loop_until_bit_is_set(UCSRA,UDRE);
  UDR=c;
}

//串口接收中斷
//void USART_RXC_vect(void) __attribute__((interrupt,__INTR_ATTRS));
//void USART_RXC_vect(void) //ISR(USART_RXC_vect)
ISR(USART_RXC_vect)
{
  uint8_t g=UDR;
  uart_putc(g);
  sei();
  while(1);
}

int main(void)
{
  uart_init();
  sei();
  while(1);
  return 0;
}

結果顯示,可多(取決於堆棧)次返回發送的數據.
說明,中斷是可以自己嵌套自己的.

在此我非常感佟老師的無私幫助。同時也希望我們廣大的技術人員要有嚴謹的工作態度,以及寬大爲懷、助人爲樂的胸襟。也衷心地祝願同仁們事業蒸蒸日上。

中斷響應後由硬件自動清零全局中斷,任何中斷都無法響應,在執行完中斷程序後,全局中斷打開.如果需要中斷嵌套 ,則在中斷程序裏軟件添加打開全局中斷.就可以響應任何中斷(包括比本中斷優先級低的中斷).以至可以中斷自己嵌套自己 (例如中斷時間是每隔100ms一次,而中斷執行時間是1s.那樣中斷就自己嵌套自己,程序就混亂了).中斷響應後,全局中斷被屏蔽,如果還有中斷進入,那麼無論優先級高低都無法響應,但響應的中斷標誌位置位,當中斷執行完畢後,總中斷打開,接着執行未響應的中斷.

發佈了37 篇原創文章 · 獲贊 1 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章