Timer

Table of Contents

Timer

Begriffe

Output Compare Units

Double Buffered Register

Clear Timer on Compare Match

PWM (pulse width modulation)

Fast PWM (Asymmetric PWM)

Glitch Free, Phase Correct PWM (Symmetric PWM)

8-Bit Timer

Output Compare Match / Waveform Generator

Double Buffering

Erzeugen von Timings

Auto Reload: CTC (clear timer on compare match)

PWM

Timer1 16Bit

Input Capture (Timer1 only)

Timer Counter ATMEGA328p

Qellen

Begriffe

Timer/Counter
Prescaler
Multiplexer

Output Compare Units

Double Buffered Register

Clear Timer on Compare Match

PWM (pulse width modulation)

Mit PWM lassen sich analoge Spannungen erzeugen. Das Verhältinis von Pulsdauer zu Periodendauer bestimmt die erzeugte Gleichspannung. Die Gleichspannung ist der Mittelwert des Digitalsignals und kann durch ein einfaches RC-Glied erzeugt werden. Je geringer die Welligkeit, desto länger dauert es, bis sich der Gleichspannungswert einstellt.

Image2

Fast PWM (Asymmetric PWM)

Glitch Free, Phase Correct PWM (Symmetric PWM)

man sieht: symmetrisch/asymmetrisch bezogen auf die Mitte der Periode.

Beim Umschalten auf ein neues Puls/Pause-Verhältnis erzeugt die symmetrische Variante weniger Oberwellen (Störungen, Glitches) weil der Abstand der Pulse konstant bleibt, bei der asymmetrischen PWM ändert sich der Abstand der Pulse, das macht sich als Störung im Analogsignal bemerkbar.

 

8-Bit Timer

Definition

BOTTOM: Zählerstand 0

MAX: Zählerstand 0xFF

TOP:  höchster Zählerstand; normalerweise TOP=MAX,
                     aber es kann auch TOP=OCR0A eingestellt werden.

Betriebsarten

 

Register

 

 

 

Mögliche Interrupt Flags:

 

Signale an den Zähler:

 

 

 

Der Zähler zählt bis 255 und läuft dann auf 0 über. Dabei setzt er ein Overflow-Flag und fordert einen Interrupt an. Wenn der Interrupt erlaubt ist wird die zugehörige ISR (Interrupt Service Routine) angesprungen.

Getaktet wird der Zähler (Timer1)  extern oder intern und über die Flags TCCR1.CS12, TCCR1.CS11 und TCCR1.CS10 geteilt.

Image1

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

int main(void)
{
TIMSK |= (1<<TOIE0);  // Timer 0 overflow erlauben
TCCR0 = (1<<CS01); // Prescaler 8, Timer starten
sei();

while(1)
{

}
}

ISR (TIMER0_OVF_vect)
{
 // ein Overflow ist aufgetreten

}

 

 

 

Beispiel: erzeuge einen Takt von ca. 1ms

 

 

mit dem Prescaler von 64 ergeben sich alle 1,024ms ein Overflow

 

#include <avr/io.h>

#include <avr/interrupt.h>

 

int main(void)

{

TIMSK0 |= (1<<TOIE0);  // Timer 0 overflow erlauben

TCCR0B = (1<<CS01)|(1<<CS00); // Prescaler 64

sei();

while(1)

{ volatile int dummy;

}

}

 

ISR (TIMER0_OVF_vect)

{

// ein Overflow ist aufgetreten

 

 

 

 

 

Beispiel: Toggle ca. alle 1ms den Pin PC0 (fosc=1MHz)

Tosc=1us → 1000 Zyklen → Prescaler = 8 → 1000/8= 125 Zyklen

Treload = 256-125=131

In der Praxis ergibt sich ein Fehler von ca. 15us dadurch, dass der Einsprung in die Serviceroutine sowie die Abarbeitung der Serviceroutine jeweils ein paar Zyklen brauchen.  (Reloadwert=130 passt besser)

 

#include <avr/io.h>

#include <avr/interrupt.h>

int main(void)

{

TIMSK0 |= (1<<TOIE0);  // Timer 0 overflow erlauben

TCCR0B = (1<<CS01); // Prescaler 8, Timer starten

sei();

while(1);

}

 

ISR (TIMER0_OVF_vect)

{

TCNT0 = 131;

}

Output Compare Match / Waveform Generator

Begriffe:

Bild7

 

Double Buffering

Doppelte Pufferung: die CPU greift auf das Schattenregister von OCR0x.
Normalbetrieb: die CPU greift direkt auf OCR0x zu.

Doppelte Pufferung synchronisiert das Update der OCR0x Register zu TOP bzw. BOTTOM der Zählsequenz. Dies verhindert unsymmetrische PWM Signale => Glitch-Free Output d.h. wenn man das OCR0x Register ändert wird es nicht sofort gesetzt, sondern erst nachdem z.B TOP erreicht wurde.

 

Erzeugen von Timings

Am Pin PB0 soll folgendes Timing erzeugt werden:

Bild2

Idee: der Timer wird mit einem Wert geladen, so dass er nach 5ms überläuft. Dies löst einen Interrupt aus. In der ISR wird der Wert auf 3ms umgestellt usw.

Taktrate des Oszillators: 16MHz   Tosc=62.5ns:  Überlauf beim Zählerstand 255 d.h. nach 256 Zyklen, also alle 256*62.5ns = 16µs. Viel zu schnell. Wenn man den Takt herunterteilt ergeben sich:

Teiler

Periode des Taktes

Überlauf nach 256 Zyklen

1

62.5ns

16µs

8

500ns

128µs

64

4µs

1.024ms

256

16µs

4.096ms

1024

64µs

16.384ms

Man sieht: für ein Timing von 5ms eignet sich bei 8Bit und 16MHz nur der Teiler 1024. Ein Zählschritt dauert dann 64µs. Die gewünschten 5ms entsprechen daher 78.125 Taktperioden. Das Timing ist also nicht genau erreichbar.

Der Zähler wird nicht bei Null, sondern so gestartet, dass er nach 5ms überläuft. Der Wert dafür (preload value) ist 256-78 = 178.

Nachteil dieser Methode: das Laden der Timer in der ISR benötigt zusätzliche Rechenzeit und ändert daher das Timing leicht.

#define F_CPU 16000000
#include <avr/io.h>
#include <avr/interrupt.h>

#define LED 0
#define PRELOAD_5MS 0x100 - 78
#define PRELOAD_3MS 0x100 - 47     //Timer overflow after 3 ms @16MHz

void setup();
int main(void){

    setup();
    sei();
while(1);

}
void setup(){
// div 1024 ==> CS0=5
TCCR0B |=_BV(CS02)|_BV(CS00);
TIMSK0 |= _BV(TOIE0); //int enable
DDRB |= _BV(LED);
}

ISR(TIMER0_OVF_vect){
PORTB ^= _BV(LED); //Toggle Pin
if (PORTB & _BV(LED))
 TCNT0 = PRELOAD_5MS;   //no need to stop counter (8bit operation)
else
 TCNT0 = PRELOAD_3MS;
}

Auto Reload: CTC (clear timer on compare match)

 

  1. Bild3Register OCR0A setzen

  2. Wenn der Zählerstand den Wert OCR0A erreicht hat und überläuft, wird wahlweise ein Pin (OC0A) gesetzt (Null, Eins, Toggle) und/oder ein Interrupt ausgelöst

  3. Die Pins OC0A (bzw. OC0B) müssen als OUTPUT konfiguriert werden.

 

 

Beispiel: alle 8192us soll der Ausgang OC0A toggeln: fosc=16MHz

#include <avr/io.h>

#include <avr/interrupt.h>

 

void setup(){

DDRD=(1<<PORTD6);  //OC0A pin is output

TCCR0A |= (1<<COM0A0);  // toggle OC0A Pin (PIND6)  

      TCCR0A |= (1<<WGM01);   // CTC Mode

TCCR0B=(1<<CS02) | (1<<CS00); // prescal 1024

TCNT0=0x00;

OCR0A=0x7F;  // nach T=62.5ns*1024*128 = 8192ms compare match

// Timer/Counter 0 Interrupt(s) initialization

TIMSK0 |= (1<<OCIE0A) | (1<<TOIE0);

}

 

int main(void){

setup(); sei(); while (1);

}

 

ISR(TIMER0_OVF_vect) {

// never reached

volatile static int i; i++;

}

 

ISR(TIMER0_COMPA_vect){

// count the compare matches

volatile static int i; i++;

}

PWM

Image31. FAST PWM 3 (WGM01=WGM00=1 in Register TCCR0A)

2. Non-Inverting Mode (COM0A1=1  in Register TCCR0A)

3. Compare Register (OCR0A) als Schaltschwelle setzen

4 Timer starten (Bit CS00 in Register TCCR0B setzen)

Interrupt

1. erlauben (Bit OCIE0A in Register TIMSK0 setzen)

2. ISR(TIMER0_COMPA_vect){}

3. sei()

 

#include <avr/io.h>

#include <avr/interrupt.h>

 

void setup(){

DDRD=(1<<PORTD6);  //OC0A pin is output

TCCR0A |= (1<<WGM01)|(1<<WGM00);   // Fast PWM Mode

TCCR0A |= (1<<COM0A1);  // noninverting PWM (PIND6)

TCCR0B=(1<<CS00); // prescal 1

OCR0A=256/2;  // 50% duty cycle

// Timer/Counter 0 Interrupt(s) initialization

TIMSK0 |= (1<<OCIE0A) | (1<<TOIE0);

}

 

int main(void){

setup(); sei(); while (1);

}

 

ISR(TIMER0_OVF_vect) {

// timer overflow interrupt service routine

}

 

ISR(TIMER0_COMPA_vect){

// compare match

}

Timer1 16Bit

Input Capture (Timer1 only)

Timer Counter ATMEGA328p

Bild4

 

Qellen

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR

Template für ATMEL Studio 6.2 Counter0.zip