-
Du kannst, um den Timer abzuschalten einfach den Prescaler auf 0 setzen (in TCCR2).
Genauso kanst du TCCR2 ganz löschen (auf 0x00 setzten), was fast den selben Effekt hat, nur dass es zusätzlich (zu deinem Vorteil) die normale Port-operation wieder freigibt (also vergiss nicht den PORT als Ausgang, und auf GND zu legen).
Wie schaltest du den Timer wieder an?: du Setzt TCCR2 einfach wieder auf den Wert, der er vorher war, bevor du das Register gelöscht hast.
Und wann stellst du den Timer wieder an?: Hierzu benutzt du den "Input Capture Interrupt" des 16bit-Timers, der ja jede 20ms auftritt. (ISR(TIMER1_CAPT_vect){...}). Vergiss nicht, ihn zu initialisieren: TIMSK |= (1<<TICIE1);
In ihm machst du also: TCCR2 = (1<<WGM20) | (1<<COM21) | (1<<CS22);
So sollte es eigentlich funktionieren. Wenn nicht, schick mir das Programm, dann schau ich mir das nochmal an.
Gruß, Yaro
-
Klappt leider nicht, es scheint als würde TCCR2 nicht auf Null gesetzt werden. Oder der Timer gleich wieder gestartet.
Mein Code sieht komplett im Moment so aus:
Code:
#include <avr/io.h> // I/O Port definitions
#include <avr/interrupt.h> // Interrupt macros
#define F_CPU 16000000
#define timer 236
volatile int ms = 0;
void pwm_init(void)
{
TIMSK |= (1<<TICIE1);
//Timer 1 (Port 0/1)
TCCR1A = (1<<COM1A1)| (1<<COM1B1); //Clear OC on Comp Match when up-count, set downcount
TCCR1B = (1<<WGM13) | (1<<CS11) ; //PWM Phase abd Freq Correct. Prescaler 8
ICR1 = 20000; //Periodendauer Servo 20ms
OCR1A = 1000; //Servosignal (Port 0)
OCR1B = 1000; //Servosignal (PORT 1)
//Timer 2 (Port 2)
TCCR2 = (1<<WGM20)| (1<<COM21) /*| (1<<CS21)*/ | (1<<CS22);
OCR2 = 150;
};
ISR(TIMER2_OVF_vect)
{
TCCR2 = 0x00;
};
ISR(TIMER1_CAPT_vect)
{
TCCR2 = (1<<WGM20) | (1<<COM21) | (1<<CS22);
};
/*void timer_init(void)
{
TCCR0 |= (1<<CS01);
TCNT0 = timer;
TIMSK |= (1<<TOIE0);
TIFR |= (1<<TOV0);
};
ISR(TIMER0_OVF_vect)
{
TCNT0 = timer;
ms++;
if (ms >= 1000)
{
OCR1A++;
ms = 0;
}
if (OCR1A >= 2000)
OCR1A = 1000;
};*/
int main(void)
{
//Initialisierungen
sei(); //Globale Interupts zulassen
pwm_init(); //PWM initialisieren
/*timer_init(); //Timer initialisieren*/
DDRB |= (1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3); //B... AUSGANG
PORTB &= ~((1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3)); //B.. Low
while(1)
{
}
}
-
Damit ein Interrupt ausgelöst wird muss generell folgendes geschehen: das I-bit in SREG muss gesetzt sein, der Interrupt muss freigeschaltet sein, das interruptauslösende Ereigniss muss auftreten.
2 davon hast du gemacht, 1 nicht. =)
TIMSK | = (1<<TOIE2);
Nicht vergessen: immer, wenn du ein interrupt benutzen willst, musst du ihn erstmal erlauben (freischalten)
Damit sollte es funktionieren.
Und noch ein Tipp: wenn du Konstanten eingibst, die größer sind als 32768, dann schreibe ein UL (= unsigned long) dahinter, denn viele compiler nehmen konstanten generell als ein int auf, was bei den AVRs 16bit ist. Also: F_CPU 16000000UL (ist besser).
Gruß, Yaro
-
Ok, das hat was geändert. Danke dir
Aber ich krieg jetzt ein Signal das .5ms high .8ms low .6ms high und dann
14ms low ist.
-
wow.....das ist wirklich seltsam......
Wie kommst du auf diese Zeiten? Wie hast du sie gemessen? Mit einem Oszi?
Wenn es digital ist, könntest du dann die Kurven posten (neu und alt)?
Du könntest versuchen, TCNT2 im Interrupt des 16bit Timers auf 0x00 zu setzen, sollte aber nur minimalen Erfolg bringen.
[edit]Versuch den Timer2 mal auf Fast-PWM umzustellen, das sollte eine deutlich Verbesserung bringen. Achte dabei auf die Frequenz, wirst den Prescaler auf eine Stufe höher stellen müssen, da Fast-PWM doppelt so schnell ist, wie phase-correct PWM.
-
Ich hab jetzt das ganze invertiert, sprich es wird gesetzt beim hochzählen und gelöscht beim runterzählen.
So funktionierts, mit dem Nachteil das ich auch OCR2 invertiert übergeben muss.
Da gibts aber noch Fast PWM und das funktioniert perfekt (Es sieht auf jedenfall so aus :))
Vielen herzlichen dank für deine wirklich tolle Hilfe =D>
-
Immer doch gerne.
Mich interessiert trotzdem noch, wie du die Zeiten gemessen hast =)
Gruß, Yaro
-
Achso entschuldige, mit einem Oszi :)
Das Ding ist sowas von praktisch wen's um solche Signale geht.
-
Ich krieg die Krise
Die sache läuft ja jetzt... könnte man meinen.
Auf dem Oszi sehen alle Signale gleich aus.
Wen ich die ersten beiden PWMkanäle benutze fahren die Servos bei 1,5ms Highflanke in die mitte,
Wen ich aber den dritten Kanal benutze fährt das Servo an eine Positon die weiter liegt als der mechanische Anschlag. Also völlig falsch da es auch zur Mitte fahren sollte.
Ich hab mit dem Oszi die Signale verglichen. Und der einzige Unterschied von Signal drei zu den anderen ist der, dass es 10ms später startet.
Das heisst die beiden ersten Signale haben im gleichen Moment die Highflanke und das dritte hat erst 10ms später die Highflanke.
Aber das sollte dem Servo doch egal sein, das interessiert sich doch nur für die 1-2ms High und eine Periodendauer von 20ms.
Am Servo liegt es nicht!
Ich bin am verzweifeln.
Die ersten beiden Signale:
Bild hier
Das erste und das dritte Signal:
Bild hier
-
Hmm das ist wirklich sehr komisch! Dem Servo sollte das eigentlich egal sein... er weiß doch nicht, wie sich die beiden anderen verhalten... und sollte sich dafür auch nicht kümmern.
Wie sieht es denn mit deiner Hardware aus? was genau hast du gebaut? besteht womöglich die Möglichkeit, dass der dritte Servo gestört wird? Hast du vielleicht irgendeinen unbemerkten Kontakt mit einem anderen Leiter? (jetzt nicht auf der Signalleitung sondern auf der Versorgungsleitung des Servos)
Diese 4 (2Paar) Pukte in der unteren Mitte der Bildes, kommen die vom Controller, oder zeichnet sie das Oszi immer dahin?
Gruß, Yaro