- LiTime Speicher und Akkus         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 14

Thema: Geschwindigkeit eines Programms (Interrupts, Timer)

  1. #1
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    06.02.2005
    Beiträge
    663

    Geschwindigkeit eines Programms (Interrupts, Timer)

    Anzeige

    Powerstation Test
    Hallo!

    Ich habe ein Programm welches das Signal zweier Lichtschranken auswertet. Dies geschieht über Interrupts (fallende Flanke). µC ist ein ATmega8 mit externem 16 MHz Quarz.
    Wenn der erste Interrupt (erste Schranke) ausgelöst wird, wird ein Timer gestartet, der eine Variable hochzählt. Wird der zweite Interrupt ausgelöst wird der Timer gestoppt und die Zählvariable(n) in eine Zeit und anschließend eine Geschwindigkeit umgerechnet und auf dem LCD ausgegeben.
    Meine Frage ist jetzt folgende: Wie "klein" kann ich den Timer konfigurieren, also wie klein sollte seine Frequenz sein?
    Denn letztlich möchte ich wissen, welche Messstrecke ich für eine bestimmte Genauigkeit benötige (Genauigkeit: +- 0,1km/h - Geschwindigkeit: max. 100km/h). Dafür müsste der Timer natürlich möglichst oft ausgeführt werden.

    Grüße, Björn

  2. #2
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    06.02.2005
    Beiträge
    663
    Hier mal das ganze Programm:

    Man sieht, der Timer ist auf 1MHz eingestellt, also Messeinheit 1µs. Schafft der µC das?

    Code:
    '#####################################################
    $regfile = "m8def.dat"                                      'ATmega8 mit externem 16 MHz Quarz
    $crystal = 16000000
    $baud = 9600
    
    '############ Variablen ##############################
    Dim Mikrosekunden As Long
    Dim Sekunden As Single
    Dim Geschwindigkeit As Single
    Dim Strecke As Single
    Dim Ausgabe As String * 5
    Strecke = 0.1                                               'Länge der Messstrecke in Metern
    
    '############ Interrupts & Timer konfigurieren #######
    Config Int0 = Falling                                       'Beide Male bei fallender Flanke reagieren
    Config Int1 = Falling
    Enable Interrupts
    Enable Int0                                                 'Die Erste Schranke aktivieren, die zweite noch sperren
    On Int0 Isr_schranke1
    On Int1 Isr_schranke2
    
    Config Timer1 = Timer , Prescale = 1
    On Timer1 Timer_irq
    Const Timervorgabe = 65520
    
    '############ Ein- und Ausgänge ######################
    Config Portd.6 = Output
    Config Portd.7 = Output
    Config Portb.0 = Output
    Portd.2 = 1                                                 'Interne Pull-Up Widerstände aktivieren
    Portd.3 = 1
    
    '############ LCD Display ############################
    Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , _
    Db7 = Portc.0 , E = Portc.4 , Rs = Portc.5
    Config Lcd = 16 * 1
    
    Cls
    Cursor Off Noblink
    
    '############ Bezeichnungen ##########################
    Schranke1 Alias Pind.2
    Schranke2 Alias Pind.3
    Led1 Alias Portd.6
    Led2 Alias Portd.7
    Lcdlicht Alias Portb.0
    
    '############ Hauptschleife ##########################
    Do
       If Schranke1 = 0 Then Led1 = 0 Else Led1 = 1
       If Schranke2 = 0 Then Led2 = 0 Else Led2 = 1
    Loop
    
    End
    
    '############ Interrupt-Routinen #####################
    Isr_schranke1:
       Disable Int1
       Enable Timer1
    Return
    
    Isr_schranke2:
       Disable Timer1
       Sekunden = Mikrosekunden / 1000000
       Geschwindigkeit = Strecke / Sekunden
       Geschwindigkeit = Geschwindigkeit * 3.6
       Ausgabe = Fusing(geschwindigkeit , "#.#")
    
       Cls
       Lcd Ausgabe
    
       Mikrosekunden = 0
       Enable Int0
    Return
    
    Timer_irq:
       Timer1 = Timervorgabe
       Incr Mikrosekunden
    Return
    Grüße, Björn

  3. #3
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    15.01.2007
    Ort
    Göttingen
    Beiträge
    706
    Mit dem Timer-Reload von 65520 erreichst Du zwar, dass der Zähler 16 Takte nach seinem Start überläuft. Man muss aber bedenken, dass so ein Interrupt auch eine erhebliche Anzahl an Takten "verbraucht", bis es in die eigentliche ISR geht (es müssen allerlei Registerinhalte gerettet werden etc.). Diese Zyklen kommen also noch dazu, und wenn ich ihren Wert auch nicht genau weiss, liegen sie aber in einer Größenordnung, die die angepeilte Mikrosekunde erheblich verfälschen würden.
    Brauchst Du die Zeit denn tatsächlich in Mikrosekunden?

  4. #4
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    06.02.2005
    Beiträge
    663
    Zitat Zitat von Sauerbruch
    Mit dem Timer-Reload von 65520 erreichst Du zwar, dass der Zähler 16 Takte nach seinem Start überläuft. Man muss aber bedenken, dass so ein Interrupt auch eine erhebliche Anzahl an Takten "verbraucht", bis es in die eigentliche ISR geht (es müssen allerlei Registerinhalte gerettet werden etc.). Diese Zyklen kommen also noch dazu, und wenn ich ihren Wert auch nicht genau weiss, liegen sie aber in einer Größenordnung, die die angepeilte Mikrosekunde erheblich verfälschen würden.
    Brauchst Du die Zeit denn tatsächlich in Mikrosekunden?
    Nein, nicht unbedingt. wären 100µs, also 0,1ms Schritte möglich? Der Timer also mit einer Frequenz von 10Khz?

    Grüße, Björn

  5. #5
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    15.01.2007
    Ort
    Göttingen
    Beiträge
    706
    wären 100µs, also 0,1ms Schritte möglich? Der Timer also mit einer Frequenz von 10Khz?
    Klar, im Prinzip schon: 0,1ms entspricht bei einer Taktfrequenz von 16MHz genau 1600 Zyklen. Der Timer-Preset müsste also mit etwa (!) 65535-1600, also 63935 gewählt werden.
    Das Problem mit den Zyklen, die bis zum Sprung in die ISR vergehen, hast Du natürlich auch hier, nur fallen bei 1600 Taktzyklen 10-15 nicht ganz so ins Gewicht. Unschön ist´s aber irgndwie trotzdem, aber es gäbe zwei Alternativen:

    Probier mal im Simulator aus, wieviele Taktzyklen bei einem Timer-Überlauf-Interrupt vergehen - die müsstest Du dann von den 1600 abziehen. Mit diesem Timer-Preset hättest Du dann genau 100µs.

    Oder ganz anders: Mit ISR_schranke1 startest Du den Timer, bei 16MHz und einem Prescaler von 1024 zählt der Timer alle 64µs um eins weiter. In der ISR_schranke2 stoppst Du ihn, das Ergebnis noch mit 1000 multiplizieren und anschließend durch 64 teilen - fertig ist die Zeit in ms.

    Die zweite Methode hat als Einschränkung, dass der Timer nach etwas über 4 Sekunden überläuft - die Zeit zwischen den beiden Lichtschranken-Passagen darf also nicht länger sein. Bei 100km/h entsprechen 4 Sekunden ja aber schon ener ganz ordentlichen Strecke...

    Dann fahrt mal immer schön vorsichtig (*lach...),

    Daniel

  6. #6
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    06.02.2005
    Beiträge
    663
    Zitat Zitat von Sauerbruch
    wären 100µs, also 0,1ms Schritte möglich? Der Timer also mit einer Frequenz von 10Khz?
    Klar, im Prinzip schon: 0,1ms entspricht bei einer Taktfrequenz von 16MHz genau 1600 Zyklen. Der Timer-Preset müsste also mit etwa (!) 65535-1600, also 63635 gewählt werden.
    Das Problem mit den Zyklen, die bis zum Sprung in die ISR vergehen, hast Du natürlich auch hier, nur fallen bei 1600 Taktzyklen 10-15 nicht ganz so ins Gewicht. Unschön ist´s aber irgndwie trotzdem, aber es gäbe zwei Alternativen:

    Probier mal im Simulator aus, wieviele Taktzyklen bei einem Timer-Überlauf-Interrupt vergehen - die müsstest Du dann von den 1600 abziehen. Mit diesem Timer-Preset hättest Du dann genau 100µs.

    Oder ganz anders: Mit ISR_schranke1 startest Du den Timer, bei 16MHz und einem Prescaler von 1024 zählt der Timer alle 64µs um eins weiter. In der ISR_schranke2 stoppst Du ihn, das Ergebnis noch mit 1000 multiplizieren und anschließend durch 64 teilen - fertig ist die Zeit in ms.

    Die zweite Methode hat als Einschränkung, dass der Timer nach etwas über 4 Sekunden überläuft - die Zeit zwischen den beiden Lichtschranken-Passagen darf also nicht länger sein. Bei 100km/h entsprechen 4 Sekunden ja aber schon ener ganz ordentlichen Strecke...

    Dann fahrt mal immer schön vorsichtig (*lach...),

    Daniel
    Hallo Daniel!

    Vielen Dank für die Tipps! Und die zweite Variante wäre auch genau? Dann würde ich die nehmen. Die Durchfahrtszeit sind liegt ja im Sekundenbruchteil-Bereich, somit wäre das Timer-Überlaufen kein Problem.
    Oder spricht sonst etwas gegen die zweite Variante ?

    Grüße, Björn

    //Edit: Welchen Timervorgabe-Wert muss ich denn dann nehmen?

  7. #7
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    15.01.2007
    Ort
    Göttingen
    Beiträge
    706
    Die 2. Variante ist IMHO definitiv genau. Bei beiden Interrupts entsteht die gleiche (minimalste) Zeitverzögerung zwischen Auslösen des Interrupts und Einspringen in die ISR – die Zeit, die der Timer läuft, entspricht also exakt der Zeit zwischen den beiden Lichtschranken-Passagen.

    Ich habe aber natürlich trotzdem einen Denkfehler gemacht: Der Timer zählt (bei 16 MHz und einem Prescaler von 1024) alle 64µs ein Bit weiter – man muss den Zählerstand also mit 64 malnehmen, um auf die Zeit zu kommen, und ihn nicht durch 64 teilen. Dieses Produkt dann durch 1000 geteilt ergibt die Zeit in ms.

    Folglich muss der Zähler immer bei 0 starten – hat er z.B. bis 7628 gezählt, sind 488 ms vergangen. Nach dem Stoppen in der ISR_lichtschranke2 übergibst Du seinen Wert an eine Variable und setzt ihn auf 0 zurück – für den nächsten Start (die Variable muss dabei ausreichend groß dimensioniert sein, um sich noch mit 64 multiplizieren zu lassen!). Außerdem wäre es elegant, in dieser Stop-ISR ein Flag-Bit zu setzen, das der Hauptschleife anzeigt, dass jetzt die Zeit berechnet werden kann und soll. Damit bleibt die ISR schön kurz und hält das Hauptprogramm nicht länger auf als nötig.


    Alles klar??

  8. #8
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    06.02.2005
    Beiträge
    663
    Zitat Zitat von Sauerbruch
    Die 2. Variante ist IMHO definitiv genau. Bei beiden Interrupts entsteht die gleiche (minimalste) Zeitverzögerung zwischen Auslösen des Interrupts und Einspringen in die ISR – die Zeit, die der Timer läuft, entspricht also exakt der Zeit zwischen den beiden Lichtschranken-Passagen.

    Ich habe aber natürlich trotzdem einen Denkfehler gemacht: Der Timer zählt (bei 16 MHz und einem Prescaler von 1024) alle 64µs ein Bit weiter – man muss den Zählerstand also mit 64 malnehmen, um auf die Zeit zu kommen, und ihn nicht durch 64 teilen. Dieses Produkt dann durch 1000 geteilt ergibt die Zeit in ms.

    Folglich muss der Zähler immer bei 0 starten – hat er z.B. bis 7628 gezählt, sind 488 ms vergangen. Nach dem Stoppen in der ISR_lichtschranke2 übergibst Du seinen Wert an eine Variable und setzt ihn auf 0 zurück – für den nächsten Start (die Variable muss dabei ausreichend groß dimensioniert sein, um sich noch mit 64 multiplizieren zu lassen!). Außerdem wäre es elegant, in dieser Stop-ISR ein Flag-Bit zu setzen, das der Hauptschleife anzeigt, dass jetzt die Zeit berechnet werden kann und soll. Damit bleibt die ISR schön kurz und hält das Hauptprogramm nicht länger auf als nötig.


    Alles klar??
    Also so ganz hat's noch nicht geklickt.
    Denn "... übergibts du seinen Wert an eine Variable und setzt ihn auf 0 zurück ..." - also verwende ich keine Variable mehr, die "inkremiert" wird?

    Grüße, Björn

  9. #9
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    15.01.2007
    Ort
    Göttingen
    Beiträge
    706
    also verwende ich keine Variable mehr, die "inkremiert" wird?
    ...exakt!

    Ein Programm sagt mehr als 1000 Worte :

    Code:
    Dim Zeit as Long
    Dim Flag as Bit
    
    Config Timer1=timer, prescale=1024
    Stop Timer1
    Timer1=0
    
    Config INT0=falling
    On INT0 ISR_lichtschranke1
    Enable INT0
    
    Config INT1=falling
    On INT1 ISR_lichtschranke2
    Enable INT1
    
    Enable Interrupts
    
    
    Do
    
    (werkel - werkel...)
    
     If Flag=1 then
      Zeit = Zeit * 64
      Zeit = Zeit / 1000      'Zeit ist jetzt die Zeit in ms. Umrechnung in km/h 
                                 hängt vom Abstand der Lichtschranken ab!!
      Flag = 0 
     End if
    
    Loop
    
    
    ISR_lichtschranke1:      '1. Lichtschranke wurde passiert
    Start Timer1
    Return
    
    ISR_lichtschranke2:      '2. Lichtschranke wurde passiert
    Stop Timer1
    Zeit=Timer1
    Timer1=0
    Flag=1
    Return

    Isses jetzt etwas klarer?

    LG,

    Daniel

  10. #10
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    06.02.2005
    Beiträge
    663
    Ah.. jetzt ist's klar - Hast du die Timer-Konfiguration am Anfang weggelassen? Oder braucht man die nicht?

    Grüße, Björn

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

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

LiFePO4 Speicher Test