首页 > 解决方案 > Arduino CTC 定时器中断 ~2x 快

问题描述

下午所有

我正在寻求一些帮助,在尝试学习定时器中断时让我感到困惑

你最好把我当作新手。除了学习一些我认为有用的东西来增加我的帽子之外,我在这里没有具体的目标!

我已经写了下面的草图,作为以不同速率执行不同 fcn 的刚性框架的尝试。我已经使用millis()做了类似的事情,虽然这个工作我发现它不优雅a)没有明显的方法来检查任务溢出和备份执行率,b)处理器通过检查millis( ) 每个程序周期。*

基本上我认为应该是 Timer2 上的 1ms 定时器中断(16MHz/64 预分频器/250 比较寄存器 =1000hz)大约在 0.5ms 出现。我已经为此困惑了几个小时,但我准备接受它可能是基本的/基本的!

还需要注意的是,使用串行通信来尝试调试更快的任务速率似乎会大大减慢速度,所以我通过计算 1ms 任务来调用 10,100 和 1000ms 任务并在较慢的水平。我想在 9600 波特下咀嚼几个字符可能很慢。**

我已经粘贴了下面的代码。任何指针高度赞赏。随心所欲地苛刻:)

干杯

*虽然不是我感到困惑的 - 也欢迎在这里对我的逻辑发表任何评论 ** 虽然我不明白 Serial.println 如何设法减慢程序速度。它是由中断驱动的,所以它肯定应该只是放弃通信并执行下一个 ISR - 实际上是任务溢出。也欢迎在此发表任何意见

//NOTES
//https://www.robotshop.com/letsmakerobots/arduino-101-timers-and-interrupts
//https://sites.google.com/site/qeewiki/books/avr-guide/timers-on-the-atmega328
//http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_Datasheet.pdf
//

//INITIALISE EVERYTHING

const int ledPin = 13;
volatile int nStepTask1ms = 0; // init 0 - to be used for counting number of 1ms tasks run and hence calling 10ms task
volatile int nStepTask10ms = 0;
volatile int nStepTask100ms = 0;
volatile int nStepTask1000ms = 0;
volatile int LEDFlashState = 0; // init 0 - variable to flip when LED on
volatile int millisNew = 0; // to store up to date time
volatile int millisOld = 0; // to store prev time
volatile int millisDelta = 0; // to store deltas

//
void setup() 
{
Serial.begin(9600); //set up serial comms back to PC
pinMode(ledPin,OUTPUT); //to flash the embedded LED

noInterrupts(); //turn off interrupts while we set the registers
//set up TIMER first

TCCR2A = 0; //sets TCCR1A byte to zero, bits to be later individually mod'd
TCCR2B = 0; //sets TCCR1B byte to zero, bits to be later individually mod'd
TCNT2 = 0; //ensures counter value starting from zero
Serial.println("Timer1 vars reset");

TCCR2B |= (1<<WGM12); // bitwise or between itself and WGM12. TCCR2B = TCCR2B | 00001000. Sets WGM12 high. (CTC mode so WGM12=1, WGM 13,11,10 all 0) https://stackoverflow.com/questions/141525/what-are-bitwise-shift-bit-shift-operators-and-how-do-they-work
Serial.println("Mode 4 CTC set");
Serial.println("TCCR2B=");
Serial.println(TCCR2B,BIN);

TCCR2B |= (1<<CS11); // sets CS11 high
TCCR2B |= (1<<CS10); // sets CS10 high (i.e. this and above give /64 prescaler)
Serial.println("Prescaler set to 64");

OCR2A = 250; //compare match register for timer2
Serial.println("Compare Register set");
Serial.println("OCR2A=");
Serial.println(OCR2A);

TIMSK2 |= (1 << OCIE2A); //enables interrupts - https://playground2014.wordpress.com/arduino/basics-timer-interrupts/
Serial.println("Interrupt Mask Register Set");
Serial.println("TIMSK2=");
Serial.println(TIMSK2);

interrupts(); //enable interrupts again - not sure if this is required given OCIE1A being set above?
}

//set up ISR for Timer2 - timer structure called every interrump (1ms) that subsequently calls 1,10,100 and 1000msec task fcns
ISR(TIMER2_COMPA_vect)
{
TASK_1ms();
if (nStepTask1ms>9)
  {
    TASK_10ms();
    if (nStepTask10ms>9)
      {
        TASK_100ms();
        if (nStepTask100ms>9)
          {
            TASK_1000ms();
          }
      }
  }
}

void TASK_1ms()
{
  // 1ms tasks here
  nStepTask1ms++;
}

void TASK_10ms()
{
  //10ms tasks here
  nStepTask1ms=0;
  nStepTask10ms++;
}

void TASK_100ms()
{
  //100ms tasks here
  nStepTask10ms=0;
  nStepTask100ms++;
  //Serial.println(nStepTask100ms);
}

void TASK_1000ms()
{
  //1000ms tasks here
  nStepTask100ms=0;


  //do something 
  changeLEDFlashState();

  //check timing tick of this task
  millisNew=millis();
  millisDelta=millisNew-millisOld;
  Serial.println(millisDelta);
  millisOld=millisNew;

  nStepTask1000ms++; 
}

void changeLEDFlashState()
{
if(LEDFlashState==0)
{
  digitalWrite(ledPin,HIGH);
  LEDFlashState=1;
  //Serial.println("LED Turned On");
}
else
{
  digitalWrite(ledPin,LOW);
  LEDFlashState=0;
  //Serial.println("LED Turned Off");
}
}


void loop() 
{
// empty
}

标签: timerarduinointerruptmultitasking

解决方案


你在这里有两行:

TCCR2B |= (1<<CS11); // sets CS11 high
TCCR2B |= (1<<CS10); // sets CS10 high (i.e. this and above give /64 prescaler)

这两行将 TCCR2B 的低三位设置为 011,即 /32 预分频器。

请注意,对于 Timer1 和 Timer2,预分频器设置与 Timer0 不同。对于 Timer0,上述设置将为您提供 /64 预分频器。


推荐阅读