Hallo Leute,
ich habe ein kleines Problem bei der Servo Programmierung oder
vielleicht auch einfach nur ein Verständnisproblem. Ich benutze einen
Amtel Mega 32 und das AVR Studio.
Ich will mit Hilfe von 2 Tastern den Servo Links bzw. Rechts herum
steuern lassen. Die Taster funktionieren! Das Problem ist der Servo, der
sich immer nur um ungefähr 45 grad dreht und das halt nur auf der
rechten oder linken Seite des Motors. Ich kriege es nicht hin den Servo
genau auf einen Winkel anzusteuern.
Der Servo ist an BIT 7 von PORT C angeschlossen.
In diesem Programm dreht sich der Servo auf der Rechten hälft des
Motors(von Mittelpunkt aus gesehen), bei betätigung von Taster 1 (BIT6)
Linksherum und von betätigung des Tasters 2 (BIT7) Rechts herum. Jeweils
45 Grad! Ab und zu kommt es vor, das ein Taster nicht wirkt bzw. der
Motor nur kurz zuckt!
CODE:
1
#include<avr/io.h>
2
#include"../cpu/cpu.h"
3
#include<util/delay.h>
4
5
voidInit();
6
voidFlashLed(unsignedcharbit);
7
8
#define PORT_LED PORTC
9
#define DDR_LED DDRC
10
#define BIT7 7
11
#define BIT0 0
12
13
14
#define PORT_TASTER PORTA
15
#define DDR_TASTER DDRA
16
#define BIT6 6
17
#define BIT7 7
18
19
intTaster(inttnum)
20
{
21
if(((~PINA)&(1<<tnum)))
22
{
23
delay_ms(1000);
24
25
if(((~PINA)&(1<<tnum)))
26
{
27
return1;
28
}
29
}
30
return0;
31
}
32
33
//*****Hauptprogramm*******
34
intmain()
35
{
36
Init();
37
38
while(1){
39
//Drücken taste 1
40
while(!Taster(BIT6));
41
{
42
43
//LED Ein
44
DDR_LED|=(1<<BIT0);
45
PORT_LED&=~(1<<BIT0);
46
47
48
//SERVO
49
PORT_LED|=(1<<7);
50
_delay_us(2000);
51
PORT_LED&=~(1<<7);
52
delay_ms(18);
53
}
54
55
56
//Drücken taste 2
57
while(!Taster(BIT7));
58
{
59
//LED aus
60
PORT_LED|=(1<<BIT0);
61
62
63
64
//SERVO
65
PORT_LED|=(1<<7);
66
_delay_us(1500);
67
PORT_LED&=~(1<<7);
68
delay_ms(19);
69
70
71
}
72
73
}
74
return0;
75
}
76
77
//Bit anders herum setzten!
78
voidInit()
79
{
80
DDR_LED|=(1<<7)|(1<<BIT0);
81
PORT_LED|=(1<<7)|(1<<BIT0);
82
DDR_TASTER&=~((1<<BIT7)|(1<<BIT6));
83
PORT_TASTER|=((1<<BIT7)|(1<<BIT6));
84
}
Würde mich freuen, wenn ihr mir bei diesem Problem weiterhelfen könnt!
Mit freundlichen Grüßen
mr_desmond
p.s. Die Tutorials auf Microkontroller.net, zu diesem Thema habe ich mir
schon angeguckt und verstehe diese eher nicht!
Hast du denn mal kontrolliert ob _delay_us / delay_ms richtig
funktioniert ?
(Led an, eine Sekunde warten, Led aus - Zeit messen)
AVR-GCC-Tutorial - 11 Warteschleifen (delay.h)
Also von der delay_ms weiß ich, das diese funktioniert!
bei der delay_us bin ich mir nicht sicher!
@anigav Kann das sein, dass ich ein Denkfehler habe? Weil das ist doch
ne PWM oder? Wobei ich mir bei der Delay_us nicht sicher bin, wenn ich
die beiden auf 1500 stelle, so wie auf einem Beispielprogramm von
Microkontroller.net
""""""
1
PORTB|=(1<<PB1);
2
_delay_us(1500);// in den 1500 steckt die Lageinformation
3
PORTB&=~(1<<PB1);
4
5
_delay_ms(18);// ist nicht kritisch
6
}
dann funktioniert dies auch machmal nicht richtig und bleib auch auf
einer Hälfte des Servos stecken!
theoretisch ist das eine PWM.
Aber die Megas haben auch einen Timer, mit dem man sehr komfortabel eine
PWM erzeugen kann. Und man muss sich nicht ständig um das richtige
Timing kümmern.
Lies dir mal
http://www.mikrocontroller.net/articles/Modellbauservo_Ansteuerung
durch, besonders "Signalerzeugung für 1 Servo mittels Timer (C)"
Also erstmal Dnake für die schnelle antwort!
Den Artikel habe ich schon einmal gelesen aber ich kriege es nicht hin
diese Programm so abzuändern, dass mein Servo sich per Taster sich
bewegt!
Was müsste ich an diesem Programm ändern, wenn ich den Servo an PORTC
BIT7 angelegt habe? Und dieser sich zumindest bewegen soll? Irgenwie
steige ich dort nicht hindurch!
Michael Klink schrieb:> In diesem Programm dreht sich der Servo auf der Rechten hälft des> Motors(von Mittelpunkt aus gesehen), bei betätigung von Taster 1 (BIT6)> Linksherum und von betätigung des Tasters 2 (BIT7) Rechts herum. Jeweils> 45 Grad!
Ist doch auch kein Wunder. Du veränderst ja in dem Programm deine
Pulsweite nirgends. Du gibst immer nur zwei Möglichkeiten vor, nämlich
1,5 ms (entspricht Mitte) und 2 ms (entspricht 45° rechts). Warum sollte
der Servo also je irgendeine andere Position annehmen?
mr_desmond schrieb:> Die Taster Funktion funktioniert! auch an LEDs usw. ich habe nur das> Problem der mit dem Servo Code!
Ok, aber sowas sieht halt schon sehr danach aus, als ob es nicht so
gedacht sei:
Michael Klink schrieb:> while (!Taster(BIT6));> {
Die geschweifte Klammer läßt vermuten, daß du den Code danach innerhalb
der Schleife ausführen willst, aber das Semikolon führt dazu, daß das
eben nicht so ist. Wozu dann aber die Klammer?
Das führt auch dazu, daß dein Programm so lange komplett stehen bleibt
(und damit auch gar keine PWM generiert), wie Taster(BIT6) bzw.
Taster(BIT7) nicht gesetzt ist, und innerhalb der Funktion Taster()
blockierst du das Programm auch für eine Sekunde. Die PWM muß aber
eigentlich dauerhaft anliegen. Die PWM-Ausfälle sind vermutlich der
Grund für das Zucken des Servos.
Was den Code aus dem Artikel angeht:
Schau dir doch mal das Datenblatt zu deinem Controller an, besonders die
Pinbelegung der Taster und den Pin an dem die PWM von OCR1A anliegt.
Ok mir klar was OCR1A ist, aber was beuten diese Funktionen hier im
Zusammenhang mit der PWM (Oben genannter Microcontroller.net Code)
TCCR1A = (1<<COM1A0); // Togglen bei Compare Match
TCCR1B = (1<<WGM12) | (1<<CS11); // CTC-Mode; Prescaler 8
TIMSK = (1<<OCIE1A); // Timer-Compare Interrupt an
MfG
mr_desmond
mr_desmond schrieb:> Ok mir klar was OCR1A ist,
Das ist aber nur die halbe Miete.
Der Timer erzeugt seine Hardware-PWM, in dem er einen ganz bestimmten
Pin toggelt. Dere Pin ist festgelegt und du kannst ihn nicht ändern.
> aber was beuten diese Funktionen hier im> Zusammenhang mit der PWM (Oben genannter Microcontroller.net Code)>> TCCR1A = (1<<COM1A0); // Togglen bei Compare Match> TCCR1B = (1<<WGM12) | (1<<CS11); // CTC-Mode; Prescaler 8> TIMSK = (1<<OCIE1A); // Timer-Compare Interrupt an
Genau das was jeweils im Kommentar steht.
FAQ: Timer
Der springende Punkt in diesem Code besteht darin, dass der Timer selbst
den Ausgangspin umschaltet (toggelt). Aber das kann nicht irgendein Pin
sein, sondern das ist (bei dieser Art der Programmierung) immer der OC1A
Pin. Der liegt aber physikalisch an jedem µC woanders. Also musst du in
deinem Datenblatt nachsehen, an welchem Pin bei dir der OC1A Ausgang
liegt und du musst dein Servo dann dort anschliessen (und den Pin
mittels entsprechender DDRx 'Akrobatik' auch auf Ausgang stellen)
Hallo erstmal,
also erstmal danke für die ganzen Hilfen, ich habe paar Dennkfehler
ausgemertzt und eine einstellung am IC geändert und zack die Scheiße
funktioniert... Ich kann jetzt 9 Servos direkt ansteuern!
Habe da noch eine frage: Kann man die Servos langsamer laufen lassen?
durch ein Befhel oder ähnliches?
MfG
Michael Klink
Michael Klink schrieb:> Habe da noch eine frage: Kann man die Servos langsamer laufen lassen?> durch ein Befhel oder ähnliches?
Durch einen 'Befehl' nicht.
Aber nichts und niemand hindert dich daran, die Vorgabepositionen für
die Servos langsam und in Schritten zu ändern um die Zielposition zu
erreichen.
Michael Klink schrieb:> Habe da noch eine frage: Kann man die Servos langsamer laufen lassen?> durch ein Befhel oder ähnliches?
Indem du eine Rampe programmierst.
Wenn er z.B. in 2 Sekunden von Mittelstellung nach 45° rechts gehen
soll,
dann sende ihm innerhalb von 2 Sekunden länger werdende Impulse
beginnend von 1,5ms so daß in 2 Sekunden die Impulse 2ms lang sind
Ganz verstanden hast du die Ansteuerung der Servos noch nicht.
die Breite des PWM Signales entspricht der Servostellung. Wenn du jetzt
immer zwischen zwei Werten springst versucht der Servo mit seiner
maximalen Geschwindigkeit die neue Position zu erreichen.
das must du sanfter machen, die Breite des Signales immer nur ein
bischen ändern. Je langsammer du das machst um so langsammer fahrt der
Servo.