探索一下如何設置定時器中斷速度

單片機開發在使用定時器中斷的時候,
如果頻率過高會使中斷響應時間很短,一箇中斷沒完成,另一箇中斷又要響應,這樣中斷數量會超過硬件最大中斷值,導致堆棧溢出,出現這種情況後中斷返回值就會混亂,程序跑飛。


以arduino nano板爲對象,看看它的芯片特徵(atmega328p)
Advanced RISC Architecture
– 131 Powerful Instructions – Most Single Clock Cycle Execution
– 32 x 8 General Purpose Working Registers
– Fully Static Operation
– Up to 16 MIPS Throughput at 16 MHz
– On-chip 2-cycle Multiplier

高級risc架構

–131條功能強大的指令–大多數單時鐘週期執行
–32 x 8通用工作寄存器
–全靜態操作
–16兆赫時高達16 MIPS吞吐量(每秒執行16M個指令)
–片上2週期乘法器

重點單週期指令、 16 MIPS 

關於中斷的介紹:
The interrupt execution response for all the enabled AVR interrupts is four clock cycles minimum. After four clock cycles the program vector address for the actual interrupt handling routine
is executed. During this four clock cycle period, the Program Counter is pushed onto the Stack.
The vector is normally a jump to the interrupt routine, and this jump takes three clock cycles. If
an interrupt occurs during execution of a multi-cycle instruction, this instruction is completed
before the interrupt is served. If an interrupt occurs when the MCU is in sleep mode, the interrupt
execution response time is increased by four clock cycles. This increase comes in addition to the
start-up time from the selected sleep mode.
A return from an interrupt handling routine takes four clock cycles. During these four clock
cycles, the Program Counter (two bytes) is popped back from the Stack, the Stack Pointer is
incremented by two, and the I-bit in SREG is set.


所有啓用的AVR中斷的中斷執行響應至少爲四個時鐘週期。四個時鐘週期後,實際中斷處理程序的程序矢量地址被執行。在這四個時鐘週期內,程序計數器被PUSH到堆棧上。

向量通常是中斷程序的跳轉,這個跳轉需要三個時鐘週期。如果在執行多週期指令時發生中斷,

在中斷服務之前先完成此指令。如果在MCU處於睡眠模式時發生中斷,則中斷執行響應時間增加了四個時鐘週期。
除了所選睡眠模式的啓動時間。

從中斷處理程序返回需要四個時鐘週期。在這四個時鐘週期裏循環,程序計數器(兩個字節)從堆棧中POP出,
堆棧指針是遞增2,SREG中的I位被設置。


重點:中斷保護現場4個週期,跳轉需要3個,執行中斷程序n個,回到現場4個

 

分析


假如中斷程序只是一個變量的變化。把程序描述成彙編指令的形式就可以分析消耗的時鐘週期了。

變量+ 常量. 變量+ 變量. 在彙編中並不能直接操作.需要交給寄存器進行中轉
 產生代碼大致形式如下:

mov reg,[ebp - ?]
add reg,[ebp - ?]
mov [ebp - ?],reg

至少要你3個時鐘週期,所以n>3


所以理論上從現場到中斷觸發,跳轉,執行中斷、再到現場至少是4+3+n+4=11+n總共約14個時鐘週期。


沒有深究,也沒有精確的計算方法,還是動手實驗吧。

 

 

實測 


操作一個char 變量需要7個左右的週期(理論推算11+7=18,實際33)
操作一個int 變量需要16個左右的週期(理論推算11+16=27,實際42)
操作一個long 變量需要36個左右的週期(理論推算11+36=47,實際62)

數學能力較差,推算和實際差別較大,還是自己知識水平有限,希望有經驗的老師指教!


底部是測試程序,註釋包含了實測的數據,保證中斷完全執行,程序也不跑飛。
檢驗標準是
delay(1000)準確
保證串口輸出的millis()正確


會有臨界值,程序不穩定,millis正確,但delay完全不在點上。

所以結論是,中斷中的負荷越小越好,中斷頻率需要合適實際應用的要求,既要滿足精度,又不影響效率。

char stepN1=0;//33週期
int stepN2=0;//42週期
long stepN3=0;//62週期

char stepN11=0;//兩個char變量需要 40週期

ISR(TIMER1_COMPA_vect)
{ 
  //stepN3+=1;
  //stepN2+=1;  
  stepN1+=1;
  stepN11+=1;
}

void setup() {
  Serial.begin(115200);
  //Serial.println("Wait 1 seconds");
  delay(1000);
  TCCR1A = 0;
  TCCR1B = 0;
  OCR1A =40; //79;//xxk=200k         //19;//xxk=800k
  TCCR1B |= (1 << CS10)|(1 << WGM12);//0.0625us | CTC模式
  TIMSK1 |= (1 << OCIE1A);// 允許比較中斷
}
 
void loop() {
  Serial.println("Wait 1 seconds");
  delay(1000);
  digitalWrite(LEDPIN, !digitalRead(LEDPIN));
  Serial.println(millis());
}

 


http://www.diy-robots.com/?p=852
Arduino系列教程之 – PWM的祕密(下)


https://www.codercto.com/a/20649.html
魔法書4:Arduino UNO 內部定時器之謎


https://wenku.baidu.com/view/c72a653287c24028915fc3bd.html
AVR CTC模式實驗


https://www.bbsmax.com/A/gVdnRrXNdW/
AVR/Arduino定時/計數器、中斷入門


http://news.eeworld.com.cn/mcu/article_2016100930250.html
ATmega 16單片機的定時器/計數器相關寄存器(二)


http://www.elecfans.com/emb/danpianji/20171203591881.html
不知道單片機程序爲什麼死機跑飛?6個原因告訴你

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章