Arduino timer interrupt

Thread Starter

gilley

Joined Nov 23, 2014
23
I have found the example for blinking led using timer interrupt.

Code:
/*
* Arduino 101: timer and interrupts
* 2: Timer1 overflow interrupt example
* more infos: http://www.letmakerobots.com/node/28278
* created by RobotFreak
*/

#define ledPin 13

void setup()
{
  pinMode(ledPin, OUTPUT);

  // initialize timer1
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;

  TCNT1 = 34286;            // preload timer 65536-16MHz/256/2Hz
  TCCR1B |= (1 << CS12);    // 256 prescaler
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts
}

ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  TCNT1 = 34286;            // preload timer
  digitalWrite(ledPin, digitalRead(ledPin) ^ 1);
}

void loop()
{
  // your program here...
}

In the code we can see that TCNT1 is set to 34286, but I wanna know if there is any way to change that withing program. For example that after LED blinks 5 times, I wanna set TCNT1 to 0 so I have longer "blinking" period.

Is this possible using hardware interrupt or somehow withing software ?

Thank you
 

JohnInTX

Joined Jun 26, 2012
4,787
I don't see why you couldn't.
The timer is initialized at line 19 and reloaded at line 27 after it rolls over by the interrupt routine.
Load a counter to 5 when you init the timer. On every interrupt, check it for zero. If not zero, reload the timer to the short value (34286). When the counter runs to zero, stop decrementing and load the timer to the fast value:

C:
 // in the interrupt routine..

  digitalWrite(ledPin, digitalRead(ledPin) ^ 1); // toggle LED on interrupt

  if (flash_counter == 0)  // reload timer
    TCNT1 = 0;   // slow blink
  else {
    flash_counter--;  // decrement counter towards 0
    TCNT1 = 34286; //fast blink
   }
Good luck!
 

Thread Starter

gilley

Joined Nov 23, 2014
23
I don't see why you couldn't.
The timer is initialized at line 19 and reloaded at line 27 after it rolls over by the interrupt routine.
Load a counter to 5 when you init the timer. On every interrupt, check it for zero. If not zero, reload the timer to the short value (34286). When the counter runs to zero, stop decrementing and load the timer to the fast value:

C:
 // in the interrupt routine..

  digitalWrite(ledPin, digitalRead(ledPin) ^ 1); // toggle LED on interrupt

  if (flash_counter == 0)  // reload timer
    TCNT1 = 0;   // slow blink
  else {
    flash_counter--;  // decrement counter towards 0
    TCNT1 = 34286; //fast blink
   }
Good luck!

Thank you, I understand it now.

I also have one more question. I have noticed that I have two registers ( If I am using timer1 I have OCR1A and OCR1B ) that can be set to some values, and when timer1 counts up to that value it calls ISR(TIMER1_COMPx_vect). My question is what can I do If I need to interrupt it more than two times ?

For example , I want to call ISR when timer1 is at value 100, 1000 and 10000 ( random numbers). What are my options then if I only have 2 compare registers ?

Thank you.
 

JohnInTX

Joined Jun 26, 2012
4,787
Thank you, I understand it now.

I also have one more question. I have noticed that I have two registers ( If I am using timer1 I have OCR1A and OCR1B ) that can be set to some values, and when timer1 counts up to that value it calls ISR(TIMER1_COMPx_vect). My question is what can I do If I need to interrupt it more than two times ?

For example , I want to call ISR when timer1 is at value 100, 1000 and 10000 ( random numbers). What are my options then if I only have 2 compare registers ?

Thank you.
One option would be to load one of the compare registers with the next value less any accumulated time. For example, at 100, add 900 to the compare value (1000-the 100 already counted) then at the next interrupt add 9000 and so on.

What are you trying to do? Flash one LED in a sequence, multiple LEDs at different rates or ?? If we have a better idea of the final goal, we can come up with a good solution.
Note that one timer / compare / interrupt setup can be used to generate a system TIK (a small, repeating time interval) . By running counters off the system TIK you can derive as many discrete timed events as you wish.

Good luck!
 

Thread Starter

gilley

Joined Nov 23, 2014
23
One option would be to load one of the compare registers with the next value less any accumulated time. For example, at 100, add 900 to the compare value (1000-the 100 already counted) then at the next interrupt add 9000 and so on.

What are you trying to do? Flash one LED in a sequence, multiple LEDs at different rates or ?? If we have a better idea of the final goal, we can come up with a good solution.
Note that one timer / compare / interrupt setup can be used to generate a system TIK (a small, repeating time interval) . By running counters off the system TIK you can derive as many discrete timed events as you wish.

Good luck!
Actually no, I just took LED diodes as basic example.





What I want to do is in picture above. Each of this rectangles is one arduino pin turned on and off. Green one is the longest and last for T/2, and after that he is turned off and another green one (different arduino pin, but it will turn on electric current of opposite direction). Red one starts at T/8 and ends at 3T/8 and so on. So one arduino pin is for, let's call it "+voltage" and one is for "-voltage" ( I am aware that arduino digital pins cannot give negative voltage ). That sums up one phase, and I have to have 3 phases ( main goal is to control 3 phase asynchronous motor and I have hardware for it). All phases look the same and next one starts on T/3 ( 120 degrees moved), and the last phase starts at T/6 (240 degrees moved ). So basically I need to have 18 "points" in timer/counter where I will turn digitals pins on and off. Some of these points can be used to turn more of pins on and off, but 18 is the worst case.


Also one more thing is that is has to be scalable, so I have to be able to make period narrower or wider without messing up the signals. I tough about using resistor pot on analog input and by changing his value also change the period of phases.

For test I have used LED diode (and of course, much longer period, so that I am able to see LED blinking ) and by using your advice you gave me earlier I managed to change blinking time of LED diode.

Now the only thing that bothers me is how to make these points where timer will call ISR to turn off or on digital pins. To be precise the problem is that I have to have 18 of them, while I only have 2 registers to compare values.

If possible it would be good to have some mean to change time of period ( shorter or longer ) but main concern is to make it work on 100kHz.


Thank you.
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
For something like this, I usually make an array of chars (1 byte each) that represent a pattern of LEDs for each time slice. On each interrupt, pull the next pattern and jam it onto the port pins.

Suppose your LEDs were connected to the same port like this:
Green to bit 01h
Orange to bit 02h
Blue to bit 04h
The first few entries in the array would be (reading your timeline left to right)
01h Green ON (port bit 01h on, others off)
03h Green + Orange ON
07h Green + Orange + Blue ON
07h (4T/16 is the same)
03h Green + Orange ON
01h Green ON
.. continue for the other half. If those are different LEDs they might be weighted 08h, 10h, 20h depending on the port pins they are connected to.

The array would be declared like:
unsigned char LEDpatterns[] = {0x01,0x03,0x07,0x03,0x01}; // for the first half, continue in the same declaration for the 2ed half.

Then just pull the next pattern for each interrupt tik and write it to the port. Change the interrupt timer setting to change the speed without changing the pattern. Wrap the array index to 0 when you reach the end.

Nice!
 

Thread Starter

gilley

Joined Nov 23, 2014
23
Thank you.

Note that one timer / compare / interrupt setup can be used to generate a system TIK (a small, repeating time interval) . By running counters off the system TIK you can derive as many discrete timed events as you wish.

Good luck!
Could you just elaborate this bit more ? Because I'm still not sure how to make more than 2 interrupts. Where could I find example how to use/generate system TIK for what I wanna do ?

Thank you
 

JohnInTX

Joined Jun 26, 2012
4,787
You only need one periodic interrupt - the system TIK. The single service routine maintains the array index. On interrupt it reads array[index], writes the port and bumps/wraps the index for the next time. Changing the speed of the periodic interrupt changes how fast the LED pattern changes.
 

Thread Starter

gilley

Joined Nov 23, 2014
23
I have come up with this

Code:
unsigned int T=65535;
unsigned char LEDpatterns[]={0x01,0x03,0x07,0x03,0x01,0x08,0x18,0x78,0x18,0x08};
unsigned int TimerInterrupts[]={0,T/8,(3*T)/16,(5*T)/16,(3*T)/8,
T/2,(5*T)/8,(11*T)/16,(13*T)/16,(7*T)/8,T};
//period in counter
int counter =0;


void setup(){

  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;

  TCNT1 = 0;    // set timer/counter 1 to zero

  DDRC = 0xff;    //define portC
  TCCR1B |= (1 << CS12);
  TCCR1B |= (1 << CS10);  // 256 prescaler
  OCR1B = 0;
  TIMSK1 |= (1 << OCIE0B);  //register to compare to

  interrupts();             // enable all interrupts


}


  ISR(TIMER1_COMPB_vect){

   PORTC = LEDpatterns[counter];
   OCR1B = TimerInterrupts[counter];
   if(counter<9)
      counter++;
   else
      counter=0;
  }




void loop(){

  }

I have implemented your advice of LEDpatterns in array. It is actually very good idea. I have also used one array for setting OCR1B for next time at which interrupt should happen. Code is currently controling only one phase.

I have tested it with led diodes , but it is kinda hard to tell does it work 100% ( I can definitely see pattern is right, but not sure about time periods ). I will try to get my hands on oscilloscope to test it properly.

Just one last question. How would you implement control of period without messing up signals. I have tough about using linear pot and reading analog value, and according to it setting up T. Would that mess up signals if I put it in void loop?


EDIT:

I have noticed one more problem that is bugging me.

TCNT1 is 16bit timer with max value 65535.
When I declare T as 65535 ( period length of 65535 counts ) everything is working great. But when I set for example T=32000, then on last iteration I have delay before again reading array from 0 again.

I think it has something to do with TCNT1 not overflowing to 0, as it happens when he reaches 65535, but when he reaches 32000 he simply keeps counting until overflowing (aka reaching 65535).

I have tried adding TCNT1=0 in else condition but without luck.

Any advices ?

Thank you.


EDIT2:

OK I got it.

Code:
//Digital pin Mapping
/*
35 -C2
36 -C1
37 -C0
38 -D7
39 -G2
40 -G1

First phase is using portC

Port numbers go from 0 to 7

DDRx is data direction registr and is used to setup pins as input
or output (1 for output, 0 for input).

PORTx is for accesing whole port, PINx is for acessing specific pin

*/

unsigned int T=267;
unsigned char LEDpatterns[]={0x01,0x03,0x07,0x03,0x01,0x08,0x18,0x78,0x18,0x08};
  unsigned int TimerInterrupts[]={0,(T/8),((T/16)*3),((T/16)*5),((T/8)*3),
(T/2),((T/8)*5),((T/16)*11),((T/16)*13),((T/8)*7),T};
//period in counter
int counter =0;
void setup(){

  noInterrupts();           // disable all interrupts


  
  TCCR1A =0;
  TCCR1B = 0;



  DDRC = 0xff;    //define portC
  TCCR1B |= (1<<CS12) |(1<<CS10) | (1<<WGM12) ; // 256 prescaler
  //WGM12 compares to 0CR1A !!!!!!!!!!!!!!!!!
   OCR1B =0;
   OCR1A = T+1;
 
  

  TIMSK1 |= (1 << OCIE0B);  //register to compare to
  TIMSK1 |= (1 << OCIE0A);
  TCNT1 = 0;    // set timer/counter 1 to zero
   interrupts();       // enable all interrupts

}


ISR(TIMER1_COMPB_vect){
 
   PORTC = LEDpatterns[counter];
   OCR1B = TimerInterrupts[counter];
   if(counter<9){
      counter++;
   }
   else{
      counter=0;
    
    
   }
 
    
  }




void loop(){


  }

So the only problem I have now is how to scale T using some hardware(button, linear pot, etc ).

Much appreciated :):):):):):):)
 
Last edited:
Top