- Akku Tests und Balkonkraftwerk Speicher         
Seite 1 von 3 123 LetzteLetzte
Ergebnis 1 bis 10 von 23

Thema: Riesen Problem mit Int0, Timer1 und Impulszählung

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    14.12.2005
    Beiträge
    161

    Riesen Problem mit Int0, Timer1 und Impulszählung

    Anzeige

    LiFePo4 Akku selber bauen - Video
    Hallo zusammen,

    ich habe ein riesieges Problem.
    Ich habe einen Code bei dem über den Int0 die Impulse eines Durchflussmessers kontinuierlich gezählt werden. Wichtig ist das kein Impuls verloren geht. Gleichzeitig soll aber der Gesamtwert der Impulszählung über RS232 jede Sekunde ausgegeben werden.

    Das Problem das ich jetzt habe ist, das zwar die Impulse gezählt werden aber bei höherer Frequenz die Daten nicht gesendet werden, da ja ständig der Interrupt des Impulszählers "aktiv" ist. Erst wenn keine Impulse mehr kommen bzw. die Impulsrate wieder sehr niedrig ist werden die Daten ausgegeben.

    Die max. Impulszahl die kommen kann ist je nach Durchflussmengenmesser um die 30.000 Impulse/Min.

    Wie kann ich das Problem lösen?

    Hier der Code:

    Code:
    $regfile = "m8def.dat"
    $crystal = 3686400
    $baud = 9600
    
    Dim Eu As Word 
    Dim Dfmimpulse As Long
    Dim Tv As Integer
    Dim Ti As Byte
    Dim Tb As Byte
    Dim Tank As Integer
    
    
    Config Timer1 = Timer , Prescale = 64
    Timer1 = 7936
    
    Config Int0 = Falling
    Config Pind.2 = Input                                       'Int0 bei Mega8
    Portd.2 = 1
    
    
    Config Adc = Single , Prescaler = Auto
    
    Config Pinc.0 = Input                                       'ADC0 ein
    Config Pinc.1 = Output                                      'Status LED Setup
    Config Pinc.2 = Output                                      'Status LED Datensenden
    Config Pinc.3 = Output                                      'Status LED impulse
    
    Declare Sub Irq0
    Declare Sub Datensenden
    
    On Timer1 Datensenden
    Enable Timer1
    
    On Int0 Irq0
    Enable Int0
    
    Enable Interrupts
    
    '-------------------
    'Main
    '-------------------
    
    Portc.1 = 1
    Portc.2 = 0
    Portc.3 = 1
    
    Dfmimpulse = 0
    Tv = 5000
    Ti = 0
    Tb = 20
    Tank = 0
    
    Do
    Portc.2 = 1
    Portc.3 = 1
    
    Start Adc                                      'Messung Akkuspannung
    Eu = Getadc(0)
    Stop Adc
    
    '***Hier stehen noch ein paar interne Berechnungen
    
    Portc.2 = 1
    
    Loop
    
    '-------------------
    'Sub IrQ
    '-------------------
    
    Irq0:
       Portc.3 = 0
       Decr Tv              'für weitere interne Berechnungen
       Incr Ti                'für weitere interne Berechnungen
    
       If Ti = Tb Then       'für weitere interne Berechnungen
          Ti = 0                   'für weitere interne Berechnungen
          Incr Tank              'Für weitere interne Berechnungen
          End If                    'für weitere interne Berechnungen
    
    
       Incr Dfmimpulse       'Der ist wichtig und muss über RS232 raus
       Return
    
    '--------------------
    'Sub RS232
    '--------------------
    
     Datensenden:
    
    Portc.2 = 0
    
    Print Dfmimpulse
    
    Return

    Und nu???????? Datensenden nicht über Timer? Oder geht es irgendwie das über den Timer die Daten gesendet werden und die Zählung der Impulse trotzdem weiterläuft?

    Wie gesagt zwei Sachen sind wichtig: 1. Kein einziger Impuls darf verloren (nicht gezählt) werden. 2. Die Daten müssen alle 1 Sekunde gesandt werden.

    Stehe jetzt voll auf dem Schlauch

    Gruß
    Markus

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    30.10.2005
    Ort
    Mönchengladbach
    Alter
    54
    Beiträge
    114
    Ohne mir den Code angesehen zu haben: wenn es tatsächlich so ist, dass die Interrupt-Routine für den Zähler so häufig angestoßen wird, dass der Prozessor zu nichts anderem mehr kommt, fallen mir zwei Lösungsansätze aus dem Stegreif ein:

    1. Schnellere Taktung: Laut $crystal hats du einen 3.7 MHz Quartz im Einsatz. Tausche ihn gegen etwas deutlich schnelleres aus. Wenn du nur sekündlich ein paar Bytes überträgst und dazwischen immer wieder Sendepausen auf der RS232 herrschen, ist der Timingfehler zu verbachlässigen, insodern kommt durchaus ein 16MHz Quartz in Betracht, also immerhin die vierfache Geschwindigkeit.

    2. Softwareoptimierung: Ich selber arbeite nicht mit Basic, kann also nichts dazu sagen, wie gut der erzeugte Code optimiert ist. Bei AVR-GCC bemerke ich deutliche Unterschiede zwischen den veschiedenen Optimirungsstufen. Zur Not muss man halt selbst zeitkritische Teile in Assembler proggen, was aber sicherlich ein hartes Los für einen Hochsprachler ist.

    Gruß,
    Chris

  3. #3
    Benutzer Stammmitglied
    Registriert seit
    14.09.2005
    Alter
    68
    Beiträge
    77
    Du muß einen Timer als Counter benutzen und damit die Impulse zählen, und den andren Timer als Timer um jede Sekunde den Wert vom Counter über die RS232 auszugeben.

    Edit:
    Sicher kann er den Controller schneller Takten, irgendwann wird es dann klappen. Das ist heute so die Regel. Man schreibt ein schlechtes Programm und ändert die Hartware damit es läuft. Als die Amerikaner zum Mond flogen hatten die keine Controller mit 3 Mhz, und heute können wir nicht mal ein paar Impulse mit 3 Mhz zählen.

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    30.10.2005
    Ort
    Mönchengladbach
    Alter
    54
    Beiträge
    114
    Für die Impulszählung ist kein Timer nötig, das geht über externe Interrupts einwandfrei, schliesslich soll nur die Anzahl der Impulse gezählt werden, aber nicht ihre Frequenz (so hab ichs zumindest verstanden).

    Timer1 (10bit) kann dann als Sekundentimer genutzt werden (CTC Mode).

    Was die Geschichte mit der Optimierung durch schnellere Hardware angeht: für mich ein klares Dingen. Wenn ich Software optimieren möchte, weils mir ein gutes Gefühl gibt, dann optimiere ich Software. Wenn ich schnell zum Ziel kommen muss oder möchte, dann greife ich auch zum schnellen Mittel.

  5. #5
    Benutzer Stammmitglied
    Registriert seit
    14.09.2005
    Alter
    68
    Beiträge
    77
    Zitat Zitat von xanadu
    Für die Impulszählung ist kein Timer nötig, das geht über externe Interrupts einwandfrei, schliesslich soll nur die Anzahl der Impulse gezählt werden, aber nicht ihre Frequenz (so hab ichs zumindest verstanden).
    Genau das ist ja der Fehler den er auch gemacht hat. Wenn du mit einem externe Interrupts Impulse Zählst dann macht der Controller sonnst nichts als dauernd die Unterroutine des Interrupts auszuführen, und es bleibt keine Zeit für andres.

    Warum glaubst du den wozu das gut ist, dass man den Timer als Counter benutzen kann? Genau, dann werden die Impulse von der Hardware gezählt und belasten das laufende Programm nicht. Nur bei einem Überlauf, oder bei einem Interrupts durch eine Timer wird das Programm Unterbrochen. Also bei Ihm hier jede Sekunde.

  6. #6
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    30.10.2005
    Ort
    Mönchengladbach
    Alter
    54
    Beiträge
    114
    Ah jetzt ja. Jetzt hab ich verstanden. Okay, den Ansatz lasse ich gelten

  7. #7
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    14.12.2005
    Beiträge
    161
    Danke Jungs,

    also habe ich das richtig verstanden:

    Die Impulszählung nicht vom Interrupt sondern vom Timer zählen lassen.

    Der Timer lässt das Programm laufen und zählt sozusagen im "Hintergrund" obwohl das Programm gerade mit anderen Dingen wie das Senden der Daten beschäftigt ist.

    Wogegen der Interrrupt ganz brutal alles blockt wenn er "aktiv" ist.

    So richtig?

    Dann werd ich mal die beiden Timer bemühen.

    Gruß
    Markus

  8. #8
    Benutzer Stammmitglied
    Registriert seit
    14.09.2005
    Alter
    68
    Beiträge
    77
    Ja genau. Du kannst dir das so vorstellen als hättest du einen externen Zähler den du jede Sekunde ausliest.

    Du mußte jetzt nur noch schauen ob du den Counter bei jeder Ausgabe wieder auf null setzt, oder den Counter durchlaufen läset und die Differenz rechnest. Wenn du den Counter auf Null setzt, dann solltest du erst den Wehrt in eine Variable setzten, und dann auf Null setzen. Erst dann die Ausgabe auf die Schnittstelle senden.

    Noch mal zu deinem Prog mit dem Interrrupt. Selbst wenn das Programm in die (Datensenden) Routine springen, hättest du immer das Problem, dass während der Ausführung dieser Routine keine weitere Interrrupt ausgeführt werden können weil die Interrrupts blockiert sind, und du so Impulse verlieren kannst. Beim AVR kannst du keine zwei Interrrupt gleichzeitig ausführen, oder aus einem Interrrupt in einen andren springen.

  9. #9
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    14.12.2005
    Beiträge
    161
    Hallo Guy,

    wäre es schlau die Timervorgabe so zu wählen das bei jedem Impuls der Timer überläuft und in meine alte Interruptroutine spring? Müsste dann weniger in meinem Code ändern. Oder ist dann das gleiche Problem wie vorher?

  10. #10
    Benutzer Stammmitglied
    Registriert seit
    14.09.2005
    Alter
    68
    Beiträge
    77
    Dann hast du das selbe Problem. Für den Counter braust du keine Interruptroutine, der wird ja nie überlaufen Bei 30.000 Impulse/Min. sind ja nur 500 Impulse/sec.

    An deinem Programm braust du ja nicht viel zu ändern. Braust nur den Interrupt raus zuschmeißen und den Zweiten Timer als Counter einstellen. Dann in der Ausgabe die ja durch den andren Timer jede Sekunde angesprungen wird den Counter auslesen. Du mußt nur den Impuls an den richtigen Pin vom Timer-Counter legen.

    Ok, habe jetzt mal dein Programm geschaut, du machst noch in der Interruptroutine Berechnungen. Das solltest du sowieso vermeiden. Eine Interruptroutine sollte immer so schnell wie möglich verlassen werden.

    Es gibt noch eine andre Möglichkeit. Du läßt das Programm in einer DO Schleife laufen. wartest immer auf steigende oder fallende Flanke und Zählst dann jedesmal eine Variable hohe, und machst dann deine Brechungen. Die Berechnungen dürfen aber auch nicht zulange dauern weil sonst auch Impulse verlorengehen können. Mit dem Timer Springst du dann jede Sekunde zur Ausgabe. Aber auch hier besteht das Risiko das währen der abarbeiteung dieser Routine Impulse verloren gehen.

    Wenn keine Impulse verloren gehen dürfen ist es mit einem Timer als Counter am sichersten.

Seite 1 von 3 123 LetzteLetzte

Berechtigungen

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

12V Akku bauen