探索一下如何设置定时器中断速度

单片机开发在使用定时器中断的时候,
如果频率过高会使中断响应时间很短,一个中断没完成,另一个中断又要响应,这样中断数量会超过硬件最大中断值,导致堆栈溢出,出现这种情况后中断返回值就会混乱,程序跑飞。


以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个原因告诉你

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