-         

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 14

Thema: Frequenz-Auswertungssystem

  1. #1
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    17.01.2006
    Ort
    Homberg (Efze)/Nordhessen
    Alter
    32
    Beiträge
    207

    Frequenz-Auswertungssystem

    Anzeige

    Hallo zusammen!

    Ich habe gerade folgendes Projekt im Bau, und würde mich freuen wenn wir hier mal ein bisschen über Möglichkeiten der Umsetzung sprechen können.

    Um folgendes gehts:

    Ein Frequenzsignal (kommt ursprünglich von einer Ottomotor-Zündanlage) wird durch ein aktives Filter geschickt, am Ende kommt ein schönes Rechtecksignal mit definierter Signalbreite und Variablem Abstand raus (die Zeit zwischen zwei Signalen ist also umgekehrt proportional zur Frequenz).

    Diese Zeit wird nun mittels ATMEGA8 mit Bascom programmiert gemessen, und mit dem PULSEIN-Befehl ausgegeben (der dezimalwert entspricht der Zeit zwischen zwei Flanken in der Einheit [10µs])

    Bis hierhin habe ich die Schaltung am Laufen. Ich wertete das ganze über ein LCD Display aus, welches 3x pro sekunde über die Timer ISR aktualisiert wird.

    Nun fängt es an mit den Praxisproblemen:

    Die Anwendung ist sehr Zeitkritisch. Wenn ich es laufen lasse, tauchen immer mal wieder "Lücken" auf, d.h. mir wird eine Frequenz von 0 angezeigt, obwohl das nicht stimmt. Wenn ich im Hauptprogramm eine Mittelung vornehme (die letzten 5 Pulsabstand-Werte werden addiert und durch 5 geteilt) wird es etwas besser, verschwindet jedoch noch nicht ganz.
    Meine Vermutung: Es kommt ein Impuls in diesem Falle genau dann, wenn das Programm in der ISR ist, der Pulsabstand wird nicht aufgenommen. Wenn das öfters passiert (genauergesagt wenn 635,55ms kein Impuls registriert wird) gibt es einen Timeout (laut Bascom hilfe). Das Display zeigt mir eine 0 an.

    Nun gilt es wohl das Programm zu optimieren, heißt den controller sich möglichst auf diese Pulsweitenmessung konzentrieren zu lassen.

    Gleichzeitig möchte ich aber dass eine Ausgabe des Wertes erfolgt. Wie kann ich das also bestmöglich realisieren?

    Eine Idee war, dass ich das Signal an einen zweiten Controller sende, der mir dann in aller ruhe als Anzeigetreiber dient. Nur in welcher form kann dieser wert gesendet werden? Als Analogwert und im anderen uC wieder ADC rückkonvertieren? Bestimmt nicht optimal. Oder als Frequenz und dann wieder rückkonvertierung? Stelle ich mir auch nicht so besonders geeignet vor. Auch dieses Senden muss ja möglichst wenig Takte beanspruchen.
    Mit kommunikation zwischen zwei Controllern hab ich mich bisher noch gar nicht beschäftigt....

    Sollte erst mal genug Input sein, hoffe ihr habt ein paar gute Vorschläge für mich.

    Hier noch der Code:

    Code:
    '---------------------------------------------------------
    
    
     $regfile = "m8def.dat"
     $crystal = 16000000                                        'Quarz: 16,000 MHz
    
    
      '---------------------------------------------------------
    Config Pinc.0 = Input
    
    Dim Pulsbreite As Long
    
    
    'Config Adc = Single , Prescaler = Auto , Reference = Internal
    'Start Adc
    
    Dim A As Word
    Dim B As Word
    Dim C As Word
    Dim D As Word
    Dim E As Word
    Dim Schnitt As Word
    Dim N As Long
    
    '===========================================
    
    '++++++++FÜR LCD Verwendung:++++++++++++++++
    
    'Config Lcdpin = Pin , E = Portc.3 , E2 = Portd.7 , Rs = Portc.2 , Db4 = Portd.2 , Db5 = Portd.3 , Db6 = Portd.4 , Db7 = Portd.5
    'Config Lcd = 20 * 4a , Chipset = Ks077
    'Config Lcdbus = 4
    
    'Config Pind.6 = Output                                      'RW=0 (für LCD erforderlich)
    'Portd.6 = 0
    
    'Config Pind.7 = Output                                      'LCD Licht ein
    'Portd.7 = 1
    
    
    
    'Initlcd
    
    'Cursor Off
    
    'Cls
    
    '------------------------------------------------------------
    
    '+++++++ISR Config: Springt 3x pro sec in ISR um etwas auszuführen (z.B. LCD Betrieb)++++++++
    
    'Config Timer1 = Timer , Prescale = 64                       '16Mhz / 64 = 3 Hz Konfiguriere Timer0
    'Enable Timer1                                               'schalte Den Timer0 Ein
    'On Timer1 Isr_von_timer1                                    'verzweige Bei Timer0 überlauf Zu Isr_von_timer0
    'Enable Interrupts
    
    '============================================
    
    Do
    
    Pulsein Pulsbreite , Pinc , 0 , 1                           'Pulsein Abfrage an PC0
    
    '------ Umrechnungsfaktor auf U/min: ----------
    
    If Pulsbreite > 400 Then                                    'Pulsbreite = 6.000.000 / Drehzahl
    N = 6000000 / Pulsbreite                                    'PB(3000/min)=2000, (4000)=1500, (5000)=1200, (6000)=1000, (7000)=857, (8000)=750, (9000)=667, (10000)=600, (11000)=545, (12000)=500, (13000)=462, (14000)=429, (15000)=400, (16000)=375
    End If
    
    '-----------------------------------------------
    
    
    E = D
    D = C
    C = B
    B = A
    A = N                                                       'Bildung eines Mittelwerts der letzten 5 Zündungen
    
    Schnitt = A + B
    Schnitt = Schnitt + C
    Schnitt = Schnitt + D
    Schnitt = Schnitt + E
    
    Schnitt = Schnitt / 5
    
    
    If Schnitt < 6000 Then
    Portd.7 = 1
    Else
    Portd.7 = 0
    End If
    
    Loop
    
    Isr_von_timer1:
    
    
                                       'ISR von Timer0
    Timer1 = 0
    
    Locate 1 , 3
    Lcd "        "
    Locate 1 , 1
    Lcd "c=" ; Schnitt
    
    Return
    
    
    
    
    
    End
    Grüße Paul

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    1.892
    Wenn das mit Pulsein Probleme macht, schreib doch die Auswerteroutine selber.
    Am Schönsten geht das mit dem Input Capture Interrupt des Timers 1.
    Wenn da am ICP Pin ein Flankenwechsel ( programmierbar ) stattfindet wird der aktuelle TCNT Stand in das Input Capture Register geschrieben.
    Den holst Du Dir dann in der Interruptroutine ab, ziehst den vorher ermittelten Wert ab und legst ihn in einem kleinen ARRAY ab.
    Da Du für das Array ohnehin einen Pointer brauchst, kannst Du den gleich als Marker für neue Impulse verwenden.
    Einlesezeiger != Auslesezeiger = neuer Impuls eingetroffen.

    Aus dem Array kannst Du dann gleich deine Mittelwerte in der Hauptroutine rausholen.

    Eine Sache musst Du dabei beachten, wenn sehr wenige Impulse kommen kann der Timer überlaufen - das musst Du programmtechnisch abfangen.

  3. #3
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    17.01.2006
    Ort
    Homberg (Efze)/Nordhessen
    Alter
    32
    Beiträge
    207
    Danke für deinen Beitrag, das ist eine gute Idee!

    Das Prinzip hab ich soweit verstanden, mir ist nur noch nicht klar wie du das mit den Arrays und zeigern meinst, und vor allem nicht, wie ich es in Code umsetzen kann (bin nicht so übermäßig Fit was den Programmierteil angeht). Vielleicht kannst du ja mal ein kleines Code Beispiel Posten.

    Für den Timerüberlauf lasse ich mir dann was einfallen, das sollte lösbar sein.
    Grüße Paul

  4. #4
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Wenn überhaupt etwas dabei schierig ist, dann die Behandlung des Timerüberlaufs. Die einfache Lösung ist es den Überlauf zu vermeiden solange der Motor läut. Dazu reicht schon ein passend gewählter Prescaler für den Timer. Den Stillstand zu erkennen ist nicht so schwierig wie eine vollständige Berücksichtign der Überläufe.

    Die Benutzung von Array wird man wohl selber lernen müssen.

    Hier soll da array wohl als zyklischer Puffer dienen. Die gemessenen Werte aus dem ICP Register werde der reihe nach gespeichert, und wenn man am Ende angekommen ist, wird wieder von vorne angefange und die dann ältesten Werte werden überschrieben. Dazu muß man sich dann den Index merken wo der letzte neue Wert steht und das Hauptprogramm muß sich merken (als Index) welcher Wert als letztes verarbeitet wurden.


    Die Datenübertragung auf einen 2 ten µC kann man sich vermutlich sparen. Die eigentliche Messung über die ICP Funktion ist nicht wesentlich komplizierter als des Empfanden der Daten über eine Schnittstelle.

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    1.892
    So wie Besserwessi das schreibt, war das gedacht.

    Ein kurzes "Pseudo Beispiel" in "C"


    }
    Code:
    //Variablen definieren
    volatile unsiged int ui_wertebuffer[5]  //Das wird mal der Ringpuffer
    volatile unsigned char uc_readin=0    //Einlesezeiger
    volatile unsigned char uc_readout=0  //Auslesezeiger wird hier als Marker genutzt
    
    //Einlesen der Werte
    void einlesen(unsiged int ui_wert)
    {
    ui_wertebuffer[uc_readin]=ui_wert;   //Aktuellen Wert einlesen
    uc_readin++;                                  //Pointer erhöhen
    uc_readout++;                               //Wird hier nur als Marker genutzt
    if (uc_readin>4){uc_readin=0;}       //Pointer auf 0 zurücksetzen wenn Pufferende erreicht
    }
    /* Diese Subroutine kann man in die Input Capture Routine einbauen. oder von da aus aufrufen - Ich würd die paar Zeilen direkt in die ICP Interrupt Routine einbauen */
    
    //Auslesen der Werte
    unsigned int auslesen(void)
    {
    unsigned char uc_i=0;                   //Schleifenvariable
    unsigned int ui_result=0;               //Ergebnisvariable
    unsigned long int ui_math;            //Berechnungsvariable
    if(uc_readout>0)
       {
       for(uc_i=0;uc_i<5;uc_i++)        //Eine Schleife, die die 5 Werte ausliest
          {
          ul_math+=ui_wertebuffer[uc_i];  //Die 5 Werte werden addiert
          }
       ul_math/=5;                                  //Das Ergebnis wird durch 5 geteilt
       ui_result=ul_math;                        //Das Endergebnis wird in die unsigned int Variable ui_result übergeben
       }
    return(ui_result);              //Das Endergebnis wird an die aufrufende Routine zurück gegeben
    uc_readout=0;
    /* Man könnte es auch so machen, diese Routine nur dann aufzurufen, wenn uc_readout>0 ist */
    }

  6. #6
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    17.01.2006
    Ort
    Homberg (Efze)/Nordhessen
    Alter
    32
    Beiträge
    207
    Hallo zusammen,

    also erstmal hat mich das ein gutes Stück vorangebracht, vielen Dank.

    Ich habe mal ein neues Programm geschrieben, und wollte das mit dem Bascom simulator mal testen bevor ich es auf den Controller lade, da ich hierfür auch noch die Hardware umbasteln muss (ICP Pin ist PB0 beim Atmega

    Im Simulator spring er mir allerdings nie in den Interrupt, jetzt weiß ich nicht obs am Simulator liegt, oder ob ich den Controller noch mal speziell Konfigurieren muss für diesen Betrieb.

    Hier mal mein Code so weit, vielleicht fällt ja jemandem auf wenn noch was bestimmtes fehlen sollte:

    Code:
     '---------------------------------------------------------
    
     $sim
     $regfile = "m8def.dat"
     $crystal = 16000000                                        'Quarz: 16,000 MHz
    
    
      '---------------------------------------------------------
    
    
    Dim Counterstand As Word                                    'Zählerstand des Counters
    Dim Altercounterstand As Word                               'Vorheriger Zählerstand
    Dim Cntdifferenz As word                                    'Cnts die zwischen zwei interrupts vergangen sind
    
    Config Pinb.0 = Input
    Enable Interrupts
    
    Config Timer1 = Counter , Edge = Falling , Prescale = 1024 , Noise Cancel = 1 , Capture Edge = Falling
    
    '============================================
    
    Do
    
    
    On Capture1 Puls_kommt
    
    
    Loop
    
    Puls_kommt:
    
    Altercounterstand = Counterstand
    Counterstand = Capture1
    Cntdifferenz = Counterstand - Altercounterstand
    Print Cntdifferenz
    
    
    Return
    
    End
    Grüße Paul

  7. #7
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    08.01.2006
    Beiträge
    4.556
    Im Simulator kann man oben in der Leiste die IRQ ein/aus schalten (glaube ich) ? Oder jedenfalls irgendwie festlegen...In einer IRQ nichts Zeitaufwändiges erledigen, nur Wert in eine Variable speichern. den dann als erstes in ein Arry schieben.
    Danach auswerten.

    Gruß Richard

  8. #8
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Den Print Befehl sollte man nicht in der ISR nutzen, außer vielleicht für einen erste Test. Der Print-befehlt braucht ausgesprochen viel Zeit, in der Regel zu viel für eine ISR.

    Soweit ich weiss muß man den Interrupt noch extra einschalten, per Enable capture1 oder so ähnlich.

  9. #9
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    17.01.2006
    Ort
    Homberg (Efze)/Nordhessen
    Alter
    32
    Beiträge
    207
    Ja das problem scheint irgendwo bei einem Start oder Aktivierbefehl eines timers zu liegen. Er zählt schlichtweg nicht und der Interrupt wird auch nicht ausgeführt. Habe sogar jetzt extra die Hardware angeschlossen aber identisch mit der Software. Irgendwo hängts.

    Wie aktiviert man einen Timer und lässt ihn loslaufen? Mit Enable capture1 ebenfalls kein unterschied.
    Grüße Paul

  10. #10
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    17.01.2006
    Ort
    Homberg (Efze)/Nordhessen
    Alter
    32
    Beiträge
    207
    Habe den Fehler gefunden ^^:


    Config Timer1 = Counter , Edge = Falling , Prescale = 1024 , Noise Cancel = 1 , Capture Edge = Falling

    Niemals Edge = Falling und Capture Edge = Falling kombinieren (so wie komischerweise in der Hilfe), der counter wird genullt und abgefragt gleichzeitig, logisch warum ich eine 0 angezeigt bekomme.
    Grüße Paul

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

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