Tried that. It is my understanding that there is only one timer 1 with two compare values/registers (please correct me if I am wrong).
When I put a Serial.println(TCNT1) in the loop, the timer does not appear to be incrementing ...
I'm stumped.
Yeah, we all have bad hair days from to time. (Well, most of us...)
Here's the deal: You need to be taking over Timer 1. Totally. See Footnote.
Try the following, to make sure that that the Timer 1 registers don't have anything left over from the Arduino initialization stuff:
void setup()
{
pinMode(13, OUTPUT);
cli(); //Disable interrupts while setting registers
TCCR1A = 0; // Make sure it is zero
TCCR1B = (1 << WGM12); // Configure for CTC mode (Set it; don't OR stuff into it)
TCCR1B |= ((1 << CS10) | (1 << CS12)); // Prescaler @ 1024
TIMSK1 = (1 << OCIE1A); // Enable interrupt
OCR1A = 15624; // compare value = 1 sec (16MHz AVR)
sei(); // Enable global interrupts
Serial.begin(9600);
}
Regards,
Dave
Footnote:
The Arduino init() function is always called before your setup() function. That's the way that Arduino builds the application around your sketch.
The Arduino init() function initializes Timer 1 to be ready for PWM output operation as follows:
Sets bit WGM10 in TCCR1A
- ```
[color=blue]Sets bits CS11 and CS10 in TCCR1B[/color]
Bottom line: You are taking over the timer. You need to initialize the registers for your mode of operation. By leaving those Timer 1 register bits set and ORing your bits into TCCR1B, the timer is definitely not operating the way you want it to.
If you are willing to use timer2 instead, there is already a well developed general purpose timer library avalible. I've used it to generate 2 millsec interrupts in a 5x5x5 led cube I built. Recall the arduino core functions already utilize timer0 for predefined functions like millis(), etc.
Either way you should be able to read the source code for MsTimer2 to see how they built it.
bryanb334:
...Or does this timer only control PWM on some pins?
For PWM output using Arduino analogWrite() function calls, Timer 1 is used to control ATmega pins OC1A and OC1B. For Arduino Duemilanove, Uno, and other Arduino non-Mega boards, these are Arduino Pins 10 and 11. Of course, you can still use Pins 10 and 11 for other things; you just can't expect to call *analogWrite()*s for those pins if you modify Timer 1 to operate in CTC mode. (The other analogWrite() pins are not affected by Timer 1 settings.)
Thanks again Dave!
To clarify my understanding of the timer ... timer1 is just one timer but has two compare registers/values (A & B). Can these compare registers/values each have a different value and be used to trigger their own separate ISR in the way I have just done?
I've been fiddling around with TIMER1 , and I can't get interrupt A AND B to work at the same time.
I'm in CTC mode, timer resets when it gets to OCR1A so i set OCR1B lower of course, but still it seems to be either or. Also tried using ICR1 (input capture) and OCR1B to no avail.
It doesn't affect me since I don't want both interrupts, I just use interrupt A and in my loop check for the OCF1B flag.
Yes, I have been having the same problem. Can only get one interrupt to work at a time. My thoughts are that it is in CTC (Clear on Timer Compare) mode. So which one does the clearing? It would seem that the lowest compare value would clear the timer so the higher value would never be reached, but it doesn't appear to be doing that.
Can anybody set me straight?
Thanks!
Here's a way to use ICR1 to determine the count period and use OCR1A and OCR1B interrupts for times somewhere within each count cycle.
//
// Illustration of use of OCR1A and OCR1B interrupts
// with Timer 1.
// A "real" application might do something more meaningful
// than simply recording the times that the interrupts
// occur, but, this can form a framework for bigger and
// better things.
//
// Maybe.
//
// davekw7x
//
#include <avr/io.h>
#include <avr/interrupt.h>
const int LEDPIN = 13;
// I want the count period to be 1 second. This is how long
// (in seconds) it takes the counter to reset.
const float countinterval = 1.0;
// For Arduino Uno and Duemilanove and Mega boards F_CPU = 16 MHz
const unsigned long CPU = F_CPU;
// I'll pick a large prescale divisor to allow long intervals
const unsigned long prescale = 1024;
// Round the floating point value to an integer
const unsigned count1 = (CPU * countinterval / prescale) + 0.5 - 1;
//
// For countinterval = 1 sec, the LED goes high for one second
// and low for a second.
//
// For countinterval equal to 1.0 and F_CPU equal to 16000000,
// we will get count1 = 15624
//
// That is, the result fits in a 16-bit unsigned int, as it must.
// With this scheme you can get count intervals of slightly over
// four seconds.
//
// If you want a shorter interval you can decrease,
// the prescale value to get better granularity,
// but you must always keep the size so that count1
// fits into a 16-bit integer. A more sophisticated program
// might select the optimum prescale factor based on the value
// of countinterval.
//
void setup()
{
pinMode(LEDPIN, OUTPUT);
digitalWrite(LEDPIN, HIGH);
// Disable interrupts while setting registers
cli();
// Make sure all is normal in TCCR1A
TCCR1A = 0;
// Configure timer 1 for CTC mode with TOP = ICR1A, prescale = 1024
// For finer granularity with shorter intervals, you could use a lower
// prescale factor
//
// Top is ICR1
TCCR1B = (1<< WGM13) | (1 << WGM12) | (1<< CS12) | (1 << CS10);
// This determines output frequency: Timer will reset when it hits this value
ICR1 = count1;
OCR1A = count1 / 3; // Make it about 1/3 of the way through the count cycle
// Arithmetic can overflow an int, so do the calculation
// with long ints and truncate the result to an int
OCR1B = 2L*count1 / 3; // Make it about 2/3 of the way through the count cycle
// Enable CTC Interrupts for count match on comparator A
// and also for comparator B
TIMSK1 = (1 << OCIE1B) | (1 << OCIE1A);
// Enable global interrupts
sei();
// As a sanity check, show the register values that were obtained by
// calculations
Serial.begin(9600);
Serial.print("count1 = ");Serial.println(count1);
Serial.print("OCR1A = ");Serial.println(OCR1A);
Serial.print("OCR1B = ");Serial.println(OCR1B);
}
void loop()
{
static unsigned long oldtime;
unsigned long newtime = get_compb1time();
if (newtime != oldtime) {
oldtime = newtime;
//Serial.print(millis());
//Serial.print(": ");
Serial.print(get_compa1time(), DEC);
Serial.print(" ");
Serial.println(newtime, DEC);
}
}
unsigned long compa1time, compb1time; // Millisecond values for OCR matches
// Fetching a 16-bit quantity is not atomic. If it just
// happens that a timer0 (or other) interrupt occurs when
// trying to get compa1time, it just might return
// low byte from one count and high byte from the next
// count. This can lead to occasional gross errors in
// the count value.
// To avoid this, don't try to read compa1time from the application,
// use this function:
unsigned long get_compa1time()
{
unsigned long t;
byte oldSREG = SREG;
cli();
t = compa1time;
SREG = oldSREG;
return t;
}
// See comment preceding get_compa1time()
unsigned long get_compb1time()
{
unsigned long t;
byte oldSREG = SREG;
cli();
t = compb1time;
SREG = oldSREG;
return t;
}
ISR(TIMER1_COMPA_vect)
{
compa1time = millis();
// Two methods for writing to the LED pin.
// Comment out one of them and uncomment the other
// Direct manipulation of Arduino Pin 13 ia
// faster than digitalWrite
//PINB = (1 << 5); // Toggle the LED
// On the other hand, digitalWrite makes it
// easy to use a different LEDPIN without having
// to look up the port and bit number.
// Local variable keeps from having to read the LED pin each time
static byte compa1;
digitalWrite(LEDPIN, (++compa1)&1);
}
ISR(TIMER1_COMPB_vect)
{
compb1time = millis();
}