Hi Leutz, ich möchte eine Pulsweite (konstante Periodendauer) mit dem AT Mega8535 messen. Lt. Beschreibung des 16Bit - Timers gibt es da eine Möglichkeit, dass der Timer automatisch so lange läuft, wie der Impuls anliegt. Leider steige ich durch die Doku da nicht ganz durch... Hat jemand so etwas schon mal programmiert und könnte mir helfen ? Greetz, tho
die Timer sind eigentlich dazu da die PWM (Pulsweitenmodulation) zu erzeugen. Du kannst allerdings das so lösen, indem du den Pin (wo das PWM signal anliegt) in einer schleife abfragst, und wenn der Impuls anliegt, startest du den Timer, sobald impuls aufhört stopst du den timer. Danach timerinhalt auslesen, einfacher geht es nun wirklich nicht. Andere Lösung du benutzt einen einfachen Tiefpass (evtl. aktiven Tiefpaß mittels OPV zur erzeugung einer gleichspannung aus dem PWM signal) und benutzt den ADC des Atmega. Anhand der gemessenen Gleichspannung rechnest du dir dann das Tastverhältniss aus. Da du ja weisst, dass die Periodenlänge konstant ist, wie du uns mitgeteilt hast, kannst du dir die Pulsweite ausrechen. Tast = Umess/Umax Pulsweite = T_PWMPeriod * Tast T_PWMPeriod : konstante Periodenlänge des PWM signals Umess : am ADC gemessene Spg. Umax : Spannung des High- Impulses deines PWM Signals G. Tobias
Das scheint mir nun doch arg von hinten durch die Brust ins Auge. Impulse detektiert man gemeinhin mit dem INT0- oder dem INT1-Eingang, woraufhin die Interrupt Service Routine den Timer abfragt, den Wert ablegt, den Timer Null setzt und erneut startet. Ist aus praktischer Erfahrung eine recht zuverlässige und genaue Methode, wenn man nicht mit Mikrosekunden geizen muss. mfg gerd
> Das scheint mir nun doch arg von hinten durch die Brust ins Auge. > Impulse detektiert man gemeinhin mit dem INT0- oder dem > INT1-Eingang, woraufhin die Interrupt Service Routine den Timer > abfragt, den Wert ablegt, den Timer Null setzt und erneut startet. Das scheint mir nun doch arg von hinten durch die Brust ins Auge. ;-) Für sowas ist beim 8535 die Input-Capture-Unit des 16bit-Timers da. Damit geht's dann auch taktzyklengenau.
@Rolf Ja, das wäre schön. Wenn nur ATMEL vorgesehen hätte, nicht nur entweder positive oder negative Flanken, aber keinesfalls beide, sowie ein automatisches Rücksetzen des Timers beim Match mit als Option dazu zu geben. Dann wäre das eine brauchbare, genaue und fast vollautomatische Sache. Wer nur entweder active low oder active high oder sogar abwechselnd beide messen will (z.B. um ein Pulsweitenverhältnis daraus auszurechnen), muss sich da in der Interrupt-Service-Routine ganz schön verrenken. Die Beschreibung der Input-Capture-Unit strotzt nur so von wenn's und aber's, z.B. wenn man die zu detektierende Flanke wechselt. mfg gerd
Hi Leutz, eigendlich hatte ich gehofft, man könnte über einen mit dem CLK-Signal ver-UNDeden Eingang messen ... aber das scheint so nicht zu gehen. Zumindest nicht so einfach, und ich brauch das ganze auch 2 mal (2 PWMs zu messen). Ich schalte den INT jetzt zwischen rising und falling um. Zeitasis ist der 8Bit Timer / 1024 und Overflow, der 16Bit Timer wird vom Int gestartet und gestoppt. Die Messergebnisse sind schon ziemlich gut vgl. mit Scope. Latürnich möchte ich euch den Code nicht vorenthalten. Da gibtz sicher noch was zu verbessern. Wer das selber sucht: Hier isses, wer Verbessungsvorschläge hat, her damit gg btw: Debugging mache ich mit dem Scope (Tektronix Digiscope), PORTB = 1 bzw. 0 ist zum Debuggen der Software ;-) INTERRUPT(SIG_INTERRUPT0) { if(xrising) //Timer starten { //PORTB=1; bit_on(TCCR1B, CS10); // clk/1, Timer start bit_on(MCUCR, ISC01); //Int0 falling edge bit_off(MCUCR, ISC00); //Int0 falling edge xrising=0; } else //Timer stoppen { //PORTB=0; bit_off(TCCR1B, CS10); // timer stop xhigh = TCNT1/10; bit_off(GICR,INT0); //Int0 inaktiv xrising=1; xmess=1; } } INTERRUPT(SIG_OVERFLOW0) { /* if(out) //Rechteck am PORTB erzeugen out=0; else out=1; PORTB = out; */ bit_on(MCUCR, ISC01); //Int0 rising edge bit_on(MCUCR, ISC00); bit_on(GIFR, INTF0); //INT0 - Flag löschen TCNT1 = 0; //Zählerstand löschen bit_on(GICR,INT0); //Int0 aktiv } int main() { //Timer 16Bit als Zähler interner Impulse bit_off(TCCR1A, COM1A0); //normal port operation, OC1A/B disconnected bit_off(TCCR1A, COM1A1); bit_off(TCCR1A, COM1B0); bit_off(TCCR1A, COM1B1); bit_off(TCCR1A, WGM10); //Timer / Counter Mode normal bit_off(TCCR1A, WGM11); bit_off(TCCR1B, WGM12); bit_off(TCCR1B, WGM13); TCNT1 = 0x00; //Timer-Reg. löschen //bit_on(TIMSK, TOIE1); //Overflow INT enable bit_off(TCCR1B, CS10); // timer stop bit_off(TCCR1B, CS11); bit_off(TCCR1B, CS12); //Timer 8Bit setup bit_off(TCCR0, WGM00); //Waveform Generation mode: Normal (off) bit_off(TCCR0, WGM01); bit_off(TCCR0, COM00); //normal Port Operation, OC0 disconnected bit_off(TCCR0, COM01); bit_on(TCCR0, CS00); //Int. CLK/1024 bit_off(TCCR0, CS01); bit_on(TCCR0, CS02); TCNT0 = 0x00; //Timer-Reg. löschen bit_on(TIMSK, TOIE0); //Overflow-Int. enable //Interrupt 0 DDRD = 0x00; DDRB = 0xff; PORTB = 0x00; ... bit_on(MCUCR, ISC01); //Int0 rising edge bit_on(MCUCR, ISC00); bit_off(GICR,INT0); //Int0 inaktiv sei(); //Globale Interrupt enable ... } Greetz, Th. de Buhr
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.