kramann.info
© Guido Kramann

Login: Passwort:










kramann.info
© Guido Kramann

Login: Passwort:




Timer 1 auch als Zeitbasis nutzen ohne Interrupts

(EN google-translate)

(PL google-translate)

Eine einfache Möglichkeit, eine Zeitsteuerung für die einzelnen Prozesse des Programms zu erhalten besteht in der Nutzung eines Timer als Zähler und das Abwarten dessen Überlaufs am Ende der Main-Loop.

Im Fall hier wird der bereits für den Antrieb (PWM-Geber) verwendete Timer 1 benutzt. Dieser Timer war hier bisher so konfiguriert, dass ein 10-Bit Phasen-korrektes PWM-Signal generiert wird (Modus3, Datenblatt Seite 107). Nun hat dieses den Nachteil, dass hier der Zähler hoch- und wieder herunter zählt und somit bei einem bestimmten Zählstand nicht erkennbar ist, ob er beim Herauf- oder Herabzählen erreicht wurde.

Darum wird nun das nicht Phasen-korrekte Fast-PWM-Signal auch mit 10 Bit verwendet (Modus 7). #pdf atmega32_doc2503.pdf atmega32_doc2503.pdf - Datenblatt zum ATmega32.

Bei dem nachfolgenden Programm wird ein Blinken mit 0,5Hertz auf einer LED des Fahrzeugs erzeugt, indem für 122 Main-Loop-Durchgänge diese an und für die darauffolgenden 122 ausgeschaltet wird. Ein Main-Loop-Durchgang erfolgt dabei mit...


Zählfrequenz = 8.000.000 / (64*1024) ==  122,0703125Hz 

Da sich der PWM-Zyklus laut Datenblatt für Fast-PWM wie folgt berechnet und 
das Fahrzeut mit 8MHz getaktet ist:

Zählfrequenz = fclock / (N*(TOP+1))


Code 0-1: Berechnung der Frequenz, mit der ein Main-Durchlauf abgearbeitet wird (siehe auch nachfolgenden Quelltext).

Man beachte die Warteschleife while(TCNT1<1023) PORTB|=0; am Ende des nachfolgenden Quelltextes in der Main-Loop:
//   avr-gcc -O2 -mmcu=atmega32 syncprog.c -o syncprog.elf 
//   avr-objcopy -O ihex -j .text -j .data syncprog.elf syncprog.hex 

//   Upload über RobotLoader_20100712



#include<avr/io.h>

//   Zählfrequenz = fclock / (N*(TOP+1))
//   Zählfrequenz = 8.000.000 / (64*1024) ==  122,0703125Hz (einmal hochzählen)   ungefähr 8ms pro Schleifendurchlauf

void initialisiereMotore()
{
    DDRC |= 0b00001100;  //Richtung

    //10-Bit Phasen-korrektes PWM-Signal.
    TCCR1A = (1<<COM1A1) | (0<<COM1A0) | (1<<COM1B1) | (0<<COM1B0) | (0<<FOC1A) | (0<<FOC1B) | (1<<WGM11) | (1<<WGM10);
    TCCR1B = (0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (1<<WGM12) | (0<<CS12) | (1<<CS11) | (1<<CS10);
    DDRD |= (1<<PD5) | (1<<PD4); //auf Ausgang setzen.            
    OCR1A = 0; //PWM-Breite setzen (entspricht für Servo auf 0 Grad).
    OCR1B = 0; //PWM-Breite setzen (entspricht für Servo auf 0 Grad).
}

void fahrt(int links, int rechts)  //Wertebereich: +-1023
{
    if(links==0)    
    {
        PORTC &= ~(1<<PC2);
        OCR1B = 0;
    }
    else if(links<0)
    {
        PORTC |=  (1<<PC2);
        OCR1B = -links;
    }
    else
    {
        PORTC &= ~(1<<PC2);
        OCR1B = links;
    }

    if(rechts==0)    
    {
        PORTC &= ~(1<<PC3);
        OCR1A = 0;
    }
    else if(rechts<0)
    {
        PORTC |=  (1<<PC3);
        OCR1A = -rechts;
    }
    else
    {
        PORTC &= ~(1<<PC3);
        OCR1A = rechts;
    }

}

int main()
{
    unsigned long pause=0;
    initialisiereMotore();

    int ZAEHLER = 0;

    DDRC |= 0b01110000;

    while(1) //Durchlauf === 122,0703125Hz
    {
      /*
        for(pause=0;pause<300000;pause++)
            DDRB|=0;
        fahrt(1023,1023);  //Geradeaus

        for(pause=0;pause<300000;pause++)
            DDRB|=0;
        fahrt(0,0);  //stop

        for(pause=0;pause<300000;pause++)
            DDRB|=0;
        fahrt(200,200);  //langsame Geradeaus

        for(pause=0;pause<300000;pause++)
            DDRB|=0;
        fahrt(0,0);  //stop

        for(pause=0;pause<300000;pause++)
            DDRB|=0;
        fahrt(-1023,1023);  //Links-Drehung

        for(pause=0;pause<300000;pause++)
            DDRB|=0;
        fahrt(0,0);  //stop
     */

        ZAEHLER++;
        ZAEHLER%=244;

        //Blinken mit 0,5Hz:
        if(ZAEHLER<122) // 1 Sekunde an
        {
            PORTC |=  0b01110000;
        }
        else //dann 1 Sekunde aus.
        {
            PORTC &= ~0b01110000;
        }

 
        while(TCNT1<1023) PORTB|=0; //Immer warten, bis der Zähler den oberen Zählstand erreicht hat.
        //Der Zählvorgang ist langsam gegenüber dieser while-Schleife, so wird 1023 in jedem Fall "erwischt".
    }
}

Code 0-2: Beispielprogramm - Nur Blinken (Fahren auskommentiert) mit 0,5Hz, siehe while-Schleife in Main-Loop.

SUMOBOT3.zip - Obiges Programm als Quelltext und .hex-Datei.