Pages: [1]   Go Down
Author Topic: Using COMPA and COMPB correctly  (Read 3869 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Full Member
***
Karma: 1
Posts: 140
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
I am struggeling using CAMPA and COMPB correctly. I would like to start an action by an external interrupt on PIN2 (UNO) and start Timer1. After TIMER1 has started it shall use COMPA and COMPB to start certain actions, but NOT resetting the TIMER1.  That reset shall happen later on special command at a later point in time. The script should enable and disable the LED13 on the UNO board.  Here is the code I tried to start with COMPA and COMPB, but the LED won't go off...

Code:
// avr-libc library includes
#include <avr/io.h>
#include <avr/interrupt.h>

#define LEDPIN 13
int timer;
void setup()
{
 
  pinMode(LEDPIN, OUTPUT);
  cli();                    // disable global interrupts
  pinMode(2, INPUT);        // Enable Pin2 as input to interrupt
  EIMSK |= (1 << INT0);     // Enable external interrupt INT0  (see table 13-2-2 in Atmel 328 spec)
  EICRA |= (1 << ISC01);    // Trigger INT0 on rising edge (see table 13-1 in Atmel 328 spec)
  EICRA |= (1 << ISC00);    // Trigger INT0 on riding edge (see table 13-1 in Atmel 328 spec)

  // initialize Timer1
  // ZERO Timer1
  TCCR1A = 0;               // set entire TCCR1A register to 0
  TCCR1B = 0;               // same for TCCR1B

  // set compare match register to desired timer count:
  OCR1A = 15624;            // turn on CTC mode:initial value changed in loop
  OCR1B = 30000;            // turn on CTC mode:initial value changed in loop
  TCCR1B |= (1 << WGM12);   // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR1B |= (1 << CS10);    // prescaler 1024
  TCCR1B |= (1 << CS12);    // prescaler 1024
  TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt:
  TIMSK1 |= (1 << OCIE1B);  // enable timer compare interrupt:
  sei();                    // Enable global interrupts
}

void loop()
{}
ISR(TIMER1_COMPA_vect){digitalWrite(LEDPIN, HIGH);}
ISR(TIMER1_COMPB_vect){digitalWrite(LEDPIN, LOW);}
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 178
Posts: 8061
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't see an  ISR for INT0 (Pin 2).

You are also setting the Waveform Generator Mode to 4 (only WGM12 set) which resets the timer to 0 when it reaches the value in OCR1A.  You will never reach the value in OCR1B so that interrupt will never occur.  You probably want Mode 0 where the timer counts up to FFFF and then re-starts at 0.  After you reset the timer the LED should come on about a second later and stay on for 0.92 seconds.  The who cycle will then repeat every about every 4.2 seconds.

Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

0
Offline Offline
Full Member
***
Karma: 1
Posts: 140
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi johnwasser,
I improved my sketch and the compA and compB are working. I let the LED on pin13 switch on (compA) and off (compB) which works well.

What is missing/ not working is:
- External interrupt on INT0 on rising flag
- this interrupt starts the timer1 starting at zero
- stopping the timer1 with compB

Is that possible?

Code:
// avr-libc library includes
#include <avr/io.h>
#include <avr/interrupt.h>
#define LEDPIN 13
// int timer;
// unsigned int counter;

void setup()
{
  Serial.begin(115200);
  pinMode(LEDPIN, OUTPUT);
  pinMode(2, INPUT);        // Enable Pin2 as input to interrupt

  cli();                    // disable global interrupts
  EIMSK |= (1 << INT0);     // Enable external interrupt INT0  (see table 13-2-2 in Atmel 328 spec)
  EICRA |= (1 << ISC00);    // Trigger INT0 on rising edge (see table 13-1 and 13-2 in Atmel 328 spec)
  EICRA |= (1 << ISC01);    // Trigger INT0 on rising edge (see table 13-1 and 13-2 in Atmel 328 spec)


    // set compare match register to desired timer count:
  OCR1A = 100;            // COMPA
  OCR1B = 50000;          // COMPB

  TCCR1B = 0;               // set entire  TCCR1B register to 0
  TCCR1B |= (1 << CS12);    // prescaler 256- see table 16-5

//***Not shiure if this is right...
  TCCR1A = 0;               // set entire TCCR1A register to 0
  TCCR1A |= (1 << COM1B0);    // Set OC1A/OC1B on Compare Match (Set output to high level).- see table 16-1
  TCCR1A |= (0 << COM1B1);    // Set OC1A/OC1B on Compare Match (Set output to high level).- see table 16-1
  TCCR1A |= (1 << COM1B0);    // Set OC1A/OC1B on Compare Match (Set output to high level).- see table 16-1
  TCCR1A |= (0 << COM1B1);    // Set OC1A/OC1B on Compare Match (Set output to high level).- see table 16-1
//***Not shiure if this is right...

 
  TIMSK1 |= (1 << OCIE1B);  // enable timer compare interrupt channel B:
  TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt channel A:


  sei();                    // Enable global interrupts
  attachInterrupt(0, start, RISING);
}

void loop()
{
}

ISR(EXT_INT0_vect){   
//Reset Timer1
TCCR1A = 0;               // set entire TCCR1A register to 0
TCCR1B = 0;               // same for TCCR1B and setting timer1 to 0
}


void start()
{
//want to start the timer here

//TCNT1H=0; //To do a 16-bit write, the high byte must be written before the low byte
//TCNT1L=0; //To do a 16-bit write, the high byte must be written before the low byte

}

ISR(TIMER1_COMPA_vect){
  digitalWrite(LEDPIN, HIGH);
  Serial.println("NUN");
}

ISR(TIMER1_COMPB_vect){
  digitalWrite(LEDPIN, LOW);

 // digitalWrite(LEDPIN, !digitalRead(LEDPIN));
 Serial.println("AHA");
//want to stop the timer here
}
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 178
Posts: 8061
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It looks to me like you are starting the timer in setup() and then calling start() which does nothing.  The code in the ISR looks like it stops the timer by setting the control registers to 0.

Perhaps you should move the code that starts the timer into start() and call it from your external interrupt instead of from setup().  

Then you can take the code the stops the timer, put it in a function called stop() and call it from the COMPB interrupt to stop the timer.
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

0
Offline Offline
Full Member
***
Karma: 1
Posts: 140
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
the "attachInterrupt(0, start, RISING);" was a try to get the external interrupt running because I couldn't make it with real "C"  smiley-red . And the  ISR(EXT_INT0_vect) function is basically the double cover to the attachInterrupt...but both doesn't work... smiley-confuse

Quote
The code in the ISR looks like it stops the timer by setting the control registers to 0.
I wanted to put the counter at least to zero. I again read the datasheet and should have put a zero value to the TCNT1 register and not to TCCR1* control register , right?

Quote
Perhaps you should move the code that starts the timer into start() and call it from your external interrupt instead of from setup(). 
I did not know that I started the timer...I thought it would be running anyhow. How can I start and stop it?
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 178
Posts: 8061
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
The code in the ISR looks like it stops the timer by setting the control registers to 0.
I wanted to put the counter at least to zero. I again read the datasheet and should have put a zero value to the TCNT1 register and not to TCCR1* control register , right?
Yes.

Quote
Perhaps you should move the code that starts the timer into start() and call it from your external interrupt instead of from setup(). 
I did not know that I started the timer...I thought it would be running anyhow. How can I start and stop it?

The timer starts when you set the Clock Select Bits in TCCR1B to something other than 0.
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

0
Offline Offline
Full Member
***
Karma: 1
Posts: 140
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
changed the code as proposed. There is "a" reaction to what I have written, but not as expected. The (red) Interrupt rising line is not very close to the (blue) trigger HIGH expected 20 ticks after. Changing the CompB from 100 to 10.000 (which is intended to increase pulseduration but keeping the rising edge at the same position) changes the rising edge position.
Here is the code and a oscilloscope screenshot (blue line is trigger and red line is interrupt reaction- time/ dev= 50mS):

Code:
#include <avr/io.h>
#include <avr/interrupt.h>
#define LEDPIN 13

void setup(){ 
  pinMode(LEDPIN, OUTPUT);
  cli();                    // disable global interrupts
  TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt channel A:
  TIMSK1 |= (1 << OCIE1B);  // enable timer compare interrupt channel B:
//  TCCR1A = 0;               // set entire TCCR1A register to 0
  TCCR1A = B11110000;      //see table 16-1
  sei();                    // Enable global interrupts
  attachInterrupt(0, start, RISING);
}

void loop(){
 OCR1A = 20;            // COMPA
 OCR1B = 40;          // COMPB
}

void start(){
  //want to start/ restart the timer here
  TCCR1B |= (1 << CS10);    // prescaler 1- see table 16-5 and (re)start timer1
}

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

ISR(TIMER1_COMPB_vect){
  digitalWrite(LEDPIN, LOW);
  TCCR1B = 0;  //stop timer here
}
}


* COMPA and COMPB-compA20-compB100.png (4.78 KB, 672x299 - viewed 20 times.)

* COMPA and COMPB-compA20-compB10000.png (5.16 KB, 672x299 - viewed 22 times.)
« Last Edit: December 28, 2012, 07:05:27 am by soulid » Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 178
Posts: 8061
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The pulses look OK to me.

100-20=80  80/16=5 microseconds.  at 0.5 milliseconds (500 microseconds) per division the pulse would be about 1/100th of a division.

10000-20 = 9980.  9980/16=623 microseconds or a little over 1 division.

I suspect the long delay before triggering is a wrap-around of the timer.  Try resetting more of the registers:
Code:

#include <avr/io.h>
#include <avr/interrupt.h>
#define LEDPIN 13

void setup(){ 
  pinMode(LEDPIN, OUTPUT);
  cli();                    // disable global interrupts
  TCCR1A = 0;               // Clear TCCR1A
  TCCR1B = 0;               // Clear TCCR1B
  TCCR1C = 0;               // Clear TCCR1C
  TCNT1 = 0;                // Clear the timer
  TIMSK1 = 0;               // Clear the interrupt mask
 
  TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt channel A:
  TIMSK1 |= (1 << OCIE1B);  // enable timer compare interrupt channel B:
  TCCR1A = B11110000;      // Set OC1A/OC1B on Compare Match, clear OC1A/OC1B at BOTTOM
  OCR1A = 20;              // COMPA at 20/16ths microseconds
  OCR1B = 40;              // COMPB at 40/16th microseconds

  sei();                    // Enable global interrupts
  attachInterrupt(0, start, RISING);
}

void loop(){
}

void start(){
  //want to start/ restart the timer here
  TCNT1 = 0;                // Clear the timer
  TCCR1B |= (1 << CS10);    // prescaler=1 16 MHz clock
}

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

ISR(TIMER1_COMPB_vect){
  digitalWrite(LEDPIN, LOW);
  TCCR1B = 0;  //stop timer here
}
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

0
Offline Offline
Full Member
***
Karma: 1
Posts: 140
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your code works! Jihaa!  smiley-mr-green

I tried several values and found a "base delay" of abput 12.5us meaning that there is no Interupt control below that. From that value on the control works , but I can live with that.

Thank you for your brilliant help!
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 178
Posts: 8061
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your code works! Jihaa!  smiley-mr-green

I tried several values and found a "base delay" of abput 12.5us meaning that there is no Interupt control below that. From that value on the control works , but I can live with that.

Thank you for your brilliant help!

The digitalWrite() function takes a while and probably explains much of your 12.5 microsecond delay.  You can get faster response using direct port access.  On the UNO, Pin 13 is PORTB bit 5.  (See: https://spreadsheets.google.com/spreadsheet/pub?key=0AtfNMvfWhA_ccnRId19SNmVWTDE0MEtTOV9HOEdQa0E&gid=0

To set it HIGH:
Code:
PORTB |= 0b00100000;
To set it LOW:
Code:
PORTB &= 0b11011111;
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Pages: [1]   Go Up
Jump to: