Danke für den Hinweis mit den Kondenastoren, wenn ich mich richtig erinerre, habe ich da 25k Potis drin.
Wenn ich nach dem "in ADCH" noch ein ldi anhänge, läuft das ganze, aber ich werde dann noch die bereinigte Versiuon mit dem save hochladen.
Danke für den Hinweis mit den Kondenastoren, wenn ich mich richtig erinerre, habe ich da 25k Potis drin.
Wenn ich nach dem "in ADCH" noch ein ldi anhänge, läuft das ganze, aber ich werde dann noch die bereinigte Versiuon mit dem save hochladen.
Mit 25 K Potis sollte es eigentlich kaum Probleme geben mit den AD eingängen. Hab mich oben mit dem Wert etwas vertan, kritisch wird es erst ab 50 kOhm und dann auch eher langsam.
Eine ISR routine die das SREG verändert (so wie im code oben) führt fast immer zu unerwarten Fehlern im Rest des Programms. Diesen Punkt unbedingt beheben.
Ok, ich hab mal die üblichen ADC Maßnehmen ergriffen, also Induktivität und C an Aref und die Kondensatoren an den Eingängen gegen Masse.
Trotzdem zappelt da alles weiter vor sich hin. Muss ein Fehler im Code sein.
Ich hab auch mal ein Register zum sicher von SREG => save_sreg angelegt.
Danke auch bis hier hin schon für die Mühen,Code:.include "m8def.inc" .def tmp = r16 .def k0 = r17;Servo 0 .def k1 = r18;Servo 1 .def k2 = r19;Servo 2 .def k3 = r20;Servo 3 .def zyclus = r21 .def kanal = r22 ;geht an ADMUX .def pause = r23 ;für die 1ms Offset und die zweite ms für ; die Servoposition wird die selbe ISR benutzt. Ist Pause = 0 ;wird über das LOW setzten weggesprungen, wenn Pause = 1 eben nicht. ;sinngemäß wird Pause nach der ms erhöht und nach dem Positionsstellen ;erniedrigt. .def save_sreg = r24 ;erklärt sich sicher von selbst .org 0x000 rjmp reset .org OC2addr ; OCR2 Interrupt Vector Address rjmp hitvalue reset: ;Stack wird bei Interrupts benötigt! ldi r16,HIGH(RAMEND) out SPH,r16 ldi r16,LOW(RAMEND) out SPL,r16 ldi tmp,0b00000010 out TCCR0,tmp ldi tmp,0b00100000 out DDRC,tmp ldi tmp,0b01010101 out DDRD,tmp ldi tmp,0b011000000 out ADMUX,tmp ldi tmp,30 out OCR2,tmp sei main: ;################################################################## ;################################################################## ;hier werden die ADC Werte für das jeweilige Servo erfasst ldi kanal,0b01100000 ;Hier wird für den Servo 0 out ADMUX,kanal ;die Position ermittelt ldi tmp,0b11000101 ;PRESCALER 32 - Singleconversion out ADCSRA,tmp kanal0: in tmp,ADCSRA sbrs tmp,4 rjmp kanal0 in k0,ADCH ldi kanal,0b01100001 out ADMUX,kanal ldi tmp,0b11000101 ;PRESCALER 32 out ADCSRA,tmp kanal1: in tmp,ADCSRA sbrs tmp,4 rjmp kanal1 in k1,ADCH ldi kanal,0b01100010 out ADMUX,kanal ldi tmp,0b11000101 ;PRESCALER 32 out ADCSRA,tmp kanal2: in tmp,ADCSRA sbrs tmp,4 rjmp kanal2 in k2,ADCH ldi kanal,0b01100011 out ADMUX,kanal ldi tmp,0b11000101 ;PRESCALER 32 out ADCSRA,tmp kanal3: in tmp,ADCSRA sbrs tmp,4 rjmp kanal3 in k3,ADCH ;############################################################# ;############################################################# ldi tmp,0 out TCNT0,tmp ;_________________18ms Pause_____________- waita: in tmp,TCNT0 cpi tmp,252 brlo waita ldi tmp,0 out TCNT0,tmp inc r26 cpi r26,74 brlo waita ;________________________________________- ldi tmp,0b00001001 ;RPESCALER 1 out TCCR2,tmp ldi tmp,0 out TCNT2,tmp ldi tmp,0b01010101 ;Pins für das Signal HIGH setzten out PORTD,tmp ldi tmp,0b10000000 out TIMSK,tmp ldi zyclus,0 ldi r26,0 ;*******************1ms Offset***************** warten1: cpi zyclus,250 breq wigger rjmp warten1 wigger: ;********************************************** sbi PORTC,5 ;wurde zur Kontrolle der Zeiten benutzt und mit Oszi gemessen ldi zyclus,0 out TCNT2,zyclus ldi pause,1 ;ab hier Stellungs kritische ms ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ;diese Schleife wird solange durchlaufen, ;bis der PORTD an dem die Servo angeschlossen sind ;komplett LOW ist pulse: in tmp,PORTD cpi tmp,0 brne pulse ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ;''''''''''''''''''''''''''''''''' ;diese Schleife macht die ms ggf. voll,um das PWM nicht zu verzerren warten: cpi zyclus,250 brsh ende rjmp warten ende: ;''''''''''''''''''''''''''''''''' cbi PORTC,5 ldi zyclus,0 out TCCR2,zyclus ldi pause,0 ldi kanal,0b01100000 out ADMUX,kanal rjmp main hitvalue: in save_sreg,SREG cpi pause,0 breq null cp zyclus,k0 brne ka cbi PORTD,0 ka: cp zyclus,k1 brne kb cbi PORTD,2 kb: cp zyclus,k2 brne kc cbi PORTD,4 kc: cp zyclus,k3 brne kd cbi PORTD,6 kd: null: inc zyclus out SREG,save_sreg reti
The Man
Ich bin der Meinung dein Programm hängt viel zu viel in der Timer 2 Interrupt Routine rum.
Warum nimmst Du nicht den Timer 1 her und gibst dann ein Servo nach dem anderen aus ?
Der Timer kann bei einer Quarzfrequenz von 8MHz mit einem Prescaler von 8 verwendet werden. Mit diesen Parametern entspricht der Comparematch Zählerstand dann auch der Servoimpulslänge in µs.
Da der Timer 1 ein 16Bit Timer ist brauchst Du nicht mal ein Überlaufregister, weil ja 65ms in den Timer "reingehen".
Dann lässt Du eine Pause von 12ms folgen und startest den Zyklus neu.
Die Comparematch1A Routine würde dann in einem Zyklus 20ms nur 4mal durchlaufen und deine Servos kriegen genauso viele Impulse wie jetzt auch.
Zur Register Sicherung:
Meine Register Sicherung schaut immer folgendermassen aus:
Code:PUSH temp ; temp Register sichern IN temp,SREG; SREG ins temp Register PUSH temp ; temp Register nochmal sichern PUSH temp1... ; weitere in der Interruptroutine verwendete Register sichern ; #### Dein Quellcode #### POP temp1 ; weitere Register zurückschreiben POP temp OUT SREG,temp ; SREG zurückschreiben POP temp ; Werte des temp Registers zurückholen RETI ; Raus aus dem Interrupt
Ich hab jetzt mal den Kanalwechsel im ADMUX wegkommentiert, damit alle Servo Register aus dem Selben Poti versorgt werden. laufen jetzt alle synchron. (Ich habe bei der ersten Version darauf geachtet, erst den Kanal zu ändern und dann die Wandlung zu starten) Das bedeutet ja, das das Program im Prinzip funktioniert. Ich verstehe nur nicht, warum er die Werte dann durch einander Würfelt, wenn ich die Kanäle weiterschalte
![]()
SOOOOOOOOOOOOO,
ich hab das Problem gefunden! Ich lese an vier Stellen das ADCH ei´n (left adjusted). Das funktioniert ohne Interrupt über das ADC Flag Bit 4. Also in einer Schleife:
kanal0:
in tmp,ADCSRA
sbrs tmp,4
rjmp kanal0
in k0,ADCH
Der Gag ist, dass dieses Bit irgendwie nicht wie üblich automatisch gelöscht wird und das Program deshalb Sinnlos durchrennt. Das löscht sich nichtmal, wenn ich ADCSRA manuell mit NULL beschreibe.
Kann es sein, dass ich hier einem Vista Problem aufsitzte? Im Dec C++ Compiler hatte ich das auch schon...
Chuck Norris kann Windows Vista auf einem Atmel in Assembler implementieren!
Chuck Norris coded mit 3 Tasten:"1","0" und "compile"
Das kommt davon wenn man nur einfach 4 schraubt um ds ADIF bit auszuwählen. Besser statt der den Bitnahmen (ADIF) verwenden, dann wird der code besser portabel und man sieht besser welches Bit gemeint ist.
Die Intteruptsflags werden gelöscht, indem eine 1 hineingeschrieben wird. Klingt unlogisch ist aber so.
for (applaus=0;applaus<1001;applaus++){
printf("=D> =D> =D> =D> =D> =D> DANKE!\n");
}
Jetzt läuft das Ding.
Chuck Norris kann Windows Vista auf einem Atmel in Assembler implementieren!
Chuck Norris coded mit 3 Tasten:"1","0" und "compile"
Lesezeichen