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)
|
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 0-2: Hauptprogramm für Servo-Ansteuerung
Prozedurale Umsetzung
|
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 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
|
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 0-4: Prozedurales Servo-Ansteuerungsprogramm mit einer Auflösung von 1,25o