Go Down

Topic: Interrupts and timer1 pulse output (Read 752 times) previous topic - next topic

xsilvergs

Hi, been struggling with this for a few days now. I need to trigger an Interrupt on pin change so have used attachInterrupt(0, st_timer, FALLING) which seems to work. This needs to trigger timer1 to give a single pulse varying between 432 uS and 4mS. The pulses are triggered every 20mS (50Hz).

How do I get timer1 to produce a single pulse which gets triggered every cycle unless I decide to stop them? I don't see this as PWM.

Timer1 use defeats me.

Code: [Select]

// Arduino timer CTC interrupt example
//
// avr-libc library includes
#include <avr/io.h>
#include <avr/interrupt.h>
#define LEDPIN 13
#define trigger 2
int d = 0;
void setup()
{
  Serial.begin(9600);
pinMode(LEDPIN, OUTPUT);
//digitalWrite(LEDPIN, HIGH);
pinMode(trigger, INPUT);
digitalWrite(trigger, HIGH);
// initialize Timer1
cli();          // disable global interrupts
TCCR1A = 0;     // set entire TCCR1A register to 0
TCCR1B = 0;     // same for TCCR1B

// set compare match register to desired timer count:
OCR1A = 57;

// turn on CTC mode:
TCCR1B |= (1 << WGM12);

// Set CS10 and CS12 bits for 1024 prescaler:
TCCR1B |= (0 << CS10);
TCCR1B |= (0 << CS12);

// enable timer compare interrupt:
TIMSK1 |= (1 << OCIE1A);

// enable global interrupts:
sei();
attachInterrupt(0, st_timer, FALLING);
}

void st_timer()
{
  Serial.println("st_timer");
  detachInterrupt(0);
  digitalWrite(LEDPIN, !digitalRead(LEDPIN));
  TCCR1B |= (1 << CS10);
  TCCR1B |= (1 << CS12);
}

void loop()
{
// main program
}

ISR(TIMER1_COMPA_vect)
{
  Serial.println("timer1_comp");
digitalWrite(LEDPIN, !digitalRead(LEDPIN));
TIMSK1 = (0 << TOIE1);//disable Timer1 overflow interrupt
TCCR1B |= (0 << CS10);
TCCR1B |= (0 << CS12);
}


Many thanks

PaulS

Quote
How do I get timer1 to produce a single pulse which gets triggered every cycle

I think you first need to define what you mean by "every cycle". Timer1, and other timers, do not "produce pulses". Digital pins do.

Serial.print() in an ISR is not a good idea, and may not work, being based on interrupts itself, which are disabled in an ISR.

xsilvergs

PaulS, thanks for getting back.

By every cycle I mean, every cycle of the main supply, 50Hz here in the UK.

I detect the zero crossing using an opto-isolator as the volts swing negative and go through zero, at this point I need timer1 to run and one of the Arduino digital outputs go (HIGH), then after a period (between 432uS and 4mS) of time, that same digital output should go LOW.

The Serial.print in the ISR is just there to show that actually went to the ISR and will be removed when I can get it working. Is there a better way?

Sorry if my original post was not clear and I hope this has improved things. I knew what I meant and just assumed others would as well. Sorry again :-(

PaulS

Quote
I detect the zero crossing using an opto-isolator as the volts swing negative and go through zero, at this point I need timer1 to run and one of the Arduino digital outputs go (HIGH), then after a period (between 432uS and 4mS) of time, that same digital output should go LOW.

I don't see why you need a timer for this. Turn the pin on when the zero-crossing occurs. Note the time. Periodically, see if it time to turn the pin off. (Periodically being every pass through loop.)

Quote
varying between 432 uS and 4mS.

What causes the variation?

xsilvergs

#4
Jan 08, 2013, 06:01 pm Last Edit: Jan 08, 2013, 07:04 pm by xsilvergs Reason: 1
PaulS,

I thought a timer was the right thing to use as my understanding is that while using the timer the Arduino could do other tasks.

In the worst case; of the 20mS period between mains cycles 4mS would be used timing the longest pulse leaving 15mS to send data to the PC and accept button imputs to increase/decrease the pulse length. The pulses which range between 432uS and 4mS are to sent to an rotary electromagnetic load used as a brake. There are about 5 other lots of data sent to the PC.

It could well be done like you suggest I just thought I'd try using a timer because it has one. It has proved more difficult than I thought though.

Many thanks

xsilvergs

#5
Jan 10, 2013, 03:38 pm Last Edit: Jan 11, 2013, 02:41 pm by xsilvergs Reason: 1
Well I've mashed this together and it appears to do what I want but is it well written? How should it be written?
Note: There is a bit of code in the 'void loop()' to form a square wave oscillator.
Note 2: I'm trying to create a single period using timer1. These periods are between 432uS and 3.7mS in size and are to control one of the digital pins.

Code: [Select]

// Arduino timer CTC interrupt example
//
// avr-libc library includes
#include <avr/io.h>
#include <avr/interrupt.h>
#define LEDPIN 13
#define pulse 7

int grad = 4;
int b = OCR1A;
long previousMillis = 0;
long interval = 1000;
unsigned long currentMillis = millis();
int ledState = LOW;

void setup()
{
 Serial.begin(9600);
 pinMode(pulse, OUTPUT);
 digitalWrite(pulse, LOW);
pinMode(LEDPIN, OUTPUT);
digitalWrite(LEDPIN, LOW);
attachInterrupt(0, start_timer, FALLING);

}

void loop()
{
unsigned long currentMillis = millis();
 if(currentMillis - previousMillis > interval) {    
   previousMillis = currentMillis; // save the last time you blinked the LED    
   if (ledState == LOW)// if the LED is off turn it on and vice-versa:
     ledState = HIGH;
   else
     ledState = LOW;    
   digitalWrite(pulse, ledState); // set the LED with the ledState of the variable:
 }
}

void start_timer()
{
digitalWrite(LEDPIN, HIGH);
cli();          // disable global interrupts
TCNT1 = 0;
TCCR1A = 0;     // set entire TCCR1A register to 0
TCCR1B = 0;     // same for TCCR1B
OCR1A = 62; //3.7 mS
//OCR1A = 11; //432 mS
TCCR1B |= (1 << WGM12); // turn on CTC mode:
TCCR1B |= (1 << CS10); // Set CS10 and CS12 bits for 1024 prescaler:
TCCR1B |= (1 << CS12);
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt:
sei(); // enable global interrupts:
}

ISR(TIMER1_COMPA_vect)
{
digitalWrite(LEDPIN, LOW);
}


Many thanks for any help.

Go Up