Forum: Mikrocontroller und Digitale Elektronik Impulslängenmessung mit AT Mega 8535


von Thorsten (Gast)


Lesenswert?

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

von Tobias (Gast)


Lesenswert?

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

von gerd (Gast)


Lesenswert?

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

von Rolf Magnus (Gast)


Lesenswert?

> 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.

von gerd (Gast)


Lesenswert?

@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

von Thorsten (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.