kramann.info
© Guido Kramann

Login: Passwort:










Mikrocontroller
1 Einfuehrung
..1.1 Entwicklungsgeschichtliches
..1.2 Maschinensprache
..1.3 Assemblerbeispiel
..1.4 Sprachwahl
..1.5 Praxis
....1.5.1 Digital_IO
....1.5.2 Byteoperationen
....1.5.3 AVR_Studio
....1.5.4 Testboard
....1.5.5 Aufgaben
....1.5.6 Do_it_yourself
......1.5.6.1 Ampel
......1.5.6.2 Programmierer
..1.6 Literatur
..1.7 Programmierer
....1.7.1 Bauverlauf
....1.7.2 KurzreferenzLow
....1.7.2 Kurzreferenz_16PU
..1.8 Uebung1
..1.9 BoardAtHome
....1.9.1 Software
....1.9.2 Hardware
....1.9.3 Knoppix
....1.9.4 Aufbau
....1.9.5 LED
2 Oszillator
..2.1 Assembler
..2.2 Interner_RC
..2.3 Quarz
..2.4 Taktgenerator
3 DigitalIO
..3.1 Elektrische_Eigenschaften
..3.2 Pullup_Widerstaende
..3.3 Bitmasken_Eingang
..3.4 Bitmasken_Ausgang
..3.5 Tic_Tac_Toe
....3.5.1 DuoLEDs
....3.5.2 Schaltplan
....3.5.3 Spielfeld
....3.5.4 Anwahl
....3.5.5 Kontrolle
..3.6 Laboruebung2
..3.7 Laboruebung2_alt
4 PWM
..4.1 Prinzip
..4.2 Nutzen
..4.3 Generierung
..4.4 Programmierung
..4.5 Servos
..4.7 Laboruebung3
..4.8 LoesungUE3
..4.9 Uebung6
5 LichtKlangKugeln
..5.1 LED
..5.2 RGB
..5.3 Sensoren
..5.4 lautsprecher
..5.5 tonerzeugung
6 UART
..6.1 Bussysteme
..6.2 UART
..6.3 RS232
..6.4 Hardware
..6.5 Senden
..6.6 Hyperterminal
..6.7 Empfangen
..6.8 Broadcast
..6.9 Uebung4
7 Infrarot
..7.1 schalten
..7.2 seriell
..7.3 Uebung
8 OOP
..8.1 Probleme
..8.2 Konzept
..8.3 Statisch
..8.4 Datentypen
..8.5 RS232
....8.5.1 Prozedural
....8.5.2 Analyse
....8.5.3 Umsetzung
....8.5.4 Vererbung
....8.5.5 Statisch
....8.5.6 Performance
..8.6 Fahrzeug
9 ADW
..9.1 ADW
..9.2 Zaehler
10 Peripherie
..10.1 RS232Menue
..10.2 ASCIIDisplay
..10.3 Tastenmatrix
..10.4 Schrittmotor
..10.5 Zaehler
..10.6 Uebung7
11 SPI
..11.1 Testanordnung
..11.2 Register
..11.3 Test1
..11.4 Test2_Interrupt
..11.5 Test3_2Slaves
..11.6 Laboruebung
12 EEPROM
13 I2C
..13.1 MasterSendByte
..13.2 MasterSend2Bytes
..13.3 MasterReceiveByte
..13.4 MasterReceive2Bytes
14 Anwendungen
..14.1 Mechatroniklabor
....14.1.1 Biegelinie
....14.1.2 Ausbruchsicherung
....14.1.3 Einachser
....14.1.4 AV
....14.1.5 Vierradlenkung
....14.1.6 Kommunikation
..14.2 Sinuserzeugung
....14.2.1 Variante1
....14.2.2 Variante2
....14.2.3 Variante3
....14.2.4 Variante4
..14.3 Laboruebung8
..14.4 Loesung_Ue8
..14.5 SPI_Nachtrag
20 Xubuntu

4.8 Lösung zu Laborübung 3: Ansteuern eines Servos

BILDBESCHREIBUNG

Bild 4.8-1: Servo

  • Bei der Laborübung 5 sollte der Timer 0 so konfiguriert werden, dass das entstehende PWM-Signal geeignet dazu ist, einen Servo anzusteuern.
  • Im Anschluß sollten die Taster an PB0 und PB1 so verwendet werden, dass ohne Betätigen der Taster der Servo in Mittelstellung steht, er bei Betätigen von Taster PB0 in Position -450 und bei Betätigen von Taster PB1 in Position +450 geht.

Einstellen der richtigen PWM-Frequenz

  • Das vom Timer erzeugte Phasen- und Frequenz-korrekte PWM-Signal ist eine Rechteckschwingung einer festen Frequenz.
  • Der Servo kann nur PWM-Signale verarbeiten, die eine Periodendauer im Bereich 10 bis 20ms haben.
  • Dies entspricht einer für das PWM-Signal geforderten Frequenz zwischen 50Hz und 100Hz (Kehrwert der Perioden: 10ms = 0,01s 1/0,01 = 100Hz).
  • Im Datenblatt auf Seite 75 ist als Formel zur Bestimmung der PWM-Frequnz die Formel fpwm=fclk/(N*510) angegeben.
  • Bei einer Taktrate von fclk=9216000Hz (Quarztakt) folgt für eine gewünschte PWM-Frequenz von 75Hz: N = 9216000/(510*75) = 240,94
  • Der an diesem N am nächsten liegende realisierbare Wert ist eine Teilung von N=256.
  • Im Datenblatt auf Seite 79/80 ist ablesbar, wie die Vorteilung N über die Bits CS02 CS01 CS00 im Register TCCR0 eingestellt werden kann.
  • Nachfolgende Tabelle gibt diese Tabelle in Teilen wieder und zeigt gleich die resultierende PWM-Frequenz bei dem verwendeten Systemtakt von 9,216MHz:
N     CS02 CS01 CS00   Frequenz bei 9216000Hz Taktfrequenz
1       0    0    1    18070,59Hz
8       0    1    0     2258,82Hz
64      0    1    1      282,35Hz
256     1    0    0       70,59Hz geeignet für Servo-Ansteuerung
1024    1    0    1       17,65Hz
 

Code 4.8-1: Vorteilung N, Konfiguration von N über CS02 CS01 CS00 und die sich ergebende PWM-Frequenz bei einem Systemtakt von 9216000Hz

Realisierung der Winkelstellungen

  • Nun muß noch bestimmt werden, welche Breite des High-Pegels bei dem PWM-Signal eingestellt werden muß, um die geforderten Winkelstellungen zu erreichen.
  • Es ist keineswegs so, dass diese Breite zwischen 0 und 100% der Gesamt-PWM-Periode liegen kann.
  • Vielmehr sagen Herstellerangaben, dass für -45o die Breite des High-Pegels bei 1ms liegen soll, für 0o bei 1,5ms und für +45o bei 2ms.
  • In unserem Programm können wir für zur Einstellung der Breite des High-Pegels einen Wert zwischen 0 und 255 dem Register OCR0 zuweisen.
  • Der Zusammenhang zwischen der Belegung von OCR0 und der Breite des High-Pegels ist linear.
  • OCR0 = 0 heißt: Breite 0%.
  • OCR0 = 0 heißt: Breite 100%, also die ganze Periode einer PWM-Schwingung.
  • Die Periodendauer der PWM-Schwingung für den gewählten Vorteiler N=256 ergibt sich als Kehrwert der PWM-Frequenz:
  • Tpwm = 1/fpwm = (510*256)/9216000 = 0,01416666...s
  • Durch Erhöhen con OCR0 wird der High-Pegel Thigh um 1/255-igstel von Tpwm länger, oder als Formel ausgedrückt:
  • Thigh = OCR1*(2*256)/9216000 s
  • Um für die Mittelstellung Thigh = 1,5 Millisekunden einzustellen, errechnet sich damit für OCR1: OCR1 = 9216000*0,0015/512 = 27.
  • Analog für -45o bzw. Thigh = 1,0 Millisekunden: OCR1 = 9216000*0,001/512 = 18.
  • Und für +45o bzw. Thigh = 2,0 Millisekunden: OCR1 = 9216000*0,002/512 = 36.
BILDBESCHREIBUNG

Bild 4.8-2: PWM-Signal für Servo, hier zu Stellung 0o

Objektorientierte Umsetzung

  • In Kapitel 8.4 wird die Klasse PWMtimer0 entwickelt, die den Timer 0 als PWM-Geber verwendet.
  • Nach Erzeugen eines Objektes von PWMtimer0 und Aufruf der Objektmethode start(), wird ein Frequenz- und Phasenkorrektes PWM-Signal auf Pin 4 (PB3 / OC0) ausgegeben, dessen Breite mit der Objektmethode setzePulsbreitePin4(...) eingestellt werden kann.
  • In der in Kapitel 8.4 gegebenen Variante der Klasse PWMtimer0, wird eine Vorteilung N von 64 verwendet. Dies muß auf N=256 geändert werden. Ansonsten kann die Klasse genau so benutzt werden.
  • Die modifizierte Methode start() lautet dann:
        void start()
        {
            TCCR0 = (0<<FOC0) | (1<<WGM00) | (1<<COM01) | (0<<COM00) | (0<<WGM01) | (1<<CS02) | (0<<CS01) | (0<<CS00);
            DDRB |= (1<<PB3); //auf Ausgang setzen.            
            OCR0 = 0; //PWM-Breite auf Null setzen.
        }
 

Code 4.8-1: Modifizierte Methode start() mit Vorteilung N = 256 (CS02=1 CS01=0 CS00=0)

  • Das Hauptprogramm verwendet diese modifizierte Klasse und fällt dadurch sehr kurz aus. Es implementiert außerdem die Reaktion auf die Taster:
servo.zip - Projekt zur Servoansteuerung mit Hauptprogramm und der modifizierten Klasse PWMtimer0.
#include <avr/io.h>
#include "PWMtimer0.h"

int main(void)
{
    PWMtimer0 pwm0;
    uint8_t akku;

    DDRB = 0b00001000;
    DDRC = 0b11111111;

    pwm0.start();

    while(true)
    {
        akku = PINB;
        if( (akku & 0b00000011) == 1) //Taster PB0 gedrückt
        {
            PORTC = 0;
            pwm0.setzePulsbreitePin4(18); //Servo auf -45Grad
            while( (akku & 0b00000011) == 1)
                akku = PINB;
        }
        else if( (akku & 0b00000011) == 2) //Taster PB1 gedrückt
        {
            PORTC = 2;
            pwm0.setzePulsbreitePin4(36); //Servo auf +45Grad
            while( (akku & 0b00000011) == 2)
                akku = PINB;
        }
        else
        {
            PORTC = 1;
            pwm0.setzePulsbreitePin4(27); //Servo auf +45Grad
        }
    }
    return 0;
}
 

Code 4.8-2: Hauptprogramm für Servo-Ansteuerung

Prozedurale Umsetzung

  • Zur leichteren Orientierung soll im folgenden das gleiche Programm prozedural umgesetzt dargestellt werden:
servo_proz.zip - Prozedurales Projekt zur Servoansteuerung mit Hauptprogramm und der modifizierten Klasse PWMtimer0.
#include <avr/io.h>
int main(void)
{
    uint8_t akku;

    DDRB = 0b00001000;
    DDRC = 0b11111111;

    TCCR0 = (0<<FOC0) | (1<<WGM00) | (1<<COM01) | (0<<COM00) | (0<<WGM01) | (1<<CS02) | (0<<CS01) | (0<<CS00);
    DDRB |= (1<<PB3); //auf Ausgang setzen.            
    OCR0 = 0; //PWM-Breite auf Null setzen.

    while(true)
    {
        akku = PINB;
        if( (akku & 0b00000011) == 1) //Taster PB0 gedrückt
        {
            PORTC = 0;
            OCR0=18; //Servo auf -45Grad
            while( (akku & 0b00000011) == 1)
                akku = PINB;
        }
        else if( (akku & 0b00000011) == 2) //Taster PB1 gedrückt
        {
            PORTC = 2;
            OCR0=36; //Servo auf +45Grad
            while( (akku & 0b00000011) == 2)
                akku = PINB;
        }
        else
        {
            PORTC = 1;
            OCR0=27; //Servo auf +45Grad
        }
    }
    return 0;
}
 

Code 4.8-1: Prozedurale Umsetzung des Servo-Programms

Programmverbesserung: Verfeinerte Winkelauflösung

  • In der vorangestellten Version des Programms darf OCR0 Werte zwischen 18 und 36 annehmen.
  • Dies ergibt nur 19 mögliche Positionen, bzw. 18 Schritte und damit eine Winkelschrittweite in dem Bereich 90o von 5o.
  • Timer 0 und Timer 2 sind 8-Bit-Timer, wogegen Timer 1 ein 16-Bit-Timer ist, mit dem u.a. auch ein 10-Bit Phasenkorrektes PWM-Signal erzeugt werden kann.
  • Dies soll im folgenden geschehen.
Erarbeitung einer 10 Bit PWM Servoansteuerung mit Timer1 aufgrund des Datenblattes.


Phasen- und Frequenz korrektes 10-Bit-PWM:
Bits:    WGM13 WGM12 WGM11 WGM10
Belegung:  0     0     1     1

TOP = 03FF16 = 1023

fpwm = fclk/(2*N*TOP)

=> N = 64

fpwm = 9216000/(2*64*1023) = 70,381Hz

=>

Vorteilung N=64:
Bits:      CS12 CS11 CS10
Belegung:    0    1    1


TCCR1A = (1<<COM1A1) | (0<<COM1A0) | (1<<COM1B1) | (0<<COM1B0) | (0<<FOC1A) | (0<<FOC1B) | (1<<WGM11) | (1<<WGM10);
TCCR1B = (0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (1<<CS11) | (1<<CS10);

Timer 1 kann zwei PWM-Signale gleichzeitig mit unterschiedlichen Pulsbreiten aber gleicher
Frequenz erzeugen:

Betroffene Pins: 18 (PD4/OC1B) 19 (PD5/OC1A)

PWM-Breite mit 16-Bit Registern
OCR1A und OCR1B einstellen.

Die Breite kann hier von 0..1023 eingestellt werden.
Zuordnungen:
Periodendauer T = 1/fpwm = 0,014208333 s
1/1023 Periode: 0,0000138889 s
1ms benötigt darum eine Einstellung der Pulsbreite auf 72,
2ms auf 144
1,5ms auf 108

Damit ergibt sich die Möglichkeit 73 Positionen anzufahren, was einer Auflösung von 90/72 = 1,25o entspricht.
 

Code 4.8-3: Einstellungen suchen

Prozedurales Programm zur feineren Winkelauflösung

  • Die 73 Positionen können inkrementell mit den Tastern angefahren werden und werden im Display angezeigt.
servo_proz_fein.zip - Projekt zu Servoansteuerung mit feinerer Auflösung.
#include <avr/io.h>
int main(void)
{
    uint8_t akku;
    uint16_t position = 108;


    DDRB = 0b00000000;
    DDRC = 0b11111111;

    TCCR1A = (1<<COM1A1) | (0<<COM1A0) | (1<<COM1B1) | (0<<COM1B0) | (0<<FOC1A) | (0<<FOC1B) | (1<<WGM11) | (1<<WGM10);
    TCCR1B = (0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (1<<CS11) | (1<<CS10);
    DDRD |= (1<<PB5) | (1<<PB4); //auf Ausgang setzen.            
    OCR1A = position; //PWM-Breite setzen (entspricht für Servo auf 0 Grad).
    OCR1B = position; //PWM-Breite setzen (entspricht für Servo auf 0 Grad).
    PORTC = position;

    while(true)
    {
        akku = PINB;
        if( position<144 && (akku & 0b00000011) == 1) //Taster PB0 gedrückt
        {
            position++;
            PORTC = position;
            OCR1A=position; 
            OCR1B=position; 
            while( (akku & 0b00000011) == 1)
                akku = PINB;
        }
        else if( position>72 && (akku & 0b00000011) == 2) //Taster PB1 gedrückt
        {
            position--;
            PORTC = position;
            OCR1A=position; 
            OCR1B=position; 
            while( (akku & 0b00000011) == 2)
                akku = PINB;
        }
    }
    return 0;
}
 

Code 4.8-4: Prozedurales Servo-Ansteuerungsprogramm mit einer Auflösung von 1,25o