Zápisník experimentátora
Hierarchy: Časovač (timer)
Each Arduino contains several timers. They have different uses. In this article, we will focus on a timer that interrupts intermittently at intervals to allow us to perform the desired action in an interruption. As a result, the LED on pin 13 will blink by 1 Hz. We get the same function as in the classic Blink example. But we will not unnecessarily burden the microcontroller with a wait and release his hands for another activity.
The classic example Blink looks like this. Thanks to the delay function, it will work well, but we will have no time to do anything else, because the microcontroller is busy. This example can also be written using timer and interrupt.
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
Different timer modes can induce a reluctance to study the datasheet, but you really need to learn just one. It is a CTC mode, which counts gradually in the 0-OCRA interval and causes the interrupt when reaching the maximum. We'll show an example on 16-bit Timer1.
The formula for calculating the frequency is fOCXA = fclk / (1 x N x (1 + OCRXA)), where N is the value of the divider. For a desired frequency of 1 Hz this may be for example 1 = 16000000 / (1 x 1024 x (1 + 15624)).
Note that the datasheet You will read about the formula fOCXA = fclk / (2 x N x (1 + OCRXA)). However, the formula only applies to the attached table (CTC Mode, Timing Diagram). It clearly shows that interrupts occur 2 times more often and therefore we use the first formula.
I wrote two examples. This first uses pinMode and digitalWrite.
#define ledPin 13
void setup()
{
pinMode(ledPin, OUTPUT);
// initialize timer1
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 15624; // compare match register 16MHz/1024/1Hz
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= (1 << CS12) | (0 << CS11) | (1 << CS10); // 1024 prescaler
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
interrupts(); // enable all interrupts
}
ISR(TIMER1_COMPA_vect) // timer compare interrupt service routine
{
digitalWrite(ledPin, digitalRead(ledPin) ^ 1); // toggle LED pin
}
void loop()
{
// your program here...
}
The other directly handles the ports. It does exactly the same thing as the previous ones.
#define ledPin 13
void setup()
{
DDRB |= (1<<PB5);
// initialize timer1
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 15624; // compare match register 16MHz/1024/1Hz
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= (1 << CS12) | (0 << CS11) | (1 << CS10); // 1024 prescaler
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
interrupts(); // enable all interrupts
}
ISR(TIMER1_COMPA_vect) // timer compare interrupt service routine
{
PORTB ^= (1 << PB5);
}
void loop()
{
// your program here...
}
For the source code for the article, visit GitHub:
29.12.2017