This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
| de:avr:timers [2010/07/26 21:15] – angelegt Wember | de:avr:timers [2020/07/20 12:00] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Counters/ | ||
| + | Counter, welche man auch in einigen Fällen Taktgeber nennen kann, sind einer der wichtigsten Unterfunktionen eines Microcontrollers. Diese ermöglichen es Prozesse exakt zu timen, Signale zu generieren und Ereignisse zu zählen. Ein Zähler konvertiert die Nummer der Inputzyklen in einen binären Wert mit Hilfe eines Arrays an Triggern. Die maximale Nummer der gezählten Zyklen hängt von der Länge des Arrays ab und diese ist markiert von der Länge des binären Codes. Der AVR hat 8- und 16- Bit Counter. Wenn ein Timer seinen | ||
| + | Counter unterscheiden sich auch in Applikationsfällen und Arbeitsmodi. | ||
| + | |||
| + | ===== Counter' | ||
| + | |||
| + | Im Default-Modus macht ein Counter nichts anderes, als fortlaufend Nummer zu zählen | ||
| + | Sein wert kann natürlich jederzeit ausgelesen, und von einem Programm verändert werden. | ||
| + | Die einzige zusätzliche Funktion im Default-Modus ist, dass er ein Interrupt beim Counter-Overflow verursacht. Der Default-Modus wird normalerweise benutzt, um eine Sektion eines Programms in bestimmten Intervallen laufen zulassen. | ||
| + | |||
| + | <box 100% round # | ||
| + | |||
| + | Aufgabe: Ein 8 MHz ATmega128 soll einen Interrupt alle 10ms (100 Hz) auslösen. Dafür ist der 8-Bit Counter 0 brauchbar. | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | ISR(TIMER0_OVF_vect) | ||
| + | { | ||
| + | // Gibt den Counter einen Wert, | ||
| + | // dass der nächste Overflow in 10Hz passiert. | ||
| + | // Formel: 256 - 8 MHz / 1024 / 100 Hz = 177,785 = ~178 | ||
| + | TCNT0 = 178; | ||
| + | } | ||
| + | |||
| + | int main() | ||
| + | { | ||
| + | // Um den ersten Interrupt in 10ms auszulösen, | ||
| + | // muss der Counter initialisiert werden. | ||
| + | TCNT0 = 178; | ||
| + | |||
| + | // Prescaler Wert 1024 | ||
| + | TCCR0 = 0x07; | ||
| + | |||
| + | // Erlaubt Overflow Interrupts | ||
| + | TIMSK |= (1 << TOIE0); | ||
| + | |||
| + | // Erlaubt global Interrupts | ||
| + | sei(); | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (1) continue; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Der Counter in diesem Beispiel wird den Interrupt nicht in exakt 10 ms generieren, dafür müsste man dem Counter einen Dezimalwert geben, das ist aber nicht möglich. | ||
| + | Um einen präzisen Intervall zwischen den Interrupts zu verwirklichen, | ||
| + | |||
| + | |||
| + | </ | ||
| + | |||
| + | ==== Externer Taktgeber ==== | ||
| + | |||
| + | Es ist auch möglich einen externen Taktgeber als das Taktsignals eines Counters zu nutzen. | ||
| + | Der AVR hat einen Pin " | ||
| + | Das Externe Taktsignal und die Polarität kann man im Prescaler Register auswählen. | ||
| + | |||
| + | ==== Timing events ==== | ||
| + | |||
| + | Da die Counter zeitlich abgestimmte Operationen ermöglichen, | ||
| + | Der Teil des Counter heißt "Input Capture Unit". Es gibt eine Auswahl zwischen zwei Ereignissen: | ||
| + | |||
| + | <box 100% round # | ||
| + | |||
| + | Aufgabe: Miss die Frequenz eines Externen 122Hz - 100kHz logischen Rechtecksignals mit einem 8MHz ATmega128. Die Messung soll mit einer 1 Hz-Präzision erfolgen. Das Programm nutzt einen 16-Bit Counter mit einer Input Capture Unit. | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | unsigned long frequency; | ||
| + | |||
| + | // Interrupt für das Ereignis | ||
| + | ISR(TIMER1_CAPT_vect) | ||
| + | { | ||
| + | // Counter to 0 | ||
| + | TCNT1 = 0; | ||
| + | |||
| + | // Das Ergebnis ist nur gültig wenn der Counter | ||
| + | // noch kein Overflow hatte. | ||
| + | if (!(TIFR & (1 << TOV1))) | ||
| + | { | ||
| + | // Berechnen der Frequenz von der Periode | ||
| + | frequency = (unsigned long)8000000 / | ||
| + | (unsigned long)ICR1; | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | // Frequenz ist weniger als 122Hz | ||
| + | frequency = 0; | ||
| + | |||
| + | // Setzt die Counter Overflow Flagge auf 0 | ||
| + | TIFR &= ~(1 << TOV1); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | int main() | ||
| + | { | ||
| + | // Registriert eine " | ||
| + | TCCR1B = (1 << ICES1) | (1 << CS10); | ||
| + | |||
| + | // Erlaubt Ereignis-Interrupts | ||
| + | TIMSK = (1 << TICIE1); | ||
| + | |||
| + | // Erlaubt global Interrupts | ||
| + | sei(); | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (1) continue; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Das Programm löst jedes mal bei einer " | ||
| + | Während des Interrupts, überprüft das Programm den Counter auf einen Overflow - dass kann passieren wenn die Frequenz des Signals unter 122Hz (8 MHz / 2< | ||
| + | </ | ||
| + | |||
| + | Events erfassen und die Zeit registrieren die es brauchte damit das Event auftrat kann auf Software Level abgehandelt werden. Es ist möglich einen externen oder andere Interrupts zu nutzen und den Wert des Counters während des Events auszulesen. Das Erfassen auf Hardwarelevel wird genutzt um unabhängig vom Hauptprogramm zu arbeiten und sehr kurze (oder häufige) Events zu timen. | ||
| + | |||
| + | |||
| + | ===== Taktsignal generieren ===== | ||
| + | |||
| + | Komplexere Counter können ein Taktsignal generieren, zusätzlich zum Timen eines Signals. Dafür hat der Counter eine " | ||
| + | Ein Interrupt kann generiert werden und spezielle Pin Werte können geändert werden wenn der Counter Wert gleich der des Compare Unit Registers ist. In diesem Moment kann ein Pin entweder High oder low gesetzt oder invertiert werden. Das Signal wird durch Änderungen im Wert des Output-Pins generiert. | ||
| + | |||
| + | In einigen Signal-generierenden Modi, kann der maximale Wert des Counters verändert werden. | ||
| + | Die physikalische Größe bleibt die gleiche, aber ein Vergleichsregister wird benutzt um den Counter bei einem bestimmten Wert zu resetten. | ||
| + | Das vorherige Beispiel kann auch mit dieser Methode gelöst werden, aber die Funktion ist eher für das Ändern der Periode des Signals gedacht. Zusätzlich kann ein Counter so eingestellt werden, dass er mit auf- oder absteigenden Werten arbeitet. | ||
| + | |||
| + | Der Counter und die Signal-generierenden Modi die diese nutzten sind einer der komplexesten Peripheriemodule in einem AVR. Über jeden hier zu schreiben würde eine große Zeitverschwendung sein, normalerweise gibt es keinen Grund alles zu wissen, um sie zu nutzen. Der folgende Absatz beschreibt einer der üblichen PWM Signale in den Robotics. Der Rest kann den AVR Dokumentationen entnommen werden. | ||
| + | |||
| + | ==== Pulse Width Modulation ==== | ||
| + | |||
| + | Pulsweitenmodulation (PWM) ist ein Typ eines Signals, wo die Frequenz und die Periode(normalerweise) konstant sind, aber die Länge der Halb-Periode ändert sich. PWM Signale werden benutzt um elektromechanische, | ||
| + | Zum Beispiel, ein Servomotor nutzt ein ein 50Hz PWM Signal und haben einen hohe Halbperiode von 1 - 2 ms. | ||
| + | |||
| + | <box 100% round # | ||
| + | |||
| + | Aufgabe: Generiere mit einem 8Mhz ATmega128, zwei Geschwindigkeits-regulierende Servomotor Signale. Nutze Pin PB5 (OC1A) um eine Pulsweite von 1ms zu generieren und Pin PB6 (OC1B) um eine Pulsweite von 2ms zu generieren. | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | |||
| + | int main() | ||
| + | { | ||
| + | // Set pins as outputs | ||
| + | DDRB |= (1 << PIN5) | (1 << PIN6); | ||
| + | |||
| + | // Set outputs A and B low for comparison, | ||
| + | // "Fast PWM" mode, prescaler value 8 | ||
| + | TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); | ||
| + | TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); | ||
| + | |||
| + | // Maximum value of the counter. Formula: | ||
| + | // TOP = 8 MHz / 8 / 50 Hz | ||
| + | ICR1 = 20000; | ||
| + | |||
| + | // Half-period of the first motor is 1 ms, and second 2 ms | ||
| + | OCR1A = 1000; | ||
| + | OCR1B = 2000; | ||
| + | |||
| + | // Endless loop | ||
| + | while (1) continue; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | </ | ||