天天看點

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

單片機開發在使用定時器中斷的時候,

如果頻率過高會使中斷響應時間很短,一個中斷沒完成,另一個中斷又要響應,這樣中斷數量會超過硬體最大中斷值,導緻堆棧溢出,出現這種情況後中斷傳回值就會混亂,程式跑飛。

以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個原因告訴你