Timers using Atmega 328 control registers

Hi guys,

So I am very new to Arduino, and in fact all programming languages, but having to learn fast as it will play a main part in Masters final year project in Mechanical Engineering!

That aside, I was quickly made aware that I was going to have to do some 'bit-banging', which is where I start to get confused!

My first task was to try and get an LED to flash at 1Hz using Atmega 328's timer 1. This is my code, it works however doesn't blink at 1Hz. More like 0.23Hz i.e LED on for ~4s? Can anybody offer advice as to why this might be the case?

#include <avr/io.h>
#include <avr/interrupt.h>
int ledPin = 13;
int state = 0;

void setup() {
pinMode(ledPin, OUTPUT);
TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
//Target Timer Count = (Input Frequency / Prescale) / Target Frequency - 1
OCR1A = 15624; // Set CTC compare value to 1Hz at 16MHz AVR clock, with a prescaler of 1024
TCCR1B |= ((1 << CS10) | (1 << CS12)); // Start timer at Fcpu/1024
TCCR1B &= ~((1 << CS11));
TCCR1B &= ~((1<<WGM13)); //clears all bits
//TCCR1A &= ~((1<<WGM11) | (1<<WGM10)); //clears all bits
TCCR1A = 0x00; // Adifferent way of clearing all bits?
TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt
sei(); // Enable global interrupts }
}

void loop() { // Can loop forever, because the ISR will deal with everything
}
//
ISR(TIMER1_COMPA_vect) {
state = 1 - state;
digitalWrite(ledPin, state);
TCNT1 = 0x00;
}

Cheers,
Chris

Sorry, I did not mean this to be a poll? Still getting used to making posts! Please ignore the questions at the top of the post. :blush:

That aside, I was quickly made aware that I was going to have to do some 'bit-banging'

Why? Does the hardware not support what you want to do?

Well what I really want to do is PWM an AC water pump. Not how you may think though as I know this is not possible so what I thought is I could generate a saw-tooth wave such that Arduino counts up to its operating voltage and then back down in a REGULAR time period, of say 10 seconds, 0.1Hz. The key is this time period needs to be regular and measurable. Once I have this, I would like to compare an analogue signal coming in, say from a POT, compare it to the saw-tooth value at that instant in time and for every time the analogue signal is greater than the value of the saw-tooth digitally turn the pump ON. When below, OFF. If you can see what I am saying and my logic is correct then what you would get is the pump turning on/off for varying amounts of time dependant on the input. If you have any suggestions on another way of me achieving this that would be greatly appreciated.

Thanks for your time

so what I thought is I could generate a saw-tooth wave such that Arduino counts up to its operating voltage and then back down in a REGULAR time period, of say 10 seconds, 0.1Hz.

"Counts up to it's operating voltage" needs further explanation. What are you planning to count?

Well I guess up to 1023? 1 less than the maximum value read by Arduino for any analogue input signal. So for example if I turn my POT to max, Arduino reads 1024 and thus the pump will remain on the whole time. Hope that makes sense.

Chris

Well I guess up to 1023?

Yes, but what are you counting? Stars in the sky? Confused students? Number of milliseconds elapsed?

Ok, well don't worry about that just for now thanks.

Is the Arduino using the 16MHz crystal by default? If its not how do I select it? If it is can you see why my code isn't toggling the sate of my LED at 1Hz?

Cheers

Is the Arduino using the 16MHz crystal by default?

Yes.

If it is can you see why my code isn't toggling the sate of my LED at 1Hz?

No.

Greetings, the good news is that you are making this task much more complicated than it needs to be. In CTC mode is that you can set up the Arduino to toggle a pin on a compare-match in hardware. You can use an interrupt routine but it isn't even necessary. This tutorial is helpful if you are just learning about timers (and also check out the datasheet for the atmega168/328) http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=50106&start=0

Timer1 (16bit timer)
// -- TIMER1
int ledPin = 9;
pinMode(ledPin, OUTPUT);
TCCR1B |= (1<<WGM12); // CTC
TCCR1A |= (1<<COM1A0); // toggle OC1A (PB1/arduino 9) on compare match
TCCR1B |= (1<<CS12) | (1<CS10); // /1024 prescale
OCR1A = 7811;

Note that this only works on the PB1 (or arduino 9).. so if you want to toggle the arduino LED pin you need to use your match interrupt routine to change it.

The formula for the match value is

MatchValue = ( fcpu - ( 2* prescaler * freq) ) / ( 2 * prescaler * freq)
Where freq = 1Hz and fcpu = 16000000

That's it!

Jarv. Thank you, this is interesting. I have been through the datasheet a good few times but as I'm sure your aware its not the most forgiving for beginners! Anyway I managed to get my code (with interrupts) to work such that it toggles the LED state at 1Hz, here it is for the record:

#include <avr/io.h>
#include <avr/interrupt.h>

#define ISR_TIMER1_COUNT 15625 // 16.0MHz clock / (prescaler = 1024)
#define ledpin 13
int state = 0;
void setupTimer1(void)
{

TCCR1A &= ~(1<<COM1A1) & // Clearing bits
~(1<<COM1A0) &
~(1<<COM1B1) &
~(1<<COM1B0) &
~(1<<WGM11) &
~(1<<WGM10);

TCCR1B &= ~(1<<ICNC1) & // Clearing bits
~(1<<ICES1) &
~(1<<WGM13) &
~(1<<CS11);

TCCR1B |= (1<<WGM12) | // Setting bits
(1<<CS12) |
(1<<CS10);

OCR1A = ISR_TIMER1_COUNT;

// OCIE1A interrupt flag set
TIMSK1 |= (1<<OCIE1A);

// Start counter at 0, not that it would matter much in this case...
TCNT1 = 0;
}

// This interrupt service routine gets called once per second
ISR(TIMER1_COMPA_vect)
{
state = 1 - state;
digitalWrite(ledpin, state);
}

void setup()
{
pinMode(ledpin, OUTPUT);
setupTimer1();
sei(); // allow interrupts globally
}

void loop()
{

}

Once again, thanks and I'm sure I will be back!

While things are fresh in your mind you should go back and add some meaningful comments that will be of genuine use when you try to reimplement these techniques in the future. Specifically you want to indicate why you are setting/clearing the particular bits. Take a look at the program code I posted here (Generate high frequency square wave - #6 by floresta - Project Guidance - Arduino Forum) for some ideas. I believe that this code is using the technique that jarv is using but it is using Timer/Counter2. There's a lot more comment than code there but the extra time it took me to generate the comments will be paid back in the future, take my word for it.

You might also want to follow the Reference Diagrams For Programmers link in the Atmel ATmega Subsystem Diagrams section at http://web.alfredstate.edu/weimandn/ and look at the various Timer/Counter diagrams.

To post program code you should highlight the part of your post that is code and click on the '#' button. It is a lot easier to follow when you do this.

Don