- 3D-Druck Einstieg und Tipps         
Ergebnis 1 bis 10 von 10

Thema: PWM-Messung mit ATTiny15 - INT0 TIMER0

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    09.10.2005
    Beiträge
    17

    PWM-Messung mit ATTiny15 - INT0 TIMER0

    Anzeige

    LiFePo4 Akku selber bauen - Video
    Hallo Zusammen,

    ich habe eine Frage zur Nutzung eines ATTiny15L zur "Messung" (eher Detektion von 2 Werten (an/aus = max/min) eines
    PWM-Signals am Empfänger einer Modellfernsteuerung.
    Zum grundsätzlichen Test habe ich zunächst ein Programm für einen AT MEGA 8 geschrieben, was auch ganz gut funktioniert.
    Es liefert je nach Breite des H-Impulses (hab einen Servotester am INT-Eingang angeschlossen) entsp. valide Timerwerte.
    Der Code für den MEGA8 sieht so aus:
    Code:
    ' Testprogramm zur Auswertung eines Servosignals (PWM) und Anzeige
    ' der Wertes (Timer) auf dem LCD DIsplay (Typ: EA W204B-NLW (Reichelt)
    '
    ' Zuordnung:   LCD RW  = Pin5  = GND
    '              LCD RS  = Pin4  = PortC.5
    '              LCD E   = Pin6  = PortC.4
    '              LCD DB4 = Pin11 = PortC.3
    '              LCD DB5 = Pin12 = PortC.2
    '              LCD DB6 = Pin13 = PortC.1
    '              LCD DB7 = Pin14 = PortD.2
    '              LCD GND = Pin1
    '              LCD Vdd = Pin2    (+5V)
    '              LCD Vee = Pin3    (Contrast)
    '              LCD LED+ = Pin15
    '              LCD LED- = Pin16
    '
    ' Interrup-Eingang Mode: Change Pin: PD2 (4) = Servosignal (PWM H-Pgel: ~1.6 - 2.5ms)
    
    
    $regfile = "m8def.dat"                                      ' MC-Definitionen laden
    $crystal = 16000000                                         ' Quarzfrequenz
    
    Dim A As Byte                                               ' Variable deklarieren
                                                                ' der folgende Befehl ordnet die PORT-Pins den Signalen
                                                                ' gemäß der obigen Verkabelung zu
    
    
    Dim Timerwert As Byte					    ' Übergabevariable des Timers
    
    Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portc.4 , Rs = Portc.5
    
    Config Lcd = 20 * 4                                         ' definiert das Display als 20 x 4
    Config Lcdbus = 4                                           ' definiert 4Bit-Kommunikation
    
    Config Timer0 = Timer , Prescale = 1024                     ' Konfiguration Timer0 auf 64 Mikrosek. 
    Enable Timer0                                               ' pro Takt, überlauf bei ca. 16ms
    							    ' bei 16MHz: 1/(16.000.000/1024) = ein TimerIcement 
    							    ' alle 64 Mikrosek
    							    '
    
    
    
                                                                ' 
    Config Int0 = Change                                        ' Konfiguration Int0 auf wechselnde Flanke
    Enable Interrupts                                           ' einschalten der Interrupts
    Enable Int0                                                 ' einschalten von Interrupt Int0
    On Int0 Servowert		                            ' Definition Sprungmarke INT0
    
    Cls                                                         ' Display löschen
    
    Lcd "INT-TESTER"                                            ' Text auf das Display schreiben
    
    Do                                                          ' Hauptschleife
    
    Locate 3 , 1 : Lcd "Servo: " : Lcd Timerwert                ' Augabe der Wertes auf Diplayposition (Zeile, Spalte)
    
    
    Loop
    
    End
    
    
    Servowert:
                                                                 ' Interrupt-Routine (INT0)
    Timerwert = Timer0                                           ' Timer-Wert wegspeichern und 
    Timer0 = 0						     ' zurücksetzen
    
    Return
    
    
    End
    Jetzt habe ich das Programm für den ATTiny15 umgeschrieben - musste leider die Erfahrung machen, das dieser Chip
    über kein SRAM verfügt, was man nutzen kann … aber für die Anforderung sollte es reichen.
    Habe auch schon mitbekommen, das Bascom nicht so gut geeignet ist um diese "kleinen" MC's zu programmieren ;-(

    Zunächst habe ich 2 LED's an die Ports B.3 und B.4 und das PWM-Signal an den INT0 (Pin7) anschlossen.
    Die LED an B.4 soll leuchten wenn der Min-Wert (Länge des H-Pegels ~1ms) des PWM-Signals anliegt und die LED an B.3 soll
    leuchten, wenn der Max-Wert (Länge des H-Pegels ~2.5ms) des PWM-Signals anliegt
    Leider funktioniert mein Programm nicht so richtig … egal wie lang der H-Impuls am INT-Eingang ist, es wird immer die LED
    am Port B.3 eingeschaltet. Das würde bedeuten, dass der Wert des Timers immer größer ist, als mein Schwellwert von "9"
    D.h. prizipiell muss also der INT ausgelöst werden … es scheint jedoch ein Problem mit dem Timer-Wert zu geben.
    Ich habe auch schon mit div. Schwellwerten experimentiert - es wird aber immer die LED an B.3 aktiviert.
    Habe ich bei der Berechnung etwas falsch gemacht ? Kann man die von mir verwendeten Operatoren und Befehle für
    den ATTiny15 überhaupt verwenden?

    Berechnung:
    System-Takt= 1.6MHz
    Prescaler 256 (Timer0)
    1/(1.600.000/256) = ein TimerIncrement alle 160Mikrosekunden

    Bei H-Impulslängen von ~1ms - 2.5ms müssten Timerwerte von 6(min) und 12(max) herauskommen - die Mitte (Schwellwert)
    liegt bei 9

    Hier der Code für den ATTiny15:
    Code:
    ' Auswertung eines PWM-Servosignals (ein Kanal) 
    ' PWM-Signal H-Pegel zwischen ~1ms und 2.5ms
    ' INT bei wechselnder Flanke
    
    
    $regfile = "ATtiny15.DAT"                                   ' MC-Definitionen laden
    $crystal = 1600000                                          ' Quarzfrequenz (internal Clock 1.6 Mhz)
    
    
    
    Config Portb.4 = Output					    ' Status-LED am Port B.4
    Config Portb.3 = Output					    ' Status-LED am Port B.3
    
    Config Timer0 = Timer , Prescale = 256                      ' Config Timer0 auf 160 Mikrosekunden pro Takt, 
    Enable Timer0                                               ' Überlauf bei ca. 40ms
    							    ' bei 1.6MHz: 1/(1.600.000/256) = ein TimerIncrement 
    							    ' alle 160 Mikrosek
    							    ' zu erwartender Zählerbereich von ~6 bei 1ms PWM
    							    ' und ~12 bei 2.5ms PWM
                                                                
    Config Int0 = Change                                        ' Konfiguration Int0 wechselnde Flanke
    Enable Interrupts                                           ' Einschalten der Interrupts
    Enable Int0                                                 ' Einschalten Von Interrupt Int0
    On Int0 Servowert		                            ' Definition Sprungmarke INT0
    
    
    Portb.4 = 0						    ' beide Ports aus (LED aus)
    Portb.3 = 0
    
    Do                                                          ' Hauptschleife
    Loop
    
    End
    
    
    Servowert:					    ' Interrupt-Routine (INT0)
    
    If Timer0 < 9 Then					    ' Schwellwert des Zählers gemittelt zwischen					    
           Portb.4 = 1					    ' den maximalen Werten: 6 und 12 = 9
           Portb.3 = 0
    Else
           Portb.4 = 0
           Portb.3 = 1
    End If                                                              
             
    Timer0 = 0						    ' Timer zurücksetzen
    
    Return
    
    
    End
    Wäre super, wenn jemand von den Experten mir einen Tipp geben könnte, was ich hier falsch gemacht habe.


    Vielen Dank,
    Ulf

  2. #2
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    15.01.2007
    Ort
    Göttingen
    Beiträge
    706
    Ich gehe mal davon aus, dass Du ein Empfänger-Signal auswertest, d.h. der zu messende Impuls ist High, und dazwischen kommen etwa 20ms Low.

    Dadurch, dass Du als Interrupt-Kriterium "Change" gewählt hast, wird der Timer0-Wert nicht nur nach der H/L-Flanke überprüft, sondern eben auch nach jeder L/H-Flanke, d.h. auch nach jeder Pause. Und die sind ja nun mal deutlich länger als 2ms!

    Versuch´s doch mal so:


    Code:
    ...
    ...
    Config INT0=Change
    ...
    ...
    
    
    Servowert:
     
     If PINB.2=0 then
        If Timer0 < 9 Then               
           Portb.4 = 1                   
           Portb.3 = 0
        Else
           Portb.4 = 0
           Portb.3 = 1
        End If                                                             
     End if 
             
    Timer0=0
    Return
    Damit wird die Überprüfung nur nach einem H/L-Wechsel ausgeführt, d.h. nur am Ende des eigentlichen Impulses. Sicher führen noch 999 andere Wege nach Rom, aber das wäre am nähesten an Deinem Code dran!

    P.S.: In Deiner Anwendung mit dem Mega8 und LCD-Display dürfte genau das selbe passiert sein: Die Variable A hatte abwechselnd immer den Wert der Impulslänge und den der Pausenlänge. Den Wert der Pausenlänge hatte sie aber nur während des Impulses, d.h. für 1-2ms. Und das ist definitiv so kurz, dass es weder ein LCD anzeigen noch das menschliche Auge wahrnehmen kann. Deshalb hat man nur das gesehen, was die meiste Zeit angezeigt wurde - die Impulsdauer.

    Ich hoffe, Du hast trotz meiner vielleicht etwas wirren Worte verstanden was ich meine

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    09.10.2005
    Beiträge
    17
    Hallo Sauerbruch,

    recht vielen Dank für den Tipp - Du hattest recht mit dem Auslösen des INT0 .. das passiert natürlich bei jedem Flankenwechsel. Habe das Programm für den MEGA8 gemäß Deinem Hinweis angepasst . Die Werte haben voher im Display immer etwas geflackert - jetzt tun sie das nicht mehr

    Aber beim Tiny15 bekomme ich das nicht hin. Ich bin da auch etwas irritiert.
    Beim MEGA8 läuft der TIMER0 mit dem System-Takt (bei mir 16MHz) beim ATTINY15 steht in der Spec, dass er (TIMER0) mit dem internen Takt von 25,6 MHz läuft und nicht mit 1.6MHZ. Aber selbst wenn ich die Werte in meinem Programm (PRESCALER=1024 und den Vergleichswert) anpasse bekomme ich es nicht hin. Ich werde noch ein wenig experimentieren und mich im Zweifelsfall nochmal melden.

    Vielen Dank erstmal,
    VG
    Ulf

  4. #4
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    15.01.2007
    Ort
    Göttingen
    Beiträge
    706
    In meinem Datenblatt vom Tiny15 steht, dass diese mittels PLL generierte Frequenz von 16 x 1,6MHz (=25,6 MHz) nur für Timer1 zur Verfügung steht. Timer0 sollte eigentlich immer am "normalen" Clock hängen.

    Du kannst die Taktrate einfach überprüfen, indem Du den Timer mit einem Prescaler von 1024 laufen lässt und in der Timer-ISR eine LED toggelst. Das sollte bei 1,6 MHz dann alle 0,16 Sekunden passieren, d.h. die LED blinkt mit etwa 3 Hz. Das ist ideal mit bloßem Auge auf Plausibilität zu überprüfen (geht ja nicht um die achte Nachkomma-Stelle...)

  5. #5
    Neuer Benutzer Öfters hier
    Registriert seit
    09.10.2005
    Beiträge
    17
    Hallo,

    zunächst mal recht vielen Dank für den Tipp mit dem LED-Toggle in der Timer-ISR.
    Es stimmte ... der Timer-INT wird definitv bei einem PRESCALER-WERT von 1024 ca. alle 0,16s ausgelöst, was zu einem Blinken der LED von ~3Hz führt.

    Ich habe noch eine Frage bzg. der Timer-Wertes - wo kann ich den Wert abgreifen (z.B. um ihn zu vergleichen) in TIMER0 oder in TCNT0 ? Kann es sein, dass die mathem. Operationen wie "<" oder ">" mit dem Tiny15 nicht verwendbar sind? Am Fernsteuer-Empfänger soll das PWM-Signal (ein max und ein min-Wert) detektiert werden. Das PWM-Signal hat einen H-Pegel, der zw. ~1ms und 2,5ms lang ist.
    Die Idee ist, mit dem Signal einen INT0 (PortB.2) jeweils an der steigenden Flanke und bei der fallenden Flanke auszulösen (nochamls Danke für den Tipp bzgl: "CHANGE". Der TIMER0 soll bei der steigenden Flange bei Null gestartet werden und bei der fallenden Flanke auswertet werden. Bei einem Takt des TIMER0 von 1.6MHz ergeben sich bei einem PRESCALER-Wert von 64 entspr. TIMER-Werte von ~25 (bei 1ms) und 63 (bei 2.5ms)

    Der Code sieht jetzt so aus ... funktioniert aber leider immer noch nicht ... hat noch jemand eine Idee ?

    Vielen Dank,
    Ulf


    Code:
    ' Auswertung eines PWM-Servosignals (ein Kanal)
    ' PWM-Signal H-Pegel zwischen ~1ms und 2.5ms
    ' INT bei wechselnder Flanke
    
    
    $regfile = "ATtiny15.DAT"                                   ' MC-Definitionen laden
                                                                   ' Quarzfrequenz (interal Clock 1.6 Mhz)
    
    
    
    Config Portb.4 = Output                                     ' Status-LED am Port B.4 (Pin2) grün
    Config Portb.3 = Output                                     ' Status-LED am Port B.3 (Pin3) gelb
    Config Portb.2 = Input
    
    Config Timer0 = Timer , Prescale = 64                       ' Config Timer0 auf 160 Mikrosekunden pro Takt,
    Enable Timer0
                                                                 '
    Start Timer0                                                ' bei 1.6MHz: 1/(1.600.000/64) = ein TimerIncrement
                                                                  ' alle 40 Mikrosek
                                                                  ' zu erwartender Zählerbereich von ~25 bei 1ms PWM
                                                                  ' und ~63 bei 2.5ms PWM
    
    Config Int0 = Change                                        ' Konfiguration Int0 (PortB.2) wechselnde Flanke
                                                                  ' Einschalten der Interrupts
    Enable Int0                                                 ' Einschalten Von Interrupt Int0
    On Int0 Servowert                                           ' Definition Sprungmarke INT0
    Enable Interrupts
    
    Portb.4 = 0                                                 ' beide Ports aus (LED aus)
    Portb.3 = 0
    
    
    
    Do                                                          ' Hauptschleife
    Loop
    
    End
    
    
    Servowert:                                                  ' Interrupt-Routine (INT0)
    
    
    If Portb.2 = 1 Then                                         ' steigende Flanke testen
     Tcnt0 = 0                                                  ' Timer zurücksetzen
     Start Timer0                                               ' Timer0 starten
     Return
    End If
    
    
    If Tcnt0 < 40 Then                                          ' Schwellwert des Zählers gemittelt zwischen
                                                              '    den maximalen Werten: 25 und 63
          Portb.3 = 1
          Return
    
    End If
    
    Portb.3 = 0
    
    Return

  6. #6
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    15.01.2007
    Ort
    Göttingen
    Beiträge
    706
    Ich selbst definere Anschlüsse immer direkt mit dem DDR-Register als Ein- oder Ausgang, deshalb ist mir diese Geschichte mit CONFIG PORT bzw. PIN nicht so vertraut. Aber ich habe dazu was interessantes in der Bascom-Hilfe gefunden:
    Syntax

    CONFIG PORTx = state

    CONFIG PINx.y = state
    Offenbar lassen sich einzelne Pins wohl nur mit Config PINB.3 definieren, während CONFIG PORTx alle Bits des Ports betrifft.
    Was auf jeden Fall geht ist
    DDRB = B&00011000
    (Setzt B.3 und B.4 als Ausgang, alle anderen als Eingang)

    Und zum "Auslesen" sind Timer0 und TCNT0 gleichwertig. TCNT0 benennt halt schon gleich das Register beim Namen, bei "Timer0" übersetzt das Bascom noch schnell.

  7. #7
    Neuer Benutzer Öfters hier
    Registriert seit
    09.10.2005
    Beiträge
    17

    Problem eingegrenzt ... aber

    Hallo,

    ich habe nach einigen Tests das Problem eingegrenzt. Es scheint an dem Code in der ISr des INT0 zu liegen - anscheinend sind bereits die paar Zeilen Code zu viel für einen Tiny15 .. sogar für einen MEGA8. Ich habe die gleiche Auswertung (also z.B. IF TCNT0 < 25 Then ...) im MEGA8 nachprogrammiert.
    Und siehe da ... selbst der MEGA8 ist dabei regelmäßig "abgestürzt".
    Vermutlich erzeugt Bascom beim compilieren soviel HEX-Code, dass es für die ISR zuviel wird (ich vermute mal "<" ">" wird recht komplexer Code beim Compilieren). Whatever ... ich breche an dieser Stelle zunächst ab und werde mir einen ATTiny25 besorgen und damit weitermachen ... der hat zumindest 128bytes SRAM (für Variablen)

    PS die Definition mit "CONFIG PORTB.3 = Input" funktioniert sehr gut wobei CONFIG PINB.3 = INPUT zwar keine Fehlermeldung erzeugt hat, aber auch irgendwie nicht funktioniert hat - habe das aber auch nicht weiter analysiert. Trotzdem Danke für den Tipp!

    Ich melde mich wieder wenn ich den ATTiny25 habe


    VG
    Ulf

  8. #8
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    15.01.2007
    Ort
    Göttingen
    Beiträge
    706
    PS die Definition mit "CONFIG PORTB.3 = Input" funktioniert sehr gut
    Das ist auch nicht verwunderlich, denn nach dem Einschalten sind alle I/O-Ports automatisch erstmal als Inputs konfiguriert. Auch ohne eine einzige Zeile Code...

    Was mich an Deiner ISR ziemlich gewundert hat, ist das mehrfache Verwenden von Return. Dafür hat mich Bascom schon mal ziemlich angemeckert - allerdings bei einem Mega88. Umso erstaunter war ich, als sich dieser Code für den Tiny15 anstandslos compilieren ließ. Aber es kann ganz schnell Probleme mit dem Stack geben, wenn man die ISR nicht "political correct" verlässt. Und das hässliche Wort "Abstürzen" klingt schwer nach Stack-Überlauf. Dass so ein paar < oder > - Operationen die ISR überfordern, kann ich mir dagegen beim besten Willen nicht vorstellen

    Wenn Du schon vermutest dass der Hund in der ISR begraben liegt, versuch´s doch mal mit nur einem Return am Schluss (dann wird die Zeit auch nicht so lange, bis der Tiny25 da ist). z.B. so:

    Code:
    ...
    ...
    
    
    Servowert:
     If PinB.2 = 0 then            'Timer-Auswertung nur nach HL-Flanke
        If Timer0 < 40 then
           PortB.3=0
           PortB.4=1
        Else
           PortB.3=1
           PortB.4=0
        End if
     Else                             'Ansonsten (nach LH-Flanke): Timer für nächste Runde auf 0 setzen
        Timer0=0
     End if
    Return

  9. #9
    Neuer Benutzer Öfters hier
    Registriert seit
    09.10.2005
    Beiträge
    17
    Habe den Code nochmals angepasst - schon richtig das mit RETURN innerhalb der IF THEN ELSE Section ist unsauber (aber Bascom hats nicht angemeckert)

    ... habe alles nochmals überprüft und alle möglichen Fehlerquellen eliminiert. Die Signalquelle für das PWM-Signal (mein Servotester) wurde durch den richtigen Empfänger ersetzt ... habe es auch mit einem richtigen Servo gecheckt, ob er sich auch bewegt.
    Habe sogar den ATTiny25 durch einen brandneuen Chip ersetzt. Es half Alles nix .. die LED's blinken jetzt mehr oder weniger unkoordiniert. (d.h. die ISR wird angesprungen) ... da das Programm auf dem MEGA8 läuft, vermute ich hier entweder Bascom als Fehlerquelle (vielleicht kommt BASCOmM mit dem Tiny15 nicht klar bzw. erzeugt keinen korrekten Code) oder das Signal am Fernsteuer-Empfänger ist nicht "sauber" oder sieht sogar komplett anders aus (habe leider keinen LA oder Oszi). Ich hoffe mein Tiny25 kommt morgen bei mir an ... dann sehe ich weiter

    Code:
    Code:
    ' Auswertung eines PWM-Servosignals (ein Kanal)
    ' PWM-Signal H-Pegel zwischen ~1ms und 2.5ms
    ' INT bei wechselnder Flanke
    
    
    $regfile = "ATtiny15.DAT"                                   ' MC-Definitionen laden
    $crystal = 1600000                                          ' Quarzfrequenz (interal Clock 1.6 Mhz)
    
    
    
    Config Portb.4 = Output                                     ' Status-LED am Port B.4 (Pin2) grün
    Config Portb.3 = Output                                     ' Status-LED am Port B.3 (Pin3) gelb
    Config Portb.2 = Input
    
    Config Timer0 = Timer , Prescale = 64                       ' Config Timer0 auf 160 Mikrosekunden pro Takt,
    Enable Timer0                                               
                                                                  ' bei 1.6MHz: 1/(1.600.000/64) = ein TimerIncrement
                                                                  ' alle 40 Mikrosek
                                                                  ' zu erwartender Zählerbereich von ~25 bei 1ms PWM
                                                                  ' und ~63bei 2.5ms PWM
    
    Config Int0 = Change                                        ' Konfiguration Int0 wechselnde Flanke
    Enable Interrupts                                           ' Einschalten der Interrupts
    Enable Int0                                                 ' Einschalten Von Interrupt Int0
    On Int0 Servowert                                           ' Definition Sprungmarke INT0
    
    
    Portb.4 = 0                                                 ' beide Ports aus (LED aus)
    Portb.3 = 0
    
    Do                                                          ' Hauptschleife
    Loop
    
    End
    
    
    Servowert:                                                  ' Interrupt-Routine (INT0)
    
    
    If Portb.2 = 0 Then                                         'Timer-Auswertung nur nach HL-Flanke
        If Tcnt0 < 40 Then
           Portb.3 = 0
           Portb.4 = 1
        Else
           Portb.3 = 1
           Portb.4 = 0
        End If
    Else                                                        'Ansonsten (nach LH-Flanke): Timer für nächste Runde auf 0 setzen
        Tcnt0 = 0
    End If
    
    
    Return

  10. #10
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    15.01.2007
    Ort
    Göttingen
    Beiträge
    706
    mein Tiny25 kommt morgen bei mir an ... dann sehe ich weiter
    Nee, nee, nee - das MUSS auch mit ´nem Tiny15 gehen [/nicht lockerlass]

    Deine ISR fängt so an:

    If PORTB.2 = 0 then
    ...
    ...

    Eingänge fragt man aber immer mit PINX.Y ab!!! [-X

    Da PORTB.2 (!) immer 0 ist, wird TCNT0 niemals auf 0 zurückgesetzt! D.h. der Timer läuft durch, ist ca. 1/5 der Zeit < 45 und die restlichen 4/5 > 45 - und schon flackern die LEDs!

    Wie heißt es so schön: Mikrocontroller machen zwar nur selten annähernd das, was man möchte - aber immer genau das, was man ihnen sagt

    Einen Versuch noch???

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Labornetzteil AliExpress