Timer using registers

so I went through a video online, it explained that if the prescalar value is set by TCCR1B |= B00000100; which is 256.

and to achieve 500ms 500ms/16us. I want to acheive a timer duration of 40s. hense i used 1024 prescalar TCCR1B |= B00000101; and set the value to 40000ms/64us = 39062

but i cant achieve a duration of 40s. what have i done wrong? and how should i approach to make the timer longer for 40s or more.

Screenshot 2022-09-30 213939

I get 64µs*39062=2.5s

Why do you want to build yet another timer instead of using millis()?

I can't use any Arduino functions, also I found out using registers optimizes the code a lot

1. Do you want to see that TC1's COMPA flag becomes active in every 500 ms? This is what I see in your ISR code.

2. In Normal Mode operation of TC1, the TCNT1 always continuously compares its content with OCR1A and OCR1B Registers and the corresponding flags OCF1 and OCF1B are set when equality occurs (Fig-1). If local interrupt enable bits are active, these flags can generate interrupts for the MCU.


Figure-1:

3. With clkTC1 = 15625 (prescaler 1024), the value to be loaded into OCR1A Register for 500 ms delay is:
15625/2 = 7812.5

4. To avoid fractional value of Section-3, let us select prescaler to 256. Now, clkTC1 = 16 MHz/256 = 62500.

5. With clkTC1 = 62500 (prescaler 256), the value to be loaded into OCR1A Register for 500 ms delay is:
62500/2 = 31250.

6. The sketch (Compiled and tested)

volatile byte ledState = LOW;
volatile bool flag = false;

void setup() 
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  digitalWrite(13, ledState);  //L is OFF

  TCCR1A = 0x00;  //Normal Mode
  TCCR1B = 0x00;  //TC1 is OFF
  TCNT1 = 0;
  OCR1A = 31250;  //500 ms delay; prescaler 256
  bitSet(TIMSK1, OCIE1A);   //local intterupt is active
  TCCR1B |= bit(CS12);   //Start TC1 with prescale 256
}

void loop() 
{
  if(flag == true)
  {
    digitalWrite(13, ledState); //toggle L
    flag = false;
  }
}

ISR(TIMER1_COMPA_vect)
{
  TCNT1 = 0;
  OCR1A = 31250;
  ledState = !ledState; //toggle L
  flag = true;
}

thankyou so much, yeah i get this. but I need a delay of 40000ms. Thats why i tried prescalar 1024. Any idea on how to acheive that?

Figure out how many overflows of the timer gives you 40 seconds. Set up a timer overflow interrupt that increments a counter each interrupt, when it reaches the number you calculated set a bool variable (flag) in the interrupt. In your code you are polling this flag, when it is 1 you know 40 seconds have expired.

So you can just program a timer to give you a 1 second period. Then at each overflow 1 second has elapsed. At each interrupt increment a counter variable and compare it to 40. When it reaches 40 set a flag.

Can't be done. The maximum count you can specify in a 16-bit counter is 65536. 16 MHz / 65536 = 244.144 Hz / 1024 prescale = 0.238422 Hz = 4.19 seconds.

If you want to time longer intervals you have to count overflows of your timer. You could set your timer for 4 seconds (Set TOP to 62499 and prescale to 1024) and count 10 overflows to get a 40-second interval.

or you poll millis() without any additional code.

But @hareendra wants to re-invent the wheel, I guess, wants to make all known errors once more by not looking at existing code...

That's just how Microsoft became a big company.

1 Like

oh this makes so much sense

thankyou, I'll work on this

sry. I'm kinda new to this.

thankyou so much, i made adjustments as you told, it works perfectly

bool LED_STATE = true;
int tuneC[]={80,100,110,90,150,130,120,170,160,130,100,140,180,200,190,200,210};
int durC[]={300,300,300,300,300,300,600,300,300,300,300,150,150,300,150,150,200};
int i,j,n=17; //n is inialitsed to the number o fnotes in tune 1.
int tmp;
void setup() {
  pinMode(13, OUTPUT);        //Set the pin to be OUTPUT
  cli();                      //stop interrupts for till we make the settings
  TCCR1A = 0;             //initialize timer1
  TCCR1B = 0;
  TCCR1B |= 0b00000100;   //256 prescaler
  TIMSK1 |= 0b00000001;   //enable overflow interrupt
  sei();                     //Enable back the interrupts
}

void loop() {
 
}

ISR(TIMER1_OVF_vect)  //timer overflow ISR: update counter
{
  i++; if(i==40){
    //buzzerC();
    LED_STATE = !LED_STATE;      //Invert LED state
    digitalWrite(13,LED_STATE);  //Write new state to the LED on pin D5
    i=0;
  }
}



void buzzerC() {
    DDRE = (1<<DDE4); 
    TCCR3A = (1<<COM3B1)|(1<<WGM31); 
    TCCR3B = (1<<WGM33)|(1<<WGM32)|(1<<CS32); 
    for (i=0;i<n;i++){
        ICR3=tuneC[i];
        OCR3A=tuneC[i]/2;
        TCNT3=0;
        for (j=0;j<durC[i];j++){_delay_ms(1);}
    } 
    ICR3=0;OCR3B=0;TCNT3=0;
}

You want 40000 ms time delay. The sketch of post #4 is modified as follows:

`volatile byte ledState = LOW;
volatile bool flag = false;
volatile byte compCount = 0;

void setup() 
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  digitalWrite(13, ledState);  //L is OFF

  TCCR1A = 0x00;  //Normal Mode
  TCCR1B = 0x00;  //TC1 is OFF
  TCNT1 = 0;
  OCR1A = 62500; //1000 ms time delay; prescaler 256
  bitSet(TIMSK1, OCIE1A);   //local intterupt is active
  TCCR1B |= bit(CS12);   //Start TC1 with prescale 256
}

void loop() 
{
  if(flag == true)
  {
    digitalWrite(13, ledState); //toggle L
    flag = false;
  }
}

ISR(TIMER1_COMPA_vect)
{
  TCNT1 = 0;
  OCR1A = 62500;
  compCount++;
  if(compCount == 40)  //40000/1000 = 40
  {
      compAcount = 0;
      ledState = !ledState; //toggle L at 40000 ms interval
      flag = true;
  }
}
1 Like

so this timer works approx every 2.5s but even with 1024 prescalar how can I obtain a timer value of 40s?

Really, screen shots of code.

Why not post the code in code tags?

Good luck.

Sry about that

bool LED_STATE = true;
int tuneC[]={80,100,110,90,150,130,120,170,160,130,100,140,180,200,190,200,210};
int durC[]={300,300,300,300,300,300,600,300,300,300,300,150,150,300,150,150,200};
int i,j,n=1; //n is inialitsed to the number o fnotes in tune 1.
int tmp;
void setup() {
  pinMode(13, OUTPUT);        //Set the pin to be OUTPUT
  cli();                      //stop interrupts for till we make the settings
  
  TCCR1A = 0;                 // Reset entire TCCR1A to 0 
  TCCR1B = 0;                 // Reset entire TCCR1B to 0
 
  /*set the prescalar to the desired value by changing the CS10 CS12 and CS12 bits. */  
  TCCR1B |= B00000101;        //Set CS12 to 1 so we get prescalar 1024  
  
  /*enable compare match mode on register A*/
  TIMSK1 |= B00000010;        //Set OCIE1A to 1 so we enable compare match A 
  
  OCR1A = 39062;             //Finally we set compare register A to this value  
  sei();                     //Enable back the interrupts
}

void loop() {
 
}


ISR(TIMER1_COMPA_vect){
  TCNT1  = 0;                  //First, set the timer back to 0 so it resets for next interrupt
  //buzzerC();
  LED_STATE = !LED_STATE;      //Invert LED state
  digitalWrite(13,LED_STATE);  //Write new state to the LED on pin D5
  
}

void buzzerC() {
    DDRE = (1<<DDE4); 
    TCCR3A = (1<<COM3B1)|(1<<WGM31); 
    TCCR3B = (1<<WGM33)|(1<<WGM32)|(1<<CS32); 
    for (i=0;i<n;i++){
        ICR3=tuneC[i];
        OCR3A=tuneC[i]/2;
        TCNT3=0;
        for (j=0;j<durC[i];j++){_delay_ms(1);}
    } 
    ICR3=0;OCR3B=0;TCNT3=0;
}

code tags?

You can't. The counter only goes up to 65536 so you can't get slower than 4.12 seconds. To get 40 seconds you would need to count up to 625000.

You can setup timer overflow for 4s and add incrementing the counter in the IRQ. When the counter is reach the 10 - you will obtain desired 40secs interval

I have merged your cross-posts @hareendra.

Cross-posting is against the Arduino forum rules. The reason is that duplicate posts can waste the time of the people trying to help. Someone might spend a lot of time investigating and writing a detailed answer on one topic, without knowing that someone else already did the same in the other topic.

Repeated cross-posting can result in a suspension from the forum.

In the future, please only create one topic for each distinct subject matter. This is basic forum etiquette, as explained in the "How to get the best out of this forum" guide. It contains a lot of other useful information. Please read it.

Thanks in advance for your cooperation.