Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Arduino TimerOne usage in interrupt

Status
Not open for further replies.

bmandl

Full Member level 4
Joined
Feb 26, 2010
Messages
207
Helped
3
Reputation
6
Reaction score
3
Trophy points
1,298
Location
Slovenia
Activity points
2,965
Hello,
in my project, I want to use timerone library for timer interrupt. First, the external interrupt (zero cross detector) calls interrupt subrutine in which I set timer overflow interval, set timer interrupt subrutine and start the timer. When timer overflow interval expires, interrupt subrutine start in which I just turn on and turn of my TRIAC, but then I need to stop timer and detach interrupt in this interrupt subrutine, but it seems that is not possible, because timer never stops and is always on. Also, in my interrupt subrutine (from zero cross), where I set timer interval, this interval does not make any changes. Interval is always same (some predefined value).
Can anyone help me with my problem? Is usage of timerone library only possible in main program and not in interrupt subroutines?

External interrupt called by zero cross detector:
Code:
void ISR_Triac()
{ 
    Timer1.setPeriod(zak_isr);
    Timer1.attachInterrupt(Triac_ON);  
   Timer1.restart();    
}

Timer1 interrupt called by timer one:
Code:
void Triac_ON()
{
  digitalWrite(TRIAC,HIGH);
  digitalWrite(TRIAC,LOW);
  Timer1.stop();
}
 

Here is a little test program using an external interrupt on pin 2 to start a delay of around a second on timer1. It uses a serial terminal to toggle pin 5 of the arduino every time a key is pressed. Jumper pin 5 to pin 2 to simulate the external interrupt. The LED on pin 13 will light when the external interrupt is received. The Timer1 interrupt will turn it off after it counts down. Hope this can simulate some of the functionality you need.



Code:
#include <TimerOne.h>
#define trigger 5
#define TRIAC 13
int toggle = 0;


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

   pinMode(2, INPUT);       // external interrupt pin
   pinMode(5, OUTPUT);   // test program uses to interrupt pin 2
   pinMode(13, OUTPUT);  // test program indicator light
   
   attachInterrupt(0, ISR_Triac, CHANGE);  // external interrupt on pin 2
   }


void ISR_Triac()
     {
     cli();//stop interrupts

     TCCR1A = 0;  // set entire TCCR1A register to 0
     TCCR1B = 0;  // same for TCCR1B
     TCNT1  = 0;  //initialize counter value to 0
     
     // Timer1.setPeriod(zak_isr); this doesn't seem to work like you said , so, using line below 
     OCR1A = 60000;  // set time period = (16*10^6) / (1*1024) - 1 (must be <65536) 
 
     TCCR1B |= (1 << WGM12);  // turn on CTC mode
  
     TCCR1B |= (1 << CS12); // set timer1 prescaller
  
     TIMSK1 |= (1 << OCIE1A);   // enable timer compare interrupt

     sei();    //allow interrupts
     digitalWrite(13, HIGH);  // turn ed on to signal start of timer1 delay
     }
     
     
// #define TIMER1_COMPA_vect _VECTOR(11)   /* Timer/Counter1 Compare Match A */

// Timer1 interrupt called by timer one:
// void Triac_ON()  
ISR(TIMER1_COMPA_vect)  // Timer1 interrupt service routine
     {
    // digitalWrite(TRIAC,HIGH);
    // digitalWrite(TRIAC,LOW); 
     digitalWrite(13,LOW);   // after timer1 delay, turn led off
     
     Timer1.stop();
     TIMSK1 &= (_BV( OCIE1A));   // disable timer compare interrupt
     }


void loop()  // toggles pin 5 when key is pressed
    {
    if(Serial.available() > 0)
       {
       Serial.read();  
       if(toggle == 0)
         {
         digitalWrite(5, HIGH);
         toggle = 1;
         }
       else
         {
         digitalWrite(5, LOW);
         toggle = 0;
         }
       }  
    }
 
  • Like
Reactions: bmandl

    bmandl

    Points: 2
    Helpful Answer Positive Rating
FenTrac, thank you for your effort. But problem is, that I need a variable zak_isr for time interval, which is not same all the time. Everytime, interrupt is caused, interval is differend. So I can't just put a constant in there. Also, I want to do this with timer and timer overflow interrupt not with counter.
Here is part of source of timerone library if you can take a look, maybe you find out why my code doesn't work:

Code:
#ifndef TimerOne_h_
#define TimerOne_h_

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include "config/known_16bit_timers.h"

#define TIMER1_RESOLUTION 65536UL  // Timer1 is 16 bit


// Placing nearly all the code in this .h file allows the functions to be
// inlined by the compiler.  In the very common case with constant values
// the compiler will perform all calculations and simply write constants
// to the hardware registers (for example, setPeriod).


class TimerOne
{


#if defined(__AVR__)
  public:
    //****************************
    //  Configuration
    //****************************
    void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {
	TCCR1B = _BV(WGM13);        // set mode as phase and frequency correct pwm, stop the timer
	TCCR1A = 0;                 // clear control register A 
	setPeriod(microseconds);
    }
    void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {
	const unsigned long cycles = (F_CPU / 2000000) * microseconds;
	if (cycles < TIMER1_RESOLUTION) {
		clockSelectBits = _BV(CS10);
		pwmPeriod = cycles;
	} else
	if (cycles < TIMER1_RESOLUTION * 8) {
		clockSelectBits = _BV(CS11);
		pwmPeriod = cycles / 8;
	} else
	if (cycles < TIMER1_RESOLUTION * 64) {
		clockSelectBits = _BV(CS11) | _BV(CS10);
		pwmPeriod = cycles / 64;
	} else
	if (cycles < TIMER1_RESOLUTION * 256) {
		clockSelectBits = _BV(CS12);
		pwmPeriod = cycles / 256;
	} else
	if (cycles < TIMER1_RESOLUTION * 1024) {
		clockSelectBits = _BV(CS12) | _BV(CS10);
		pwmPeriod = cycles / 1024;
	} else {
		clockSelectBits = _BV(CS12) | _BV(CS10);
		pwmPeriod = TIMER1_RESOLUTION - 1;
	}
	ICR1 = pwmPeriod;
	TCCR1B = _BV(WGM13) | clockSelectBits;
    }

    //****************************
    //  Run Control
    //****************************
    void start() __attribute__((always_inline)) {
	TCCR1B = 0;
	TCNT1 = 0;		// TODO: does this cause an undesired interrupt?
	resume();
    }
    void stop() __attribute__((always_inline)) {
	TCCR1B = _BV(WGM13);
    }
    void restart() __attribute__((always_inline)) {
	start();
    }
    void resume() __attribute__((always_inline)) {
	TCCR1B = _BV(WGM13) | clockSelectBits;
    }

    //****************************
    //  PWM outputs
    //****************************
    void setPwmDuty(char pin, unsigned int duty) __attribute__((always_inline)) {
	unsigned long dutyCycle = pwmPeriod;
	dutyCycle *= duty;
	dutyCycle >>= 10;
	if (pin == TIMER1_A_PIN) OCR1A = dutyCycle;
	#ifdef TIMER1_B_PIN
	else if (pin == TIMER1_B_PIN) OCR1B = dutyCycle;
	#endif
	#ifdef TIMER1_C_PIN
	else if (pin == TIMER1_C_PIN) OCR1C = dutyCycle;
	#endif
    }
    void pwm(char pin, unsigned int duty) __attribute__((always_inline)) {
	if (pin == TIMER1_A_PIN) { pinMode(TIMER1_A_PIN, OUTPUT); TCCR1A |= _BV(COM1A1); }
	#ifdef TIMER1_B_PIN
	else if (pin == TIMER1_B_PIN) { pinMode(TIMER1_B_PIN, OUTPUT); TCCR1A |= _BV(COM1B1); }
	#endif
	#ifdef TIMER1_C_PIN
	else if (pin == TIMER1_C_PIN) { pinMode(TIMER1_C_PIN, OUTPUT); TCCR1A |= _BV(COM1C1); }
	#endif
	setPwmDuty(pin, duty);
	TCCR1B = _BV(WGM13) | clockSelectBits;
    }
    void pwm(char pin, unsigned int duty, unsigned long microseconds) __attribute__((always_inline)) {
	if (microseconds > 0) setPeriod(microseconds);
	pwm(pin, duty);
    }
    void disablePwm(char pin) __attribute__((always_inline)) {
	if (pin == TIMER1_A_PIN) TCCR1A &= ~_BV(COM1A1);
	#ifdef TIMER1_B_PIN
	else if (pin == TIMER1_B_PIN) TCCR1A &= ~_BV(COM1B1);
	#endif
	#ifdef TIMER1_C_PIN
	else if (pin == TIMER1_C_PIN) TCCR1A &= ~_BV(COM1C1);
	#endif
    }

    //****************************
    //  Interrupt Function
    //****************************
    void attachInterrupt(void (*isr)()) __attribute__((always_inline)) {
	isrCallback = isr;
	TIMSK1 = _BV(TOIE1);
    }
    void attachInterrupt(void (*isr)(), unsigned long microseconds) __attribute__((always_inline)) {
	if(microseconds > 0) setPeriod(microseconds);
	attachInterrupt(isr);
    }
    void detachInterrupt() __attribute__((always_inline)) {
	TIMSK1 = 0;
    }
    static void (*isrCallback)();

  private:
    // properties
    static unsigned short pwmPeriod;
    static unsigned char clockSelectBits;

- - - Updated - - -

I found my problem :lol:
It was in start() statement. I closely looked at start() function and I found out, that start() always resets TCCR1B register, so TOP value and prescaler settings are lost. That's why my setPeriod statment was "ignored". I replaced start() with resume() (you must admit that resume is awfull word for this meaning) and now it works.
I really had to study datasheet of this AVR and source code of library, but it was worth it. I knew it will be some stupid mistake.
Thank you again FenTrac
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top