PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : atmega 328P - Servomotor Steuerung



ArduUser
07.04.2016, 13:06
Hallo liebe Leute,

ich brauche mal eure Hilfe bei der Programmierung.

Ich habe einen Arduino UNO, den ich mittels C programmieren muss.

Ich weiß dass Servomotoren mit 50Hz arbeiten und mit einem PWM Signal 1 bis 2ms gesteuert werden.

Ich bringe es aber nicht zum laufen. Habe schon alles Probiert. Ich muss den Motor mittels PD5 steuern weil die anderen Pins anderweitig benötigt werden.

Hier mal mein Code. MIttels der Manuals habei ch gehofft durch verschiedene OCR0A werte den PWM beeinflussen zu können. Aber irgendwie mach ich was falsch. der Motor reagiert nicht darauf.
Vielleicht hat jemand von euch einen besseren Code, ein Example oder kann mir einen Hinweis auf meinen Fehler geben.

Vielen Dank, LG

#define F_CPU 16000000
int main( void )
{
DDRD |= (1<<PORTD5); // DataDirection Port D: Pin D5 = Output
TCCR0A|= (1<<COM0A1)| (1<<COM0B1) | (1<<WGM01) | (1<<WGM00); // Non - inverted Mode ; Fast pwm
TCCR0B|= (1<<CS02) | (1<<CS00); Prescaler 1024
while (1)
{
OCR0A=13;
delay(2000);
OCR0A=40;
delay(2000);
OCR0A=20;
delay(2000);
OCR0A=186;
delay(2000);
OCR0A=196;
delay(2000);
OCR0A=206;
delay(2000);
OCR0A=216;
delay(2000);
} // endlessly
return(0);
}

wkrug
07.04.2016, 13:59
Ich hab das letzthin bei einem ATMEGA 328PB so gemacht.
Ein 16Bit Timer wurde mit FAST PWM so eingestellt, das er beim erreichen vom ICP Wert das TCNT Register auf 0 gesetzt hat.
Der Wert für das OCR1A Register bestimmt dann die länge des Servoimpulses.
Der Ausgang des OCR muss dabei im DDR Register auch als Ausgang definiert werden.
Das ganze läuft rein In Hardware und deshalb super stabil. Andere Servoimpulslängen werden lediglich durch Beschreiben des OCRxA Registers eingestellt.

Wenn's wegen der Ports nicht in Hardware geht, kann man es auch über einen Comparematch Interrupt lösen und darin den entsprechenden Ausgang umschalten.
Im Interrupt wird dann der neue Wert für den nächsten Comparematch belegt - Also für den nächsten Impulsbeginn bzw. für die nächste Impulspause.
Sind aber schon mehrere andere Interrupts aktiv kann das zu einem Jitter bei der Impulsausgabe führen.

Als Prescaler würde ich dabei 8 wählen, dann bekommt man bei 16MHz eine Auflösung von 0,5µs und das ist für ein Servo schon sehr gut.

ArduUser
07.04.2016, 14:09
danke dir für deine Antwort.

Könntest du mir deinen Code schicken, oder hier posten.
Ich probiere schon seit Tagen da herum und bin schon ziemlich am frustrieren.

wkrug
07.04.2016, 14:47
Hier der Code für Counter 4 ist ein 328PB. Sollte nach anpassen der Register auch für Counter 1 passen.
Der Code ist für 20MHz für 16MHz müsstest Du die ICR und OCR Werte anpassen ( 1,5ms und 18,5ms, also 3000 und 37000 ).


// Timer/Counter 4 initialization
// Clock source: System Clock/8
// Clock value: 312,500 kHz
// Mode: Fast PWM top=ICR4
// OC1A output: Disconnected
// OC1B output: Disconnected
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer Period: OFF
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: OFF
// Compare B Match Interrupt: Off
TCCR4A=(1<<COM4A1) | (0<<COM4A0) | (0<<COM4B1) | (0<<COM4B0) | (1<<WGM41) | (0<<WGM40);
TCCR4B=(0<<ICNC1) | (0<<ICES1) | (1<<WGM13) | (1<<WGM12) | (0<<CS12) | (1<<CS11) | (0<<CS10);
TCNT4H=0x00;
TCNT4L=0x00;
ICR4H=0xC3;
ICR4L=0x50;
OCR4AH=0x0A;
OCR4AL=0xBE;
OCR4BH=0x00;
OCR4BL=0x00;

Durch Schreiben ins OCRxA Register kann die Impulslänge eingestellt werden.

wkrug
11.04.2016, 07:11
@ArduUser:
Und - Hast Du es ans laufen gekriegt ?

Ne Rückantwort wär halt immer schön.