Timer 1 problems

Hello folks,

I'm experimenting with a timer interrupt and cannot figure out what's happening.

I have been using this as a guideline.

Part of my code:

#define INTERRUPT_TIME_SEC 10

setup()
{
  Serial.begin(9600);

  interruptTimeInterval = 16000000 / (1024 * INTERRUPT_TIME_SEC) - 1;
  Serial.print("Interrupt time interval=");
  Serial.println(interruptTimeInterval);
  delay(500);

  cli();
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
  TIMSK1 = interruptTimeInterval;
  TCCR1B |= (1 << CS12) | (1 << CS10);  // Prescale set to 1024
  TIMSK1 |= (1 << TOIE1);
  sei();

  Serial.println("start");
}

ISR(TIMER1_OVF_vect)
{
  TIMSK1 = interruptTimeInterval;
  ledStatus[INTERRUPT_LED] = (LOW == ledStatus[INTERRUPT_LED]) ? HIGH : LOW;
  digitalWrite(ledPins[INTERRUPT_LED], ledStatus[INTERRUPT_LED]);
}

It worked when INTERRUPT_TIME_SEC is defined to 10 except that the LED flash with ~5 seconds interval. So I changed it to 20. Then strange things happened. In the Serial monitor window I get the "Interrupt time interval=" message over and over again every 0.5 seconds.

Obviously I have missed something... but what?

Where is your loop() function? Please, post complete codes.

Complete code. This is a sketch I made for testing a keypad and I just extended it to experiment with timer.

I have made some changes to the calculation of the interruptTimeInterval.

#include <Keypad_I2C.h>
#include <Keypad.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>

#define KEYPAD_ADDR 0x20
#define LCD_ADDR 0x27

const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

byte rowPins[ROWS] = {0, 1, 2, 3};
byte colPins[COLS] = {4, 5, 6, 7};

Keypad_I2C keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS, KEYPAD_ADDR, PCF8574);

LiquidCrystal_I2C  lcd1(
  0x27,   // LCD address on the I2C bus.
  2,        // En: (Enable) pin connected to the IO extender module
  1,        // Rw: (Read/write) pin connected to the IO extender module
  0,        // Rs: (Reset) pin connected to the IO extender module
  4,        // d4: data 0 pin map on IO extender module
  5,        // d5: data 1 pin map on IO extender module
  6,        // d6: data 2 pin map on IO extender module
  7         // d7: data 3 pin map on IO extender module
);

char keyPressed[17];

// For LED indicator board.
#define LEDCNT 6
const int ledPins[LEDCNT] = {8, 9, 10, 11, 12, 13};
volatile int ledStatus[LEDCNT];

volatile long interruptTimeInterval = 0;
#define INTERRUPT_LED 5
#define INTERRUPT_TIME_SEC 10

void setup()
{
  Serial.begin(9600);

  for (int i = 0; 17 > i; i++) {
    keyPressed[i] = '\0';
  }

  // Set up LEDs.
  for (int i = 0; LEDCNT > i; i++) {
    pinMode(ledPins[i], OUTPUT);
    digitalWrite(ledPins[i], LOW);
    ledStatus[i] = LOW;
  }

  // Set up keybaord.
  Wire.begin();
  keypad.begin(makeKeymap(keys));

  // Set up LCD display.
  lcd1.begin(16, 2);
  lcd1.setBacklightPin(3, POSITIVE);
  lcd1.setBacklight(HIGH);
  lcd1.print("KEYPAD TEST");

  // Set up software interrupt.
  interruptTimeInterval = 65536 - (16000000 / (INTERRUPT_TIME_SEC * 1024));

  Serial.print("Interrupt time interval=");
  Serial.println(interruptTimeInterval);
  delay(500);

  cli();
  // Set up timer 1 (16 bit timer).
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = interruptTimeInterval;
  TCCR1B |= (1 << CS10) | (1 << CS12);  // Prescale set to 1024
  TIMSK1 |= (1 << TOIE1);
  sei();

  Serial.println("start");
}

ISR(TIMER1_OVF_vect)
{
  TCNT1 = interruptTimeInterval;
  ledStatus[INTERRUPT_LED] = (LOW == ledStatus[INTERRUPT_LED]) ? HIGH : LOW;
  digitalWrite(ledPins[INTERRUPT_LED], ledStatus[INTERRUPT_LED]);
}

void loop()
{
  static int keypos = -1;
  char key = keypad.getKey();
  int  n = 0;
  
  if (key) {
    Serial.println(key);

    if (15 <= keypos++) {
      for (int i = 1; 17 > i; i++) {
        keyPressed[i - 1] = keyPressed[i];
      }
      --keypos;
    }

    keyPressed[keypos] = key;
    lcd1.setCursor(0, 1);
    lcd1.print(keyPressed);

    n = key - '1';
    if (0 <= n && 6 > n) {
      ledStatus[n] = (LOW == ledStatus[n]) ? HIGH : LOW;
      digitalWrite(ledPins[n], ledStatus[n]);
    }
  }
}

1. TC1 is running at 15625 Hz (16000000/1024)

2. Preset value for TCNT1 is:
==> interruptTimeInterval
==> 65536 - (16000000 / (INTERRUPT_TIME_SEC * 1024));
==> 65536 - 1563
==> 63973

3. TOV1 flag will assume HIGH state after counting 1563 pulses which is equal to:
==> 1563/15625 sec time delay
==> 100 ms

Therefore. the LED should flash at 100 ms interval and not at 5 sec interval? You should not see the flashing. With TC1 running at 15625 Hz (prescaler 1024), you cannot make the LED to flash at 5 sec interval. You can make it to flash at best at 4 sec interval by loading a preset value of 3036 into TCNT1.

4. The following codes are wrong -- correction is shown:

ISR(TIMER1_OVF_vect)
{
  TCNT1 = interruptTimeInterval;//reload preset value TIMSK1 = interruptTimeInterval;
  ledStatus[INTERRUPT_LED] = (LOW == ledStatus[INTERRUPT_LED]) ? HIGH : LOW;
  digitalWrite(ledPins[INTERRUPT_LED], ledStatus[INTERRUPT_LED]);
}

5. For the time being ignore the following formula and the ISR codes:
==> interruptTimeInterval = 65536 - (16000000 / (INTERRUPT_TIME_SEC * 1024));

Load TCNT1 with 3036 and check that the built-in LED (L) of UNO flashes at about 4 sec interval.

#define LEDCNT 6
const int ledPins[LEDCNT] = {8, 9, 10, 11, 12, 13};
volatile int ledStatus[LEDCNT];

volatile long interruptTimeInterval = 0;
#define INTERRUPT_LED 13//5  Built-in LED (L) of UNO
#define INTERRUPT_TIME_SEC 10

void setup()
{
  Serial.begin(9600);


  // Set up LEDs.
  for (int i = 0; LEDCNT > i; i++)
  {
    pinMode(ledPins[i], OUTPUT);
    digitalWrite(ledPins[i], LOW);
    ledStatus[i] = LOW;
  }
  // Set up software interrupt.
  interruptTimeInterval = 65536 - (16000000 / (INTERRUPT_TIME_SEC * 1024));//63973

  Serial.print("Interrupt time interval=");
  Serial.println(interruptTimeInterval); //63973
  delay(500);

  cli();
  // Set up timer 1 (16 bit timer).
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 3036;//interruptTimeInterval;  //63973 
  TCCR1B |= (1 << CS10) | (1 << CS12);//Prescale1024//15625//timedelay : 1563/15625 = 100 ms
  TIMSK1 |= (1 << TOIE1);  //local interrupt is enable
  sei();

  Serial.println("start");
}

void loop()
{
  
}

ISR(TIMER1_OVF_vect)  //100 ms
{
  TCNT1 = 3036;//interruptTimeInterval; //preset value:  4 sec time delay
  //ledStatus[INTERRUPT_LED] = (LOW == ledStatus[INTERRUPT_LED]) ? HIGH : LOW;
  digitalWrite(13, !digitalRead(13)); n  //test purpose using L of UNO
  //(ledPins[INTERRUPT_LED], ledStatus[INTERRUPT_LED]);
}

And then play with the formula and your ISR codes.

It is very important that we visualize what is happening!

Thanks.

I have been playing a bit more with the code and have concluded that 4 seconds is the longest interrupt time I can get. But that's OK. I just add a counter in the interrupt function so that I can emulate longer interrupt time.

If you wish, you can still get much longer delay time using TC1 by playing with the division factors of the System Clock Prescaler; but, at the cost of sacrificing all the utility services being offered by the Arduino Platform.