資料介紹
描述
概括
本教程介紹如何設置基于定時器的中斷。具體來說,它使用定時器比較中斷定期閃爍 LED,這與流行的 Blink sketch 使用 delay() 形成對比。編程特定于 Arduino Uno、5V Nano 3.x 和克隆中使用的 16MHz ATmega328P。
我的動力
我有一個瘋狂的想法,即構建一個三單元 Raspberry Pi 集群,并使用自定義 8MHz、3.3V ATMega328P(與 Arduino Uno 相同的芯片,但速度和電壓較低)在 Raspberry Pi 控制臺端口之間切換,同時還做其他有用的東西,如測量溫度和電源狀態。我的第一步是找出控制臺端口,這涉及到 SoftwareSerial 庫。
我有一個 5V Arduino Uno,而 Raspberry Pi 當然是 3.3V。因此,為了避免燒壞我的 Pi,我剪了一根電線將軟件串行傳輸和接收引腳連接在一起,創建了一個環回。這個理論是合理的,無論我在傳輸引腳上發出什么,都應該在接收引腳上返回。但是,它沒有用。由于中斷,它沒有工作。
需要中斷才能知道串行數據何時進入特定引腳,但由于關鍵時序,傳輸時中斷被禁用。這種安排使得無法同時發送和接收。不用說,這對我連接到多個 Raspberry Pi 控制臺端口的想法來說不是好兆頭。
但是,從好的方面來說,它讓我對 Arduino Uno 上的中斷產生了興趣。
從小做起
眨眼草圖。這可能是每個人的第一個 Arduino 項目。好吧,這里再次作為復習。
#define LED 9
void setup() {
pinMode(LED, OUTPUT);
}
void loop() {
digitalWrite(LED, LOW);
delay(500);
digitalWrite(LED, HIGH);
delay(500);
}
請注意熟悉的 delay() 子例程來控制打開和關閉時間。每個狀態有 500mS,LED 將以穩定的 1Hz 脈沖。
在我的草圖中,我將引腳 9 用于 LED。這需要在引腳 9 和地之間連接一個 LED 和限流電阻。我要大膽猜測,如果您正在閱讀有關定時器中斷的教程,那么您已經連接了幾個 LED,我不會詳細介紹。不過,使用外部 LED 很重要,因為稍后會同時使用內置 LED 來比較中斷閃爍和 delay() 閃爍。
如果你想做的只是對著閃光燈發出嗚嗚聲,那么這幅素描就很完美了。但是,如果您想同時做其他事情怎么辦?也許測量熱敏電阻兩端的電壓并計算溫度。那樣就好了。
問題是那兩個 delay() 函數調用。每個人都花半秒鐘什么都不做。您可以在其中一個延遲之前或之后插入代碼。但是,如果該代碼需要足夠長的時間來執行,以至于它會錯過眨眼的時間怎么辦?
你可以縮短延遲。也許將其設為 490 而不是 500。也許這太短了,495 是更好的選擇。在某些時候,您可能會舉手說,“一定有更好的方法!”
有一個更好的辦法。它被稱為定時器中斷。
什么是中斷?
查看本教程標題卡中的插圖。
戴大禮帽的花花公子——他是個干擾者。你幾乎可以想象他在一個古老的維多利亞火車站附近閑逛,說著類似“對不起,我的好先生們”之類的話。
現在長凳上的三位先生——他們是您的 loop() 函數中的進程。左邊那個坐下,當 LED 熄滅時,他就是 LED。下一個人是 LED 燈。第三個人,那個戴著帽子遮住眼睛的人,他一定是延遲功能。
“請原諒,我的好先生們,”打斷說。突然,他引起了替補席上三個人的注意。就連昏昏欲睡的家伙也豎起了耳朵。不管他們之前在做什么,他們都停下來讓戴大禮帽的花花公子上臺。
這正是中斷所做的。它會停止 loop() 的正常執行并運行它自己的代碼一段時間。
簡潔很重要
如果戴禮帽的人是個體面的人,他會保持簡短的打斷。他可能會說一些重要的話,比如,‘老兄,你的火車就要出發了,’然后就上路了。或者他可能會一連幾個小時在龐氏騙局的最新趨勢上喋喋不休地自以為是。
前者是好中斷的例子,后者是壞中斷。當中斷花費太多時間時,它會使所有其他進程等待。中斷應該只做絕對必要的事情,并將控制權交還給主循環。
在 LED 閃爍的情況下,最少量的處理歸結為改變輸出引腳的狀態,以便連接的 LED 打開或關閉。因此,在我們繼續之前,請看一下以下代碼行:
PORTB ^= B00100000; // Toggle bit 5, which maps to pin13.
它有什么作用?好吧,閱讀評論,它說它切換了一個映射到引腳的位。該引腳恰好是引腳 13,這是 Arduino Uno 上的內置 LED。PORTB
是 Uno 上控制引腳 8 到 13 的寄存器。位 0 控制引腳 8,位 1 控制引腳 9,依此類推。第 5 位控制引腳 13,即內置 LED。
該^=
運算符是一個異或 (XOR)。XOR 可用于反轉操作數之一為 1 的任何位。XOR 就像一個帶有扭曲的常規 OR。兩個零位作為輸入給出一個零作為輸出。零和一或一和零給出一的輸出。但是,這里有一個轉折……如果你有一個和一個,結果是零。
這就是為什么上面的代碼行只會翻轉 one 所在的位。如果寄存器 PORTB 的第 5 位的當前值為零,則該零與二進制值第 5 位中的 1 進行異或后B00100000
結果為 1。如果 PORTB 的第 5 位是 1,則 1 與 1 的異或結果為 0。每次應用 XOR 時,該位都會翻轉。PORTB 中的任何其他位將與零進行異或,從而返回原始值并且不受影響。
使用 digitalRead() 確定引腳的當前狀態然后使用 digitalWrite() 應用相反狀態的練習現在在單個 XOR 中完成。快速高效,就像任何優秀的、正直的中斷一樣。
我被賣了,我從哪里得到一個?
有了基礎知識,就該開始設置中斷了。這涉及兩個部分。
第一個是中斷服務程序(ISR)。它只是一個執行位翻轉代碼的子程序。ISR() 子例程存在于 setup() 和 loop() 例程之外,它看起來像這樣:
ISR(TIMER1_COMPA_vect)
{
PORTB ^= B00100000; // Toggle bit 5, which maps to pin13.
}
在最簡單的形式中,ISR() 接受一個參數。該參數TIMER1_COMPA_vect
是中斷的向量(或源)。使用像 TIMER1_COMPA_vect 這樣的名稱,您可能會猜到它與 timer1 有關,并且可能正在進行一些比較。你是對的。
但我們還沒有完成。到目前為止,我們所做的只是告訴 ATmega328P 當定時器比較中斷發生時該做什么。我們實際上還沒有設置任何定時器來產生中斷,所以什么都不會發生。
設置的第二部分涉及告訴計時器何時引發中斷。這涉及更多的控制寄存器和二進制值,但如果你已經做到了這一點,你會沒事的。這是代碼:
cli();
TCCR1A = B00000000;
TCCR1B = B00001100;
TIMSK1 = B00000010;
OCR1A = 31250;
sei();
cli() 和 sei() 指令是相關的。第一個清除中斷標志,第二個設置它。中斷標志允許中斷發生。使用 cli() 忽略所有中斷,本質上它是一個很大的請勿打擾標志。sei() 做相反的事情并允許中斷。
最初使用 cli() 阻止中斷的原因是因為需要設置四個寄存器并且所有四個都是相關的。在中斷開始滾動之前只設置一兩個將導致一些不可預測的行為。最好在設置過程中熄滅請勿打擾標志。
寄存器(TCCR1A、TCCR1B 和 TIMSK1)是指示 timer1 如何工作的標志的集合。在代碼中,所有設置都使用二進制值,以便更容易查看正在設置的位以及它是 1 還是 0。
OCR1A 是要與定時器的當前計數進行比較的值。它以十進制表示法顯示,以便于閱讀。按照配置,計時器將從 0 開始并向上計數。當它達到存儲在 OCR1A 中的值時,就會發生一些事情。如果您猜到某事是中斷,您將贏得獎品。
定時器計數的速度以及當它達到 OCR1A 中的值時它做什么由 TCCR1A 和 TCCR1B 中的標志決定。這些定時器控制寄存器在 ATmega328P 數據表的第 15.1 節中有詳細說明。但這里有一個簡短的描述:
-
TCCR1A = B00000000
是最簡單的。它設置全零,或所謂的“正常”模式。
-
TCCR1B = B00001100
指示計數器用位 0..2 的值計數的速度。在這種情況下,那些較低位中的二進制 100 會將預分頻器設置為 256(稍后會詳細介紹)。
-
還包括在 中
TCCR1B = B00001100
,第 3 位中的 1 表示當達到 OCR1A 中存儲的值時,計數器將重置為零。
-
TIMSK1 = B00000010
確保當計數器達到存儲在 OCR1A 中的值時將產生中斷。
最后設置的寄存器是OCR1A,比較寄存器,但是為什么設置為31250呢?答案在于以下等式:
interrupts_per_second = clock_speed / 預分頻器 / OCR1A
也可以表示為
OCR1A = clock_speed / 預分頻器 / interrupts_per_second
使用 16MHz Arduino Uno 和預分頻器值為 256(記住 TCCRB1 的最低 3 位設置該值),等式變得更簡單:
OCR1A = 16MHz / 256 / interrupts_per_second
OCR1A = 62500 / interrupts_per_second
我想每秒切換 LED 兩次以獲得 1Hz 閃爍率,因此我將 62500 除以 2 得到 31250。這就是 OCR1A 值的來源。
讓我們眨眼!
到目前為止,這都是一堆理論。讓我們將所有代碼放在草圖中并證明它確實有效。這是它的樣子:
#define LED 9
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(LED, OUTPUT);
cli();
TCCR1A = B00000000;
TCCR1B = B00001100;
TIMSK1 = B00000010;
OCR1A = 31250;
sei();
}
void loop() {
digitalWrite(LED, LOW);
delay(500);
digitalWrite(LED, HIGH);
delay(500);
}
ISR(TIMER1_COMPA_vect)
{
PORTB ^= B00100000;
}
請注意 delay() 閃爍的舊方法如何仍然包括在內,但現在草圖的新中斷代碼部分也是如此。這就是使用兩個 LED 的原因。外部 LED(引腳 9)將由 loop() 內的 digitalWrite() 和 delay() 控制,而內置 LED(引腳 13)由 ISR() 和 setup() 內的配置控制.
將草圖加載到 Uno,您應該會看到兩個 LED 燈同時閃爍。
現在,做一些改變。嘗試以下任何或所有操作:
- 將 OCR1A 的值加倍,使其成為 62500。
- 將預分頻器位的值設置為 64 而不是 256。 (TCCR1B = B00001101)
- 將兩個 delay() 值更改為 250 而不是 500。
- 刪除 loop() 中的所有內容。
預測每種情況下會發生什么,然后上傳草圖以查看您是否正確。在您思考的同時,想象一下使用 8MHz 時鐘晶體代替標準 16MHz 的 Arduino Uno 會產生什么效果。
作為最后的練習,這個練習需要一些時間,讓原始草圖運行幾個小時甚至一整夜,以查看對 LED 同步的影響。(劇透:它們將明顯不同步。)想出一些關于為什么會發生這種情況的理論。哪個LED的時序更準確?
下一步
一開始,閃爍的 LED 很有趣,但中斷可以用于更多用途。例如,有些中斷可以由輸入引腳的變化觸發。現在您已經知道如何編寫用于打開或關閉 LED 的中斷服務例程,請嘗試使用分配給輸入引腳的按鈕而不是定時器來觸發它。
作為介紹,本教程僅展示了一種在 ATmega328p 上配置中斷的方法。還有更高級別的函數,如:attachInterrupt() 和 detachInterrupt,它們涵蓋更廣泛的 Arduino 模型并處理細節,因此您不一定需要閱讀數據表和設置寄存器位。
無論您打算在哪里學習新知識,了解中斷的工作原理都將使您能夠構建更好、更高效的草圖。因此,放棄 delay() 并開始使用更多中斷。
- S3C2440 開發板實戰(5):定時器中斷
- 單片機定時器中斷后計數器和中斷再進入
- 關于GD32F330單片機定時器中斷初始化后立即進入中斷問題
- 定時器中斷實驗
- 定時器中斷實現步驟及實例筆記
- 51單片機中斷主要關于計時--定時--計算定時器初值--的簡介 ~~~看到的關于中斷? 計時器/定時器的介紹,覺得
- STM32定時器與中斷整理
- C51編程15-中斷篇(定時器中斷2)
- "外部中斷,定時器中斷的理解"
- 51單片機:開啟中斷和定時器
- AVR單片機 實驗六 AD轉換應用實驗
- 51單片機的定時器和計數器中斷機制的詳細簡介
- 使用定時器需要設置的寄存器和51單片機定時器的示例代碼說明
- 定時器中斷應用 3次下載
- 中斷和定時器/計數器
- 如何實現一個軟件定時器? 457次閱讀
- 51單片機定時器和中斷的介紹 2032次閱讀
- 利用定時器中斷代替延時函數(包含例程+原理思想) 3232次閱讀
- 定時器的基本操作 1934次閱讀
- 軟件定時器簡介及程序配置 3651次閱讀
- stm32定時器中斷與誤區 2.7w次閱讀
- STM32定時器原理與使用 5.7w次閱讀
- 8051單片機定時器溢出中斷與CPU響應中斷的時間誤差分析 3971次閱讀
- 51單片機定時器控制LED燈 1w次閱讀
- STM32單片機的系統定時器初始化設置 7957次閱讀
- LPC210X定時器查詢方式及如何初始化 1220次閱讀
- ARM LPC2103定時器中斷方式寄存器設置 1716次閱讀
- 51單片機內部定時器和中斷系統以及編寫第一個簡單的定時器實驗程序 4w次閱讀
- 詳細介紹定時器和定時器中斷 1.7w次閱讀
- stm32定時器中斷程序 1.3w次閱讀
下載排行
本周
- 1山景DSP芯片AP8248A2數據手冊
- 1.06 MB | 532次下載 | 免費
- 2RK3399完整板原理圖(支持平板,盒子VR)
- 3.28 MB | 339次下載 | 免費
- 3TC358743XBG評估板參考手冊
- 1.36 MB | 330次下載 | 免費
- 4DFM軟件使用教程
- 0.84 MB | 295次下載 | 免費
- 5元宇宙深度解析—未來的未來-風口還是泡沫
- 6.40 MB | 227次下載 | 免費
- 6迪文DGUS開發指南
- 31.67 MB | 194次下載 | 免費
- 7元宇宙底層硬件系列報告
- 13.42 MB | 182次下載 | 免費
- 8FP5207XR-G1中文應用手冊
- 1.09 MB | 178次下載 | 免費
本月
- 1OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費
- 2555集成電路應用800例(新編版)
- 0.00 MB | 33566次下載 | 免費
- 3接口電路圖大全
- 未知 | 30323次下載 | 免費
- 4開關電源設計實例指南
- 未知 | 21549次下載 | 免費
- 5電氣工程師手冊免費下載(新編第二版pdf電子書)
- 0.00 MB | 15349次下載 | 免費
- 6數字電路基礎pdf(下載)
- 未知 | 13750次下載 | 免費
- 7電子制作實例集錦 下載
- 未知 | 8113次下載 | 免費
- 8《LED驅動電路設計》 溫德爾著
- 0.00 MB | 6656次下載 | 免費
總榜
- 1matlab軟件下載入口
- 未知 | 935054次下載 | 免費
- 2protel99se軟件下載(可英文版轉中文版)
- 78.1 MB | 537798次下載 | 免費
- 3MATLAB 7.1 下載 (含軟件介紹)
- 未知 | 420027次下載 | 免費
- 4OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費
- 5Altium DXP2002下載入口
- 未知 | 233046次下載 | 免費
- 6電路仿真軟件multisim 10.0免費下載
- 340992 | 191187次下載 | 免費
- 7十天學會AVR單片機與C語言視頻教程 下載
- 158M | 183279次下載 | 免費
- 8proe5.0野火版下載(中文版免費下載)
- 未知 | 138040次下載 | 免費
評論
查看更多