1

I am trying to use the timer interrupt on an Arduion Uno.

Here is a imple example code for displaying a progressive digit on a lcd display, which is updated with timer interupt every second:

#include <LCD_I2C.h>

LCD_I2C lcd(0x27);
volatile bool timerFlag = false; // Timer-Flag (timer-Interrupt)
int displayWidth = 16; // display width
int digit = 0; // current digit

void setup() {
  lcd.begin();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Initializing...");

  noInterrupts();
  TCCR1A = 0;
  TCCR1B = (1 << CS12) | (1 << CS10); // set Prescaler to 1024 
  TCNT1 = 0;
  OCR1A = 15624; // should be 1 second with a prescaler of 102
  TIMSK1 |= (1 << OCIE1A); // Enable timer interrupt
  interrupts();
}

ISR(TIMER1_COMPA_vect) {
  timerFlag = true;
}

void loop() {
  static int position = 0;
  char displayString[17]; // +1 null termination
  
  if (timerFlag) {
    lcd.clear(); // clear display
    
    // update digit and progress
    digit = (digit + 1) % 10;
    position = (position + 1) % (displayWidth + 1);
    memset(displayString, ' ', displayWidth);
    displayString[displayWidth] = '\0'; add null termination
    displayString[position] = '0' + digit; // Character for the current digit
    
    // Show updated progress on the display
    lcd.setCursor(0, 1);
    lcd.print(displayString);
    
    timerFlag = false;
  }
}

The values for setting up he inteupt timer 1 for 1 second is arround everywhere. BUt the updates generated by this code is clearly much slower than 1 second, it's more about 4 seconds. So i did a comparison with a delay based version of the same example:

#include <LCD_I2C.h>

LCD_I2C lcd(0x27);
int displayWidth = 16; // display width

void setup() {
  lcd.begin();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Initializing...");
}

void loop() {
  for (int digit = 0; digit < 10; digit++) {
    char displayString[17]; // +1 null termination
    int position = digit % (displayWidth + 1);

    // Update progression
    memset(displayString, ' ', displayWidth);
    displayString[displayWidth] = '\0'; // add null termination
    displayString[position] = '0' + digit; // Character for the current digit
    
    // Show updated progress on the display
    lcd.clear(); // Clear display
    lcd.setCursor(0, 1);
    lcd.print(displayString);

    delay(1000);
  }
}

This one works as expected and updates every second.

So what is wrong with my interrupt settings?

0

2 Answers 2

3

There is a flag in TCCR1A/B called WGM12 which sets the wave generation mode (WGM) to Clear Timer on Compare Match (CTC). This causes the timer to count up to the value in OCR1A and then automatically reset to 0.

This flag was forgotten, so the interrupt simply ignores the setting OCR1A = 15624; and counts through to 65535, which corresponds to the observed factor of about 4. Therefore the setting line for TCCR1B must be changed to

TCCR1B = (1 << WGM12) | (1 << CS12) | (1 << CS10); 
// Set CTC mode and set Prescaler to 1024

Now the interrupt is triggered correctly every second.

1
  • "This still got me some time to find out what it means and what i needed to do, so:" I'm pleased that it was a useful learning exercise for you and your description looks good. Much more valuable than receiving a ready made and complete solution.
    – 6v6gt
    Aug 18 at 11:01
2

It is ignoring this OCR1A = 15624; and simply rolling over at 65535 instead., hence the error factor of 4. You have to set the wave generation mode as CTC in registers TCCR1A/B.

2
  • Thank you for the answer. Unfortunately, I won't be able to try it out until after the weekend. I will see if it works (but I am pretty confident)
    – maddes8cht
    Aug 11 at 19:36
  • This still got me some time to find out what it means and what i needed to do, so: The ctc mode means "Clear Timer on Compare Match" and is controled by the WGM12 flag in the TCCR1A/B register. As I'm using the TCCR1b, the line gets: ` TCCR1B = (1 << WGM12) | (1 << CS12) | (1 << CS10);`
    – maddes8cht
    Aug 18 at 10:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.