0
votes

Afternoon all

I'm looking for some assistance please with something that has been confusing me whilst trying to learn timer interrupts

You'd be best treating me as a novice. I have no specific goal here other than learning something that I think would be useful feather to add to my cap!

I have written the below sketch as a stab at a rigid framework for executing different fcns at different rates. I've done something similar using millis() and whilst that worked I found it inelegant that a) there was no obvious way to check for task overruns and backing-up the execution rate and b) the processor is bunged up by checking millis() every program cycle.*

Essentially what I think should be a 1ms timer interrupt on Timer2 (16MHz/64 prescaler /250 compare register =1000hz) is coming out around 0.5ms. I've been confused for hours on this but I'm prepared to accept it could be something fundamental/basic!

What's also throwing a spanner in the works is that using serial comms to try and debug the faster task rates seems to slow things down considerably, so I'm inferring the problem by counting up 1ms tasks to call 10,100 and 1000ms tasks and debugging at the slower level. I suppose chewing through a few characters at 9600baud probably is quite slow.**

I've pasted the code below. Any pointers highly appreciated. Be as harsh as you like :)

cheers

Al

*Whilst not what I'm confused about - any comments on my logic here also welcome ** Although I don't get how Serial.println manages to slow the program down. It's driven from interrupts so it should surely just drop the comms and perform the next ISR - effectively a task overrun. Any comments here also welcome

//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://stackguides.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
}
1
Which arduino board are you running this on?jfowkes
Arduino Uno R3 - ATMEGA328Al Fraser

1 Answers

0
votes

You have two lines here:

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

These two lines set the lower three bits of TCCR2B to 011, which is a /32 prescaler.

Note that for Timer1 and Timer2, the prescaler settings are different than Timer0. For Timer0, the settings above would give you a /64 prescaler.