avr的外部中斷
系統(tǒng)在正常運行主程序時,如果突然有一個重要的任務要馬上處理,那么系統(tǒng)就要保存現(xiàn)在的工作,然后再去處理這個任務,執(zhí)行這個重要任務完畢以后再返回原來的主程序繼續(xù)運行,這就是中斷。
主程序一旦進入中斷服務程序,那么AVR芯片將自動的關閉全局中斷,在這個期間不再執(zhí)行其它的中斷請求,直到中斷程序結束以后芯片才自動的重新開放全局中斷。(注意,在這個期間某些中斷請求可能會被丟棄,某些請求會留下中斷請求標致,一旦當前的中斷執(zhí)行完畢,這個有中斷標致的請求就有可能馬上得到響應,如INT0的下降沿觸發(fā)就會留下中斷請求標致,而低電平觸發(fā)就不會流下中斷請求標致)。如果你想在執(zhí)行中斷服務程序時響應另外一個更重要的中斷,那么就要在中斷服務程序中加入一條打開全局中斷的語句。
我們現(xiàn)在先來討論外部中斷
外部中斷要要記得5個寄存器,分別是:
1.status register -SREG狀態(tài)寄存器。而且外部中斷關心的是它的Bit-7-I位,全局中斷使能。置位時,使能全局中斷。那些單獨的中斷,就是你要實現(xiàn)的那些中斷,他們的使能由其他獨立的控制寄存器控制,就比如說下面說的EIMSK等。如果我們對I清0,則全部的中斷是不可能發(fā)生了,就象一個總的開關一樣,即使單獨中斷標志置位與否。I可以通過SEI和CLI指令來置位和清0。
2.External Interrupt Mask Register -EIMSK外部中斷屏蔽寄存器。當INT7–INT0為
3.External Interrupt Control Register A – EICRA外部中斷控制寄存器A。Bits 7..0–ISC31, ISC30–ISC00, ISC00:外部中斷3 - 0敏感電平控制位。詳見datesheet。如果SREG寄存器的I標志和EIMSK寄存器相應的中斷屏蔽位置位,那么外部中斷3 - 0由引腳INT3~INT0引腳激活。需要注意的是,改變ISCn時,有可能發(fā)生中斷。因此,建議首先在EIMSK里清除相應的中斷使能位INTn,然后再改變ISCn。最后呢,千萬不要忘記在重新使能中斷之前,通過對EIFR的相應中斷標志位INTFn寫“
4.External Interrupt Control Register B – EICRB外部中斷控制寄存器B。Bits 7..0–ISC71, ISC70 - ISC41, ISC40:外部中斷7 - 4敏感電平控制位。詳見datesheet,它和EICRA可是不同的。檢測信號跳變沿之前MCU首先對INT7:4引腳進行采樣。如果選擇了跳變沿中斷或是電平變換中斷(上升沿和下降沿都將產(chǎn)生中斷),只要信號持續(xù)時間大于一個時鐘周期,中斷就會發(fā)生;否則無法保證觸發(fā)中斷。要注意由于XTAL分頻器的存在,CPU時鐘有可能比XTAL時鐘慢。若選擇了低電平中斷,低電平必須保持到當前指令完成,然后才會產(chǎn)生中斷。而且只要將引腳拉低,就會引發(fā)中斷請求。而且,同樣需要象EICRA一樣注意:改變ISCn1/ISCn0時一定要先通過清零EIMSK寄存器的中斷使能位來禁止中斷。否則在改變ISCn1/ISCn0的過程中可能發(fā)生中斷。
5.External Interrupt Flag Register – EIFR。外部中斷標志寄存器。INT7:0引腳電平發(fā)生跳變時觸發(fā)中斷請求,并置位相應的中斷標志INTF7:0。如果SREG的位I以及EIMSK寄存器相應的中斷使能位為’
我們應該清楚的是:外部中斷通過引腳INT7:0觸發(fā)。只要使能了中斷,即使引腳INT7:0配置為輸出,只要電平發(fā)生了合適的變化,中斷也會觸發(fā)。這個特點可以用來產(chǎn)生軟件中斷。通過設置外部中斷控制寄存器–EICRA (INT3:0)和EICRB (INT7:4),中斷可以由下降沿、上升沿,或者是低電平觸發(fā)。當外部中斷使能并且配置為電平觸發(fā),只要引腳電平為低,中斷就會產(chǎn)生。若要求INT7:4在信號下降沿或上升沿觸發(fā),I/O時鐘必須工作,如數(shù)據(jù)手冊P 33“時鐘系統(tǒng)及其分布”說明的那樣。INT3:0的中斷條件檢測則是異步的。也就是說,這些中斷可以用來將器件從睡眠模式喚醒。在睡眠過程(除了空閑模式)中I/O時鐘是停止的。
上面的多為數(shù)據(jù)手冊里面的內容。也許我們回有幾個困惑。
1.為何AVR寫“
http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=749852
http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=691118&bbs_page_no=1&bbs_id=1000
http://www.c51bbs.com/c51bbs/topic1/c51bbs17322.htm
但最終呢,真正的原因是在AVR-GCC的幫助文檔avr-libc本來就有的,F(xiàn)AQ24,Why are (many) interrupt flags cleared by writing a logical 1?當然,你的E文要好地。
參見如下說明:
Why are (many) interrupt flags cleared by writing a logical 1?
Usually, each interrupt has its own interrupt flag bit in some control register, indicating the specified interrupt condition has been met by representing a logical
From the hardwares point of view, an interrupt is asserted as long as the respective bit is set, while global interrupts are enabled. Thus, it is essential to have the bit cleared before interrupts get re-enabled again (which usually happens when returning from an interrupt handler).
Only few subsystems require an explicit action to clear the interrupt request when using interrupt handlers. (The notable exception is the TWI interface, where clearing the interrupt indicates to proceed with the TWI bus hardware handshake, so its never done automatically.)
However, if no normal interrupt handlers are to be used, or in order to make extra sure any pending interrupt gets cleared before re-activating global interrupts (e. g. an external edge-triggered one), it can be necessary to explicitly clear the respective hardware interrupt bit by software. This is usually done by writing a logical 1 into this bit position. This seems to be illogical at first, the bit position already carries a logical 1 when reading it,so why does writing a logical 1 to it clear the interrupt bit?
The solution is simple:writing a logical 1 to it requires only a single OUT instruction, and it is clear that only this single interrupt request bit will be cleared. There is no need to perform a read-modify-write cycle (like, an SBI instruction), since all bits in these control registers are interrupt bits, and writing a logical 0 to the remaining bits (as it is done by the simple OUT instruction) will not alter them, so there is no risk of any race condition that might accidentally clear another interrupt request bit. So instead of writing
TIFR |= _BV(TOV0); /* wrong! */
simply use
TIFR = _BV(TOV0);
2.只要使能了中斷,即使引腳INT7:0配置為輸出,只要電平發(fā)生了合適的變化,中斷也會觸發(fā).這句怎么理解?答:也就是說,你打開了中斷int0和int1,同時這兩個管腳定義為輸出,然后,你使用軟件設置這兩個管腳的輸出電平,當滿足中斷條件時,中斷就發(fā)生了。這不就是軟件中斷嗎?
3.在配置了外部中斷控制寄存器、屏蔽寄存器、標志寄存器后,是否還需要設置IO口為輸入端口呢?答:是的,不過IO口上電時就默認是輸入了,可以不寫這條指令。補充,設置成輸出也照樣產(chǎn)生中斷。它用PINx讀。
評論