- Akku Tests und Balkonkraftwerk Speicher         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 11

Thema: hier ein code für niedrige frequenzmessung mit icp

  1. #1
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.11.2006
    Ort
    olargues
    Beiträge
    776

    hier ein code für niedrige frequenzmessung mit icp

    Anzeige

    Praxistest und DIY Projekte
    hier einmal ein quelltext für die messung von niedrigen frequenzen
    durch periodenmessung mit hilfe der input-capture funktion.

    viel spass
    klaus

    Code:
     
    ' Bascom Frequenzzähler für langsame Frequenzen: Zeit zwischen den Flanken zählen
    ' unter verwendung der input capture einheit
    
    
    
    ' dieser code basiert auf einem C quelltext von
    ' Autor:  Karl heinz Buchegger (kbuchegg) (Moderator)
    ' Datum: 08.02.2007 22:28
    ' Dateianhang : Freqcount.c
    ' aus dem Microcontroller.net
    
    ' umsetzung für Bascom durch kolisson 15.09.2009
    
    
    $baud = 115200
    
    
    ' **********************  hier noch deinen crystal rein
    $crystal = 14745600
    $regfile = "m8def.dat"
    
    $hwstack = 32
    $swstack = 10
    $framesize = 40
    
    
    ' ++++++++++++++++++++++++++++++++++   hier wird $crystal ausgelesen
    Dim Quartzfrequenz As Long
        Quartzfrequenz = _xtal
    ' ********************************************** hier den prescaler für timer1 definieren
    ' zulässig sind 1,8,64,256,1024
    Const Prescalerwert = 1
    ' in dieser version wird der overflow von T1 ausgewertet und mitgezählt
    ' daher kann man mit prescale = 1 d.h. volle auflösung fahren
    
    '******************** und den capturetimer configurieren  ********************
    Config Timer1 = Timer , Capture Edge = Falling , Prescale = 1       'Prescalerwert
    Start Timer1
    ' ****************************************************************************
    
    ' *********** das zu messende digitalsignal  wird am ICP1 eingang (hier PB0) eingespeist
    
    
    
    Dim Starttime As Word
    Dim Endtime As Word
    Dim Nroverflows As Byte
    Dim Ersteflanke As Bit
    Dim Updatedisplay As Bit
    Dim Taktejesekunde As Long
    Dim Periodendauer As Single
    Dim Frequenz As Single
    Dim Counterticks As Long
    Taktejesekunde = Quartzfrequenz / Prescalerwert
    
    
    Dim Maxoverflows As Long
    Maxoverflows = Taktejesekunde / 65535
    
    
    '*****  zwei werte zur verzögerung des seriellen ausgabe
    '*****  sonst verschluckt sich das terminalprogramm
    '*****   kleinerer wert = schnellerer output
    Dim Outputcounter As Byte
    Const Anzeigeinterval = 10
    '***************************
    
    Ersteflanke = 1
    Updatedisplay = 0
    
    '*********************************  option eingangscomparator
    ' diese 2 zeilen sind optional zu verwenden
    ' da der icp1 eingang ja logigpegel benötigt
    'besteht hier die möglichkeit anstelle des icp den ain1 eingang des comparators zu verwenden
    ' der eingang ist dann empfindlicher --- schwelle etwa 1,23 volt '
    ' der icp1 eingang gilt dann nicht mehr als eingang und kann als normaler port verwendet werden
    Config Aci = On , Compare = On
    Acsr.6 = 1                                                  'interne bandgap als ref
    '*********************************  ende option eingangscomparator
    
    
    '  ******************* und die int routinen  definieren
    On Ovf1 T1overflow
    Enable Ovf1
    
    On Capture1 Captureint                                      'wenn pb0 auf low geht  dann capture int
    Enable Capture1
    
    Enable Interrupts
    
    
    ' *************  und los gehts
    
    Do
    
         If Nroverflows > Maxoverflows Then
         Print "freq kleiner 2 Hz"
         Nroverflows = 0
         Updatedisplay = 0
         Ersteflanke = 1
         End If
    
    If Updatedisplay = 1 Then
    
    
    
    
    
         If Outputcounter = Anzeigeinterval Then
    
         'Disable Capture1
        'Disable Ovf1
        Disable Interrupts
    
         ' //
         ' // Die Zeitdauer zwischen den Flanken bestimmen
         ' // Da EndTime und StartTime unsigned sind, braucht nicht
         ' // darauf Ruecksicht genommen werden, dass EndTime auch
         ' // kleiner als StartTime sein kann. Es kommt trotzdem
         ' // das richtige Ergebnis raus.
         ' // Allerdings muss die Anzahl der Overflows in der Messperiode
         ' // beruecksichtigt werden
         ' //
         ' // Die Zeitdauer wird als Anzahl der Taktzyklen zwischen den
         ' // beiden gemessenen Flanken berechnet ...
    
          Counterticks = Nroverflows * 65536
          Counterticks = Counterticks + Endtime
          Counterticks = Counterticks - Starttime
    
          '// ... mit der bekannten Taktfrequenz ergibt sich dann die Signalfrequenz
          Periodendauer = Counterticks / Taktejesekunde
          Frequenz = 1 / Periodendauer
    
         ' //
         ' // Das Ergebnis fuer die Anzeige aufbereiten ...
         ' //
         ' // ... und ausgeben
         ' //
    
          Print " Counterticks= " ; Counterticks
    
          Print " Periodendauer= " ; Periodendauer
    
          Print " Frequenz=  " ; Frequenz
    
         ' //
         ' // Das wars: Display ist wieder up to date
          '// die naechste Messung kann starten
          '//
    
         Outputcounter = 0
         'Timer1 = 0
         'Enable Capture1
         'Enable Ovf1
         Enable Interrupts
         End If
    
          Outputcounter = Outputcounter + 1
          Counterticks = 0
          Updatedisplay = 0
    
      End If
    
    
    Loop
    
    
    End                                                         'end program
    
    
    
    T1overflow:
    Nroverflows = Nroverflows + 1
    'Print "timer1 overflow"
    Return
    
    
    Captureint:
    If Updatedisplay = 1 Then Return                            '// Das Display wurde mit den Ergebnissen der vorhergehenden
                                                                 '// Messung noch nicht upgedated. Die naechste Messung
                                                                 '// verzögern, bis die Start und EndTime Variablen wieder
                                                                 '// gefahrlos beschrieben werden koennen
    
    If Ersteflanke = 1 Then
     Starttime = Capture1
     Nroverflows = 0
     Ersteflanke = 0                                            ' / / Die Naechste Flanke Ist Das Ende Der Messung
    
     Else
    
    Endtime = Capture1
    Updatedisplay = 1                                           ' / / Eine Vollständige Messung. Sie Kann Ausgewertet Werden
    Ersteflanke = 1                                             '/ / Bei Der Naechsten Flanke Beginnt Der Naechste Messzyklus
    
    End If
    
    Return

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    12.09.2009
    Beiträge
    182
    Hey guter Quellcode!

  3. #3
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Der code hat noch eine kleine Schwäche: Wenn ICP und overflow interrupt fast gleichzeitig auftreten, kann es passieren das der ICP overflow wegen der höheren priorität zuerst aufgerufen wird, obwohl erst der overflow dran wäre. Das kann zu einigen seltenen Falschen Werten führen. Sollte etwa einer von 20000 Werten betroffen sein, wenn nicht längere Zeit der Interrupt gesperrt ist.
    Wie man das berücksichtigt steht z.B. im Wiki unter:

    http://www.rn-wissen.de/index.php/Timer/Counter_(Avr)#Input_Capture
    Der code da ist in C aber leicht zu überragen.

  4. #4
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.11.2006
    Ort
    olargues
    Beiträge
    776
    @Besserwessi

    danke für den tipp.
    den artikel hatte ich noch garnicht gefunden und gelesen.

    mal sehen, was sich machen lässt.

    gruss klaus

  5. #5
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.11.2006
    Ort
    olargues
    Beiträge
    776
    hallo ihr lieben,
    da ich mal wider etwas mit der messung von niedrigen frequenzen machen musste (wollte), ist noch ein verbesserter code entstanden, den ich hier posten möchte.

    der einwnd von besserwessi über die int-überschneidung wurde berücksichtigt.

    der hintergrung dieser neuen version ist die tatsache, dass ich ein zweikanaliges gerät benötigte. da der M8 aber nur eine icp-einheit hat und zudem die int-priorität für icp sehr niedrig ist, habe ich mich entschieden den int0 eingang für das zu messende signal zu nehmen und das entsprechde programm möglichst efficient zu gestalten.

    im ende kam ein programm heraus, bei dem man wahlweise den int0 oder den int1 verwenden kann. beide int vectoren müssen auf die gleiche isr zeigen.
    durch einfaches enablen und disablen des int1 oder int0 kann man dann den messkanal umschalten.

    einen weiteren vorteil dieser programmierung sehe ich darin, dass die int-routine als (ein besseres wort fällt mir jetzt nicht ein) als Flip-Flop INT programmiert ist und das im ende noch als Inline assembler.

    nach durchführung einer Messung, kann man in Ruhe seine calculationen oder LCd ausgaben machen, da die ganze messung bis zum nächsten aufruf stoppt und es laufen keine weiteren wartenden Ints mehr auf, die sich störend auswirken könnten.

    auf die umrechnung des messwertes (in prozessortakten, je eingangsperiode) habe ich verzichtet, da die reziprokberechnung über single oder gar double für meine anwendung nicht nötig ist und den code nur unnötig verschmutzt.



    gruss klaus


    Code:
    hier also nun der liebevoll erzeugte code:
    
    Code:
    
    
    $baud = 256000                                              'set baudrate depending on cpu clockspeed
    $crystal = 32000000                                         'and your clockrate must be set too
    
    '**********  no joke...  my M8 is running on 32Mhz now without any problems
    ' but take care .. its dangerous because some parts of your cpu may fail at high clockrates
    
    '########## warning !!!!!!!!!!!!!
    ' this software is made for atmega 8
    'Inside The Int0isr : The Register Tccr1b Is Directly Adressed .
    ' so .. if you use a different processor, check for register names and adresses.
    
    
    
    
    $regfile = "m8def.dat"
    $hwstack = 32
    $swstack = 10
    $framesize = 40
    
    
    Config Portd.2 = Input                                      'int 0
    Portd.2 = 1
    
    
    Config Timer1 = Timer , Prescale = 1
    'Tccr1b.6 = 0
    Stop Timer1                                                 'we stop the timer , because it will be activated
                                                                 'inside the int0 routine
    
    Config Int0 = Falling                                       'must be falling for efficient programming
    On Int0 Int0isr Nosave                                      'nosave .. saves time and code
    Enable Int0
    
    On Ovf1 T1overflow Nosave                                   'again nosave
    Enable Ovf1
    
    'about nosave : if you use the int routines "called ORIGINAL BASCOM" please comment
    'out the NOSAVE DIRECTIVE
    
    
    Enable Interrupts
    
    
    
    
    ' **************************************************************************************
    ' *** hier kommen zwei spezialkonstukte, die rechenzeit sparen  .. was zum nachdenken !!
    Dim Periodelow As Word
    Dim Periodehigh As Word
    Dim Pericount As Long At Periodelow Overlay
    
    
    Dim T1overlow As Byte
    Dim T1overhigh As Byte
    Dim T1overflows As Word At T1overlow Overlay
    
    ' ** ENDE von *** hier kommen zwei spezialkonstukte, die rechenzeit sparen  .. was zum nachdenken !!
    ' **************************************************************************************
    
    
    Dim Messzyklus As Byte                                      'fertig = 0 --  also eine ganze periode gemessen
    Messzyklus = 0
    
    Dim Status As Byte                                          ' 0=stop timer    1 = start timer
    Status = 0
    
    
    
    
    
    
    Print "Starting "
    Wait 2                                                      '
    
    
    
    
    
    Do
    
    '************  do not change below this line, if you are not sure what you are doing
    If Messzyklus = 0 Then
    
    Periodelow = Timer1
    Periodehigh = T1overflows
    '************  do not change above this line, if you are not sure what you are doing
    
    
    
    
    
    
    
    ' ##### your code below this line #####
    
    Print "timer" ; Timer1
    Print "ovr" ; T1overflows
    Print "pericount  " ; Pericount
    
    
    Waitms 100                                                  'das kann auch waitdays=100 sein.. gibt es ja nicht
    'genausogut kann es entfallen, wenn man in der zeit genug anderes machen will
    
    ' ####  your code above this line #####
    
    
    
    
    
    '************  do not change below this line, if you are not sure what you are doing
    Pericount = 0
    T1overflows = 0
    Timer1 = 0
    Messzyklus = 1
    Status = 1
    
    End If
    '************  do not change above this line, if you are not sure what you are doing
    
    
    Loop
    End
    
    
    
    
    
    'Int0isr:                                                     'ORIGINAL Bascom
    'Tccr1b = Status
    'If Status = 0 Then
    'Messzyklus = Status
    'End If
    'Status = 0
    'Return
    
    
    
    Int0isr:                                                    ' FASTER VERSION
    
    push r23
    PUSH R24                                                    ' since we are going to use R24 we better save it
    IN r24, SREG                                                ' get content of SREG into R24
    PUSH R24
                                                      ' we can save a register
    
    lds r24,{status}
    !out tccr1b,r24
    cpi r24,0
    
    brne exitthis
    sts {messzyklus},r24
    
    Exitthis:
    cbr r24,1
    sts {status},r24
    
    POP R24                                                     'get content of SREG
    !OUT SREG,r24                                               ' save into SREG
    POP R24
    pop r23                                                     ' get r24 back
    
    
    Return
    
    
    
    'T1overflow:                                                ' ORIGINAL Bascom
    'T1overflows = T1overflows + 1
    'Return
    
    
    T1overflow:                                                 ' FASTER VERSION
    
    push r23
    PUSH R24                                                    ' since we are going to use R24 we better save it
    IN r24, SREG                                                ' get content of SREG into R24
    PUSH R24                                                    ' we can save a register
    
    lds r23,{t1overlow}
    lds r24,{t1overhigh}
    
    inc r23
    brne kein_uebertrag
    inc r24
    
    Kein_uebertrag:
    sts {t1overlow} , r23
    sts {t1overhigh} , r24
    
    POP R24                                                     'get content of SREG
    !OUT SREG,r24                                               ' save into SREG
    POP R24
    pop r23                                                     ' get r24 back
    
    Return

  6. #6
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    So wie es Aussieht, ist das Problem mit einer möglichen Überschneidung der Interrupts nicht berücksichtigt, sondern einfach umgangen indem der Zähler angehalten wird. Das geht aber nur beim weniger genauen Weg über Int0, Int1 , nicht wenn man die ICP Funktion nutzt.


    Es ist gar nicht so schlimm, dass der ISP interrupt eine so niedriege Priörität hat. Das Puffern macht ja die Hardware. Es muß nur sichergestellt werden, dass bis zur Interrupt-routine (ISR) keine weitere Flanke dazwischenkommt.

    Wenn man mehr als einen ISP Eingang braucht, kann man bei vielen µCs den Multiplexer des AD wandlers nutzen, um den Analog comperator auf einen der AD Eingänge zu legen. Der analoge Comperator kann auch als Quelle für die ISP Funktion gewählt werden.

  7. #7
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.11.2006
    Ort
    olargues
    Beiträge
    776
    ach besserwessi,

    was bist du denn für einer ? und ich dachte ich kenn dich schon etwas!
    aber irgendwie überaschst du mich immer wieder.

    So wie es Aussieht, ist das Problem mit einer möglichen Überschneidung der Interrupts nicht berücksichtigt, sondern einfach umgangen indem der Zähler angehalten wird. Das geht aber nur beim weniger genauen Weg über Int0, Int1 , nicht wenn man die ICP Funktion nutzt.
    es ist halt durch vermeidung berücksichtigt. das macht man doch auch in anderen lebenslagen so. wenn z.b. das Rauchen von Tabak problematisch ist, könnte man es vermeiden, sofern nicht andere umstände dagegen sprechen.

    Das mit dem Admux ist natürlich wieder ein guter tipp, den ich noch nicht kannte, aber für meine sache ist das mit dem int0 und int1 schon optimal.

    zwischen int0 und int1 wechseln dauert 2 takte und das in einer phase des progs , wo es angehalten ist und es nicht stört.

    den vorteil der muxe verstehe da nicht wirklich und es wird keinen geben, da auch dies takte kostet und das schlimme an der idee mit dem icp sind ja dann die extra rechenoperationen, da der timer ja ständig weiterrennt und dann muss wieder ab und aufgerechnet werden.

    also.
    die kleinen seitentipps finde ich okay, aber diese dieses globale gezeter (mir auch jetzt kein schöneres wort ein ) naja.

    die software funktioniert übrigens super mein lieber.

    gruss klaus


    ________________ ein kleine ergänzung als edit __________________

    ich habe mein prog ja auch nicht gepostet, um den nobelpreis zu bekommen, sondern um einmal etwas funktionierendes zu teilen und zum anderen um den interessierten leuetn hier mal ein wenig zu zeigen, was ein Inline-assembler bringen kann.

    nicht umsonst habe ich ja die bascom-isr versionen nur auskommentiert und nicht gelöscht. jeder kann also nun diese wieder einkommentieren und dafür die inline versionen auskommentieren.
    das programm funktioniert dann genauso (bis auf die maximale messfrequenz) aber man sieht sehr deutlich, wie der code durch den Inline-asm schrumpft.

    es ist also nicht mehr , als ein funktionierendes beispiel.

  8. #8
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Entschuldigung, die Kritik war nicht so gemeint. Klingt beim späteren lesen doch etwas hart. Die Anmerkung war hauptsächlich dafür, falls jemand nach anderes nach der berücksichtigung der Interruptkollision sucht, und sie da nicht so direkt findet.

    Die Benutzung der ICP-Funktion ist hauptsächlich für relativ hohe Frequenzen sinnvoll, oder wenn man eine sehr hohe Auflösung braucht. Die Fehler sollte etwa 3 mal kleiner sein. In Einzelfällen (Stopsignal kommt wenn gerade der Überlauf Interrupt läuft) kann mit dem einfachen Interrupts noch ein größerer Fehler Auftreten. Wenn man die reine Basic Version ohne die ASM Beschleunigung nutzt könnte das schon recht stark stören.
    Wenn es so reicht, dann ist ja auch gut.

  9. #9
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.11.2006
    Ort
    olargues
    Beiträge
    776
    na siehste mein lieber,
    nun lächele ich schon wieder. obwohl ich kurz an VERMEIDUNG von beiträgen meinerseits dachte .

    leider ist das im web immer schwierig, sich auszudrücken, da ja die mimik des persönlichen gespräches fehlt. darunter leiden ja nun alle FORENTYPEN.

    dann ist ja alles okay soweit und es ist natürlich wichtig, dass du darauf hinweist. .. und eigentlich hatte ich auch nur geschrieben, dass dein einwand mit dem overlap-int berücksichtigt wurde und nicht, dass er so berücksichtigt wurde, wie du es gemacht hättest.

    also .. geben wir den artikel bald wieder frei, für die, die low-freq messungen machen wollen.

    eine frage am rande hätte ich schon noch, da sie mich schon länger bewegt:

    da ich ja schon oft mehr oder weniger mit dir zu tun hatte und auch das roboternetz wie eine tägliche zeitung durchlese habe ich mich oft schon gefragt, was dein hintergrund eigentlich sein könnte. du hast viele informationen bereitgestellt zu verschiedensten themen und bist offenbar in vielen wissensbereichen zu hause oder zumindest gast.

    ein projekt oder einen eigenen beitrag von dir habe ich noch nie bemerkt (das könnte mir ja entgangen sein).

    nachdem meine letzte theorie war, dass du ein projekt der Nasa oder vom Fbi bist (persönlicher smiley) erlaube ich mir mal die frage , wie ich mir Dich so vorstellen kann ?

    Ich hoffe du kannst mir helfen.

    Gruss Klaus

  10. #10
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Mein Hintergrund ist ein Physikstudium, und schon eine ganze Zeit (fast 30 Jahre) mit Elektronik/Computer als Hobby.

    Als Phsiker sollte man halt die Fähigkeit haben sich schnell auch in neue Gebiete einzulesen.

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

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

12V Akku bauen