PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Servo reagiert nicht



Jeti
04.04.2013, 09:17
Hallo an Alle!

da ich ja in letzter Zeit ein bisschen am experimentieren bin habe ich jetzt versucht ein altes Modellbauservo durch einen ATMega16 steuern zu lassen. Leider reagiert das Servo überhauptnicht (ist aber getestet. Mit der RC-Fernbedinung und dem normalen Empfänger funktioniert es).

Zur kurzen Erklärung:

Das Servo hat seine eigene Stromversorgung mittels Batterieblock. Der Controller wird durch den Programmer mit Strom versorgt.

Ich habe das Signalkabel (die Gelbe Leitung) durchgeschnitten und an PD5 (OC1A) verstöpselt.

jetzt habe ich folgenden Code in C geschrieben aber wie gesagt es reagiert nicht:



#include <avr/io.h>
#include <util/delay.h>

int main(void)
{

DDRD = (1 << DDD5); // OC1A als Ausgang
DDRB= (1<<PB0);

ICR1 = (uint16_t)19999; // TOP => 50 Hz
OCR1A = (uint16_t)1000; // Vergleichswert einstellen (hier quasi minimaler Ausschlag)

TCCR1A |= (1 << COM1A1); // non-inverting mode fuer Pin OC1A
TCCR1A |= (1 << WGM11) ; // Fast PWM Mode 14 Teil A
TCCR1B |= (1 << CS11); // Prescaler: 1/8

while (1) // endlos
{
PORTB^=(1<<PB0); //Blinkt nur als visualisierung das überhaupt was tut
_delay_ms(100);
}
return 0;
}


Wenn ich den Wert für OCR1A = (uint16_t)1000; nun auf OCR1A = (uint16_t)2000; endere sollte eigentlich das Servo zum neuen Ausschlag fahren und dann da auch bleiben... ich finde den Fehler aber nicht.

Vielen Dank schon mal
Gruß
Jeti

Klebwax
04.04.2013, 09:22
Das Servo hat seine eigene Stromversorgung mittels Batterieblock. Der Controller wird durch den Programmer mit Strom versorgt.

Ich habe das Signalkabel (die Gelbe Leitung) durchgeschnitten und an PD5 (OC1A) verstöpselt.

Wie sieht es mit den Masseanschlüssen aus?

MfG Klebwax

Jeti
04.04.2013, 09:24
Ich habe dabei 2 Varianten Probiert. Zuerst habe ich die Masse für das Servo von der Batterie geholt. Das hat nicht funktioniert aber das servo hat wenigstens noch "gezuckt" wenn man das Signalkabel vom PD5 abgestöpselt hat. Dann habe ich die Masse vom 7805 auf dem Board abgezwackt... Das hat aber auch nicht funktioniert und das servo zuckt nicht mal mehr.

DanielSan
04.04.2013, 09:36
Die Masse der Batterie muss mit der Masse des Atmel's verbunden sein. Diese gemeinsamme Masse ist dann auch die Masse für das Servo. Nur die + Leitungen müssen getrennt bleiben.

Guck mal hier (http://static.evigo.net/infolexikon/.media/images/2008/09/18/ubercam.png) da ist ein Schaltplan mit 2 Servos. Achte mal auf die Spannungsversorgung des Atmels und der Servos. Da sieht man ganz gut wie das verdrahtet sein sollte.

Jeti
04.04.2013, 09:56
also... ich habe jetzt:

-Die Masse der Batterie mit der Masse des Servos verbunden.
-Die Masse des Boards ebenfalls mit der Masse der Batterie verbunden.
-Der Programmer versorgt immer noch das Board
-Der Akku ist mit seinen 6V an das Servo angeschlossen
-Die Signalleitung des Servos liegt immer noch an PD5

aber Leider habe ich immer noch keinen Erfolg...

- - - Aktualisiert - - -

Also einen Fehler habe ich gefunden. Mir ist eine Lötstelle am Kabel für das Servo wohl gebrochen. Seit ich diese jetzt wieder gerichtet habe hat sich der Fehler deutlich geändert. Das Servo läuft jetzt immer eine Position an, nämlich ganz links... aber eine Änderung von OCR1A führt es immer noch nicht aus.

DanielSan
04.04.2013, 09:56
Hast du einen normalen RC Empfänger? Dann teste mal ob das Servo noch lebt. Ich habe die Erfahrung gemacht, das die Logikelektronik von Servos recht empfindlich ist. Passt z.B. die Signal Frequenz nicht, kann das schon reichen und das Servo ist tot.



Ok hat sich etwas überschnitten.

Ich denke dein Code passt nicht. So ganz weiss ich jetzt aber auch nicht was falsch ist.

Jeti
04.04.2013, 10:08
die On-Board Frequenz meines Mega16 müsste doch 8kHz sein oder? wenn ich dann einen Takt von 50Hz brauche darf ich den 16 bit Timer nur bis 19999 zählen lassen wenn mein Prescaler bei 8 liegt... oder sehe ich da was falsch. Und wenn ich nun das Servo auf Mittelstellung stellen will dann müsste ich doch sagen 19999/20*1,5 also ungefähr 1500... Dann schwankt der Wert für OCR1A zwischen 1000 und 2000... in Momenten wie diesen hätte ich gerne ein Oszilloskop...

Searcher
04.04.2013, 10:19
TCCR1A |= (1 << WGM11) ; // Fast PWM Mode 14 Teil A



Hallo, das ist nicht Mode 14 sondern Mode 2 und der benutzt auch nicht ICR1 als Top Wert.


die On-Board Frequenz meines Mega16 müsste doch 8kHz sein oder?
Wenn der Mega16 neu ist und an der Frequenz noch nichts, zB mit den Fuses gemacht worden ist, ist sie 1Mhz.

Gruß
Searcher

DanielSan
04.04.2013, 10:21
Ähm für die Timer berechnung musst du schon die Prozessorfrequenz nehmen. Also z.B. 8MHz.

Gib mal hier deine gewünschten Daten ein:
http://www.dieelektronikerseite.de/Tools/Timer-Rechner.htm

Pass aber mit deinem Servo auf. Klemm es erst an wenn du dir sicher bist, das alles richtig ist. Ich tu mich mit den Timern auch immer schwer.

Meine Methode:
Timer einstellen z.B. auf 20ms. Dann in der Interruptroutine einen Counter hochzählen lassen bis 50 (= 1s) und dann eine Led Togglen. Wenn die dann im 1s Takt blinkt ist das schonmal gut. So ermittel ich das experimentell. Mein Logikanalyzer ist aber schon so gut wie bestellt. Die Teile gibt es fürn 10er in China. Da kann man nicht viel verkehrt machen.

Jeti
04.04.2013, 11:10
Erst einmal herzlichen Dank schon einmal für die Hilfe!

Ich habe meine Frequenz jetzt auf den externen quarz gelegt, dann kann ich mir sicher sein das der Mega16 die 8MHz verwendet.
Außerdem habe ich im Datenblatt den Timer jetzt (denke ich) richtig auf den Mode 14 gelegt. Ich habe auch einmal die Routine mit den Interrupts versucht einzubauen um zu schauen ob die LED Blinkt. Da ich aber wie gesagt recht frisch in der Materie bin habe ich so einige Schwierigkeiten damit bekommen. Der Code sieht nun aus wie folgt:



#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
int n=0;

ISR (TIMER1_OVF_vect)
{
n++;
if (n>=50)
{ PORTB^=(1<<PB0);
n=0;
}
}

int main(void)
{

DDRD = (1 << DDD5); // OC1A als Ausgang
DDRB= (1<<PB0);

ICR1 = (uint16_t)19999; // TOP => 50 Hz
OCR1A = (uint16_t)1500; // Vergleichswert einstellen

TCCR1A |= (1 << COM1A1); // non-inverting mode fuer Pin OC1A
TCCR1A |= (1 << WGM11); // Fast PWM Mode 14 Teil A
TCCR1B |=(1 << WGM13)|(1 << WGM12) ; // Fast PWM Mode 14 Teil A
TCCR1B |= (1 << CS11); // Prescaler: 1/8
while (1);
}




Ich glaube das mir mein Interrupt den Zähler n jedesmal wieder neu mit 0 beschreibt. Ich weiß aber auch noch nicht wirklich wie ich das verhindern kann. DanielSan kannst du mir da einen Tipp geben?

---------------------------------------
Ich habe noch einmal ein paar Änderungen vorgenommen zum einen habe ich n jetzt global definiert damit es sie nicht bei jedem Interrupt überschreibt. Blinken tut meine LED deswegen trotzdem nicht. Und ich habe denke ich noch mal einen Fehler beim Mode gefunden und behoben. Jetzt zuckt das servo immerhin schon mal rythmisch... aber mehr auch nicht

Searcher
04.04.2013, 11:25
Hi,
WGM13 und WGM12 zusätzlich für den Mode 14 zu setzen ist richtig. Allerdings sind die beiden im TCCR1B Register;)
Das Timing sollte dann mit OCR1A = 1500 bei den 8MHz für die Mittelstellung des Servos gut sein.

(Ob die Syntax in C richtig ist kann ich leider nicht sagen :( )
Gruß
Searcher

DanielSan
04.04.2013, 11:28
Kann es sein, das du deinen Counter "n" bei jedem ISR aufruf resetest. Dann würde der niemals 50 erreichen. Oder ist das bei der deklaration so, das die Zeile "int n = 0;" nur einmal ausgeführt wird.

Jeti
04.04.2013, 11:46
Also ich habe jetzt die Lösung des einen Problems gefunden dafür habe ich mir ein neues geschaffen :(.

Ich habe noch einmal die Werte für eine Frequenz von 1Mhz eingetippt und plötzlich hats funktioniert. Das hat bei mir zu einem "Aha!" Erlebnis geführt und seit dem hat das mit dem servo auch geklappt. (Das Blinken der LED klappt immer noch nicht auch nachdem ich meine Variable nun global definiert habe).

Dann bin ich in die Fuses gegangen und habe dort Nur und ausschließlich den Reiter "SUT_CKSEL" umgestellt von "int.RC Osc. 1MHz" auf "Ext. Crystal/Resonator High Freq. 8Mhz"... seit dem kommt beim versuch etwas zu programieren oder die Fuses zu ändern der Fehler "Entering programming mode FAILED"... habe ich mich gerade ellegant ausgesperrt?

DanielSan
04.04.2013, 11:55
Hast du denn eine 8MHz externe Taktquelle angeschlossen?

Jeti
04.04.2013, 11:59
bei mir ist (fast) alles möglich :) aber in diesem Fall ist da ein 8Mhz Quarz dran. Da ich das Board auch nicht selber entwickelt habe sondern es gekauft ist konnte ich da aber auch nicht viel falsch machen.

DanielSan
04.04.2013, 12:14
Ok kannst du die Flash Geschwindigkeit beeinflussen? Bei meinem USBASP muss ich die Geschwindigkeit anpassen, wenn ich von 1MHz auf 8MHz umfuse.

Searcher
04.04.2013, 12:23
... und gibt es einen Link zu Deinem Board?

Jeti
04.04.2013, 12:24
Meinst du die Geschwindigkeit mit der der ISP-Programmer die Daten schreibt? Ich habe die schon verändert und durchprobiert aber das Ergebnis ist immer das Selbe.

Der Link für das Board ist
http://www.elektor.de/jahrgang/2006/mai/mini-mega-board.64106.lynkx

Searcher
04.04.2013, 12:37
Der Link für das Board ist
http://www.elektor.de/jahrgang/2006/mai/mini-mega-board.64106.lynkx

Kann leider den Schaltplan nicht runterladen. Auf dem Board sind 'ne Menge Schalter und Jumper? Könnte sein, daß da für den externen Quarz noch irgendetwas hardwaremäßig einzustellen ist? Oder ist zu den XTAL1, XTAL2 Pins noch etwas anderes parallel geschaltet als der Quartz?

Jeti
04.04.2013, 12:49
Also ich habe nun mal aus der Bastelkiste einen neuen ATMega16 in das Board gestopft, und schon funktioniert es wieder einwandfrei... Aber ich mache mir so langsam echt gedanken wie ich das jedes Mal schaffe meine Controller zu vernichten. Das war schon der 2. der nach eines Ausflug meinerseits in die Fuses quasi unbrauchbar wurde...

- - - Aktualisiert - - -

Moment ich habe einen Schaltblan. Ich stelle ihn mal Online

Edit: Habe den Schaltplan wieder entfernt

Searcher
04.04.2013, 13:02
Danke. Weil der Originalplan aber nicht so ohne Weiteres runterladbar ist, weis ich nicht, ob Du ihn so ohne Weiteres hochladen darfst ???

Sieht jedenfalls nicht so aus, als wenn da noch was in HW eingestellt werden müßte. Weis 'nu nix mehr :(

Jeti
04.04.2013, 14:23
kann das sein das mein Quarz kaputt ist? Und der deswegen einfach keinen takt bekommt? Dann dürfte ich ja eigentlich gefahrlos den Text der internen uhr auf 8MHz drehen können beim (letzten) ATMega16 der mir noch bleibt... und wenn der dann auch nicht mehr reagiert dann mache ich mir Gedanken... ich müsste das doch eigentlich relativ gut verändern können ohne gleich Gefahr zu laufen alles zu zerschießen oder? Ach ja als Software auf meinem PC nutze ich Übrigends AVR-Studio 4 fals das Hilft.

- - - Aktualisiert - - -

Falls jemandem dazu noch was einfällt... ich habe jetzt bei meinem letzten AVR die Interne Uhr auch auf 8MHz gestellt. Seit dem Reagiert dieser auch nicht mehr. Was mache ich da bitte falsch?

DanielSan
04.04.2013, 14:44
Dann fused du falsch. Mach mal bitte einen Screenshot wie du deine Fuses eingestellt hast. Ich habe kein AVR Studio.

Searcher
04.04.2013, 15:03
Zu dem Interrupt:
Im fast PWM Mode mit ICR1 als Top (Mode 14) wird bei Erreichen des Top Wertes, also ICR1 nicht der Timer Overflow Interrupt ausgelöst, sondern der Input Capture Interrupt. Dazu muß der aber im TIMSK Register mit dem TICIE1 Bit freigegeben werde.

Außerdem müssen die Interrupts global freigegeben werden. Das geht in C mit "sei"; glaub ich.

Der Name der ISR muß auch dem Input Capture Interrupt entsprechen. Und ist mir nicht klar aber sollten Variable in der ISR sollen nicht volatile sein ???

DanielSan
04.04.2013, 15:19
Ich kann dir nur sagen, wie ich das gelöst habe. Eigentlich sollen sie volatile sein, aber ich weiss nicht warum und es funktioniert auch so.



byte state = 1;
int pwm_hi = 0;
int pwm_lo = 0;
int led_w = 13;
int servo_1 = 12;
int servo_1_pos = 150;
int servo_state = 0;
int n = 0;


void setup(){
pinMode(led_w, OUTPUT);
pinMode(servo_1, OUTPUT);
setup_timer1();

}

void loop()
{
if(servo_state == 0)
{
delay(20);
servo_1_pos = servo_1_pos + 1;
if(servo_1_pos ==200)
{
servo_state = 1;
}
}

if(servo_state == 1)
{
delay(20);
servo_1_pos = servo_1_pos - 1;
if(servo_1_pos ==100)
{
servo_state = 0;
}
}

}

void setup_timer1(){
cli(); // disable interrupts
TCCR1A = 0; // Register TCCR1A auf 0 setzen
TCCR1B = 0; // Register TCCR1B auf 0 setzen um Timer zu beenden

//CTC setzen
OCR1A = 19; // bis 15624 ticken dann interrupt

//enable CTC
TCCR1B |= (1 << WGM12);
// Set CS10 bit so timer runs at clock speed:
//Timerresolution: 1/(16*10^6 / 1024)
TCCR1B |= (0 << CS10);
TCCR1B |= (1 << CS11);
TCCR1B |= (0 << CS12); // prescaler 1024
// enable Timer1 compare interrupt
TIMSK1 |= (1 << OCIE1A);
// enable global interrupts:
sei();
}


ISR(TIMER1_COMPA_vect)
{
if (n == 20000)
{
digitalWrite(led_w, !digitalRead(led_w));
n = 0;
}
n++;

if (pwm_hi > 0)
{
digitalWrite(servo_1,HIGH);
pwm_hi = pwm_hi - 1;
pwm_lo = 0;
}
else if(pwm_hi == 0)
{
pwm_lo++;
digitalWrite(servo_1,LOW);
}
if (pwm_lo == 2000 - servo_1_pos)
{
pwm_hi = servo_1_pos;
}
}