Lösung zu Laborübung 3: Ansteuern eines Servos
Bild 0-1: Servo
|
Einstellen der richtigen PWM-Frequenz
|
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 0-1: Vorteilung N, Konfiguration von N über CS02 CS01 CS00 und die sich ergebende PWM-Frequenz bei einem Systemtakt von 9216000Hz
Realisierung der Winkelstellungen
|
Bild 0-2: PWM-Signal für Servo, hier zu Stellung 0o
Objektorientierte Umsetzung
|
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 0-1: Modifizierte Methode start() mit Vorteilung N = 256 (CS02=1 CS01=0 CS00=0)
|
#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 0-2: Hauptprogramm für Servo-Ansteuerung
Prozedurale Umsetzung
|
#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 0-1: Prozedurale Umsetzung des Servo-Programms
Programmverbesserung: Verfeinerte Winkelauflösung
|
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 0-3: Einstellungen suchen
Prozedurales Programm zur feineren Winkelauflö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 0-4: Prozedurales Servo-Ansteuerungsprogramm mit einer Auflösung von 1,25o