Hallo zusammen!
Ich habe ein Problem mit meinem AVR.
Ich würde gerne mit einem ATTiny85 ein Modellbauservo mit einem Sinus
ansteuern. Der Sinus soll 2,5 Hz haben, damit kann ich dann ein von der
Länge passendes Pendel zum schwingen bringen.
Modellbauservos benötigen alle 20ms einen Puls von 0,9 bis 2,1 ms Länge.
Die Pulslänge bestimmt die Soll-Lage: 0,9 ist ganz links; 1,5 ist in der
Mitte; 2,1 ist ganz rechts.
Den Modellbauservo-Beitrag im Forum habe ich mir schon durchgelesen, die
Lösung dort kommt leider für einen Attiny85 nicht in Frage: Ich habe
keinen 16 Bit Timer.
Mein Programm soll einen 20ms Interrupt haben, der das Signal und den
anderen Timer-Interrupt aktiviert. (Timer 0, Zählmarke OCR0A)
Der andere Timer soll nach der passenden Zeit (zwischen 0,9 und 2,1ms)
auch einen Interrupt haben. Nach diesem Interrupt wird der zweite Timer
wieder deaktiviert und eine neue Signallänge berechnet. (Timer 1,
Zählmarke OCR1B)
Kann mir einer von euch helfen? Ich bin schon zwei Tage dabei und finde
den Fehler einfach nicht! Die einzelnen Timersignale kommen raus, die
habe ich mit dem Oszi gemessen. Es scheint als werden die Interrupts gar
nicht erst aktiviert (oder nicht auf die richtige Art und Weise).
Hallo Andreas,
in deinem Code fallen sofort folgende Dinge auf:
1. communication ist nicht volatile, sollte es aber sein. Der Modifier
'volatile' besagt dem Compiler, dass keine Optimierungen beim Zugriff
auf die Variable vorgenommen werden dürfen. Sonst kann es passieren,
dass die Variable in einem Register gehalten wird und das Programm von
einer Änderung in einer ISR nichts mitbekommt.
2. In ISRs sind Interrupts bereits beim Eintritt deaktiviert und werden
beim Austritt automatisch wieder aktiviert. Ebenso wird SREG vom
Compiler selbst gesichert. cli() und sei() usw. sind deshalb nicht
nötig.
3. Es empfielt sich, bei Registerzuweisungen die gesetzten Bits einzeln
anzugeben, also z.B. TIMSK = (1<<OCIE0A) anstatt TIMSK = 0x10, weil das
man hier sofort die Bedeutung des Codes sehen kann ohne erstmal im
Datenblatt nachschauen zu müssen. Zudem können sich die Bitpositionen
je nach AVR ändern, der Bitname bleibt aber meistens gleich, sodass das
Programm einfacher auf andere AVR-Controller portiert werden kann.
MfG Mark
Die 20ms brauchst du nicht einhalten.
Du kannst nach 3ms oder sogar noch früher den nächsten Impuls senden.
Die 20ms sind historisch bedingt.
Ergo: Dein Programm (das ich mir nicht näher angesehen habe) ist zu
kompliziert.
Bei dem Rest stimme ich Mork völlig zu.
Danke, das war alles schon mal sehr hilfreich.
Ich habe die Schreibweise auf die (für mich derzeit noch
unübersichtlichere) "saubere" Schreibweise geändert. Wahrscheinlich
gewöhne ich mich noch dran. Überzeugt hat mich das
Kompatibilitäts-Argument.
Dann gings.
Keine Ahnung, welches Bit ich wo falsch gesetzt hatte....
Jettzt bleibt noch ein Problem:
Obwohl ich da meinen Vektor mit 9 Werten für den Sinus definert habe,
springt das Signal von links auf rechts und wieder zurück, hält sich
manchmal an die Kurve und manchmal nicht. hm.
Solche Fehler liegen meistens an so Sachen wie fehlende
Mutexe/Semaphores. Das heißt, du hast eine Variable, die in einer ISR
als auch im Hauptprogramm beschrieben werden aber dessen Schreibzugriff
nicht synchronisiert wird.
Während die Variable im Hauptprogramm geschrieben wird, sollten die
Interrupts deaktiviert sein.
>if (servoposition > MAXPOS)
MAXPOS ist doch weiter oben auf 9 gesetzt worden.
Der Vergleich greift also bei ServoPosition = 10.
Dein Feld hat aber nur 8 Einträge...
Jo, das wars.
Jetzt gehts. Mit dem Signal steuere ich zwei Servos, und mit den zwei
Servos steuere ich acht Spinnenbeine.
Sie kann jetzt strampeln wenn man sie an einem Faden unter die Decke
hängt :-)
Nach einigen Sekunden setzt allerdings immer das Programm aus und die
Beine bewegen sich nicht mehr.
Also noch mal ran. seufz
Ja, jetzt ja. Ich poste gleich noch mal den aktuellen Quelltext.
Momentan scheint es mir, als verplant er ab einer gewissen Zeitgrenze
schlichtweg, die Signaldauer weiter anzupassen. Komisch ist, dass es
erst nach 10 Sekunden, manchmal auch noch später passiert -> also wenn
alle Schleifen und ISRs schon hunderte male aufgerufen worden sind.
Auf Lötfehler hab ichs auch schon untersucht - viel konnte man da nicht
falsch machen.
Einen Watchdog mit sechzig Millisekunden habe ich mittlerweile eingebaut
- der wird alle zwanzig Millisekunden zurückgesetzt. Hat auch nichts
geändert, nach einigen Sekunden gehts nicht mehr.
Ein Foto vom (simplen) Aufbau habe ich angehängt.
Ich vermute mal, dass die Versorgungsspannung vom Servomotor versaut
wird. Der "Angstkondensator" sieht mir nach Tantal aus, da sollte auf
jeden Fall noch was keramisches dabei.
Hallo Andreas,
ich habe deinen Code nicht ganz durchgesehen... weil er mir unnötig
kompliztiert erscheint (oder ich habe etwas wesentliches übersehen).
Einen Servopuls kannst du z.B. so machen (ist für einen ATmega8 mit
16MHz, aber die Übersetzung in ATtiny85 ist trvial, nur Timer0 halt auch
mit CTC statt OVF und Timer1 mit OCR1C, und passende Prescaler).
volatile unsigned char rc_dotask;
volatile unsigned char rc_ovf;
ISR( TIMER0_OVF_vect ) //alle 16ms bei 16Mhz ATmega und Prescaler 1024
{
TCNT1= 0;
rc_outPORT|= (1<<rc_outP);
rc_ovf= 1;
}
ISR( TIMER1_COMPA_vect ) //ISR to generate the PPM packet
{
rc_outPORT&=~ (1<<rc_outP);
if( rc_ovf ){ rc_ovf= 0; rc_dotask= 1; }
}
im main dann alle Initialisierungen und so etwas
rc_dotask= rc_ovf= 0;
sei();
while( 1 ){
if( rc_dotask ){
rc_dotask= 0;
//hier hat man nun alle Zeit etwas zu machen,
// z.B. den neuen Wert für die Servopulslänge einzustellen
OCR1A= t-1;
}
}
Sieht in manchem ähnlich wie dein Code aus nur einfacher, kein ständges
Interrupt ein und ausschalten und so, keine Mehrfachzustände, etc,...
Läuft bei mir als Servotester problemlos.
Olli
Hi!
Wenn du normale Servos hast, was ich annehme, solltest du die 20 ms
pause nicht sehr weit unterbieten (am besten gar nicht). Sonst rauchen
dir deine Servos sehr schnell ab. Wenn du Digital-Servos benutzt, dürfte
das kein Problem sein.
Erklärung: Wird die pause kürzer gemacht, läuft der Motor öfter an, und
das schlagartig in alle Richtungen. Das tut dem nicht sehr gut.
Viel Spass noch, Michael
Danke dafür!
Nachdem ich jetzt die Servo-Schwingung auf etwas mehr als 1Hz gestellt
habe von vorher 4 Hz (durch einen Rechenfehler), kackt das Programm auch
nicht mehr ab.
Also hat der µC wahrscheinlich wirklich zwischendurch keinen Strom
gehabt.
Jetzt laufen die Servos langsamer, und es funktioniert alles. Danke an
alle!