PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Atmega8 Frequenzmessung



kollimann
06.01.2010, 14:06
Hallo
ich habe ein Problem und find leider keinen Lösungsansatz.
Ich möchte mir einen Rundenzähler für meine Autorennbahn bauen.

Fakten:
jedes der einzelnen Autos sendet per IR LED eine festgelegte Frequenz
Auto1 15,625kHz, Auto2 7,8125kHz, Auto3 5,208 kHz usw.....

So ich wollte nun hergehen und mit dem Atmega die kHz messen bei jeder Überfahrt und dann anhand des Wertes dem entsprechen Auto die Runde hochzählen.
Alles was ich bisher an Bascom Code zu Frequenzmessung gefunden hab geht irgendwie nicht, meist wird bei der Geschwindigkeit garnix erkannt oder die Werte sind einfach nicht auswertbar.
OK in den Codeschnippseln geht es meist um Messung im Hz Bereich.

So meine Frage an euch, kann jemand Helfen?
Die Messung geht auch nicht über den Capture Eingang B0 weil ich ja 2 Sensoren auslesen/abfragen muss.

Über Lösungshinweise wäre ich euch Dankbar, evtl Links oder Codeschnipsel helfen nochmehr.

DANKE kollimann

wkrug
06.01.2010, 15:00
Ich meine, so einfach ist das gar nicht.
Es können ja zum Beispiel auch mehrere Autos gleichzeitig über die Ziellinie fahren.
Dann müssten auch 2 Frequenzen gleichzeitig ausgewertet werden.

Ich würde das über Filter realisieren, die auf die Frequenz des entsprechenden Autos abgestimmt sind.
Am Ausgang des entsprechenden Filters kommt ein Gleichrichter mit Schmitt Trigger, der dann die Zählimpulse für deinen Controller liefert.

Rein theoretisch könnte man auch eine einfache Fast Fourier Transformation von der Infrarot Empfängerdiode berechnen lassen.

Das dürfte aber bei 15kHz Signalfrequenz nur mehr in Assembler gehen

kollimann
06.01.2010, 15:55
Hm, 2 Autos ja, aber dann eben auf 2 Spuren und damit an 2 Sensoren und somit wieder an 2 Eingängen des Controllers.

Die Auswrtung sprich die Anzeige auf einem LCD oder sontswas muss ja auch nicht genau bei Überfahren geschehen.
Weiterhin muss ich ja die Frequenz nich wirklich auswerten, ich brauch die Frequenz ja nur zur Unterscheidung der Autos.

Kann auch gut sein das ich das Problem garnicht richtig verstanden hab im Kopf und somit völlig auf dem Holzweg bin mit meinen Gedanken.

wkrug
06.01.2010, 16:14
ich brauch die Frequenz ja nur zur Unterscheidung der Autos
Wenn Du sicher Stellen kannst, das immer nur ein Auto an einem Empfänger vorbeikommt, kannst Du das über Input Capture und INT0 realisieren.

Der Timer 1 läuft frei, es werden die Zeiten zwischen mindestens 2 Nulldurchgängen der Wechselspannung gemessen.
Daraus lässt sich dann die Frequenz bestimmen und dem entsprechenden Fahrzeug zuordnen.
Beim ersten Nulldurchgang wird dder aktuelle Zählerstand ( TCNT1 ) des Timers 1 abgespeichert. Beim nächsten nulldurchgang in gleicher Richtung ( komplette Periode ) wird der vorherige Wert von dem vorher ermittelten abgezogen. Aus diesem Wert lässt sich dann die Frequenz ermitteln.
Man kann auch die erste Periode verwerfen und dann die nächsten 2 Auswerten, oder, oder, oder...

Eine Impulsaufbereitung die Dir wieder saubere Rechteckimpulse liefert musst Du aber trotzdem Vorschalten.
Ich würd da einen Vorverstärker, einen Bandpaß und dann einen Begrenzer Verstärker hinterherschalten.

Um ein Auto nur einmal pro Runde zu zählen, kann man nach einem erkannten Fahrzeug eine Totzeit von ca. 2 Sekunden für dieses Fahrzeug in das Programm integrieren.

Ich würde für diese Aufgabe einen ATMEGA 16 Controller verwenden, da der auch genügend Ports für eine vernünftige Anzeige hat.
Wenn Du unbeding sparen willst wird es auch ein ATMEGA 8 tun, vom Preis her ist es aber kein großer Unterschied.
LapTime und Durchschnitts LapTime sind dann nur noch ne Frage von Deiner Programmierkunst.

Beispielprogramme kann ich Dir leider nicht liefern - Arbeite mit C.

kollimann
06.01.2010, 16:35
ein Auto an einem Empfänger vorbeikommt

eher drüber fährt ! Daher es kann immer nur 1 Auto über den Sensor fahren.
Klar können 2 Autos direkt hintereinander drüber fahren, das ist evtl ein Zeitproblem. So ein Auto ist gut 14cm lang, nun müsste man errechnen wie schnell die fahren könnten und somit könnte man denn errechnen wie schnell der Controller fertig sein muss mit Auto1 wenn Auto2 hinten an der Stoßstange klemmt.

Naja muss weiter lesen und testen.
C nutz mir leider nix, hab nur den einen C Code den dann jemand nach Bascom übersetzt hat, das geht aber nich richtig.
http://www.mikrocontroller.net/topic/62517#new

Hab aber den Sensor eben direkt am Atmega, mh der Hersteller machts bei seinen Weichen auch so, soll ja auch nur die Weiche gestellt werden wenn auch das richtige Auto drüber fährt. Und da iss auch nen Mega8 drinne ohne ext Quarz also 8Mhz max. OK die stellen nur die Weiche und werten nix aus, aber die Frequenz müssen sie ja auch irgendwie erkennen.

wkrug
06.01.2010, 16:50
Daher es kann immer nur 1 Auto über den Sensor fahren.
Dann müsste es so funktionieren, wie ich es oben beschrieben hab.
Sollte auch in Bascom nicht wirklich ein Problem sein.

Im Prinzip benötigt der Controller 200µs ( Eine Periodendauer bei 5kHz ) um ein Auto zu indentifizieren.
Da hat sich das Auto bei 20km/h gerade mal 1,1mm weiterbewegt.
Wenn mehrere Perioden ausgewertet werden sollen natürlich mehr.

Auch 2 hintereinanderfahrende Autos sind somit kein Problem.

Die Totzeit wird ja nur für ein bereits erkanntes Fahrzeug aktiviert, um das gleiche Fahrzeug bei einer Überfahrt nicht mehrfach zu zählen.
Kommt ein anderes auf der gleichen Spur, kann das sofort erkannt werden.

Richard
06.01.2010, 17:02
ein Auto an einem Empfänger vorbeikommt

eher drüber fährt !

Der Empfänger ist also in der Bahn, die SendeLED im Boden
des Fahrzeugs? Da ist der Abstand Sender/Empfänger sehr
gering, entsprechend die Stecke in welcher sie sich sehen können
auch! So gaaanz langsam sind solche "Rennwagen" dann auch
nicht, ich fürchte da wird die Zeit zur Erkennung selber schon
nicht reichen. Versuche einmal zu ermitteln wiefiele m/s so
ein Wagen bei Max Geschwindigkeit zurücklegt und emittel den
Radius der IR Led bei dem Abstand zum Entfänger. Damit kannst
Du dann ausrechnen Wieviel Zeit zur Frequenzbestimmung bleibt.

Gruß Richard

PICture
06.01.2010, 17:16
Hallo!

@ kollimann

Wie wäre es mit Frequenzdekodierung per NE567 und zählen damit erzeugten Impulsen ?

MfG

Besserwessi
06.01.2010, 19:11
So schwer sollte die Frequenzmessung mit der input capture funktion (oder auch der entsprechenden Software version davon) nicht sein. Die zeiten sind mit maximal etwa 0,5 ms relativ kurz, so daß man beim 16 Bit timer ohne Überlauf auskommt.

das Verfahren ist dann folgendes:
Im ICP Interrupt die Zeit auslesen, für später merken und davon die vorherige Zeit abziehen. Schon hat man die Periodendauer. Analog geht das auch mit einem ext. Interrupt, nur daß man da die Zeit direkt aus dem Timer ausließt und ggf. etwas größere Fehler hat.

Für die Messung am Auto muß man ggf. die erste Periode verwerfen, denn da ist das Auto vielleicht noch nicht ganz über dem Sensor. Die zweite und ggf. 3. Periodet sollte dann zum Messen reichen.

@Picture: die Lösung mit dem NE567 hat den Nachteil, daß man mehr Perioden (ca. 5-20) braucht, und es ist einiges an Hardware nötig.

kollimann
06.01.2010, 20:18
Erstmal DANKE für eure Vorschläge und Tipps.

Ich war warscheinlich etwas voreilig mit meiner Frage weil ich den ganzen Tag immer nur per Hand die Autos über den Empfänger geschuppst hab.
Jetzt hab ich mal die Bahn aufgebaut und siehe da es gibt erste Erfolge.

Also ich habe 2 Codevarianten aus dem Inet versucht beide haben Probleme, die eine mehr die andere weniger.

Version1, messen über INT0 mit folgendem Code


$regfile = "m8def.dat"
$crystal = 8000000
$hwstack = 32
$swstack = 10
$framesize = 40
$baud = 9600


Config Portd.2 = Input 'int 0
Portd.2 = 1


Config Timer1 = Timer , Prescale = 64
'Tccr1b.6 = 0
Stop Timer1 'we stop the timer , because it will be activated
'inside the int0 routine

Config Int0 = Falling 'or rising
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
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

'************ 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

Also diese Variante zählt erstmal wirklich jede Runde egal wie schnell man fährt, bei einem Auto sind die Werte 98% zu verwerten soll heißen manchmal zählt er doppelt oder mal 1 Wert stimmt völlig nicht. Das 2.Auto macht rießige Sorgen, da ist irgend eine Störung wohl vorhanden, da zählt er wirr egal wo das Auto auf der Bahn ist nur nicht am Sensor.
Auch wenn beide Autos Stoßstange an Stoßstange fahren also direkt hinternander werden beide gezählt, nur eben stört bei einem irgendwas. Wenns geht gehts zu 98% sauber. Also Zeit zum messen hat der Mega8.
Wobei ich gestehen muss das ich den Code fast garnicht verstehe was da gemacht wird.

2.Variante mit Capture und folgendem Code


$regfile = "m8def.dat"
$crystal = 8000000
Baud = 9600

Config Lcd = 16 * 2
Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2
Config Lcdbus = 4

' ++++++++++++++++++++++++++++++++++ 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 / 31375
'***** 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
Cls
Do

'If Nroverflows > Maxoverflows Then
'Cls
'Lcd "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
' //
'Locate 1 , 1
'Lcd "ti=" ; Counterticks
'Locate 1 , 8
'Lcd " Pe=" ; Periodendauer
'Locate 2 , 1
Print Frequenz
'Lcd " Fr=" ; 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

So diesen Code versteh ich eher, da gibts auch keinerlei Störungen und wenn er mal was anzeigt dann stimmt das auch, ABER die Version zählt nur mal aller 5 Runden und nur wenn man langsam fährt.
Auf jeden Fall wenn was ausgewertet wird stimmt das super genau nur eben ist irgendwas viel zu lahm.

Und die Variante mit dem NE567 hatte ich auch schon ins Auge gefasst, nur muss man dem nicht per Widerstände und Kondensatoren was vorgeben an Frequenz?

So also weiter basteln....und Infos sammeln

DANKE für eure Hilfe

EDIT jetzt gehts bei Version 1 wieder mit beiden Autos, hab das störende mal zerlegt, weiß nich was da war.
Auf jeden Fall wenn man die Fehlmessungen weggbekommt würde es schon gehen, bestimmt was mit Timing oder sowas.........

PICture
06.01.2010, 20:21
Hallo!

@ Besserwessi

Es ist mir klar, aber je mehr Hardware um so weniger Software und umgekehrt, gilt hoffentlich immernoch... :)

MfG

Besserwessi
06.01.2010, 21:28
Beide Versionen haben noch ein Problem mit der Behandung der Überläufe. Problem gibt es wenn Überlauf und ICP bzw. Int0 fast gleichzeitig auftreten. Vermutlich die Ursache für die etwa 2 % Fehlmessungen.

Für die Messung der Periodendauer wird man die gar nicht brauchen, nur für die Rundenzeit selber.

Ps:
Die Programme werden übersichtlicher, wenn man die Zeilenlänge etwas reduziert. Durch den Umbruch einiger Kommentrare wird das wirklich unübersichtlich.

wkrug
07.01.2010, 07:40
Problem gibt es wenn Überlauf und ICP bzw. Int0 fast gleichzeitig auftreten.
Das kann ich mir eigentlich nicht vorstellen.
Auch wenn beide Interrupts wirklich absolut zeitgleich eintreffen wird von jedem ein Flag gesetzt.
Die Routine mit der höheren Priorität wird dann zuerst ausgeführt, die andere später.
Es gilt natürlich auch hier was sonst auch immer gilt - Interruptroutinen sollten möglichst kurz sein.

Ich denke eher, die Fehlmessungen kommen von der Mechanischen Seite her, wenn z.B. die LED nicht genau über die Fotodiode fährt und deshalb kein vernünftiges Signal zustande kommt.

Ich hab ein wenig rumgerechnet, bei 8MHz Controllertakt sollte die Unterscheidung der Frequenzen problemlos möglich sein.

Ich würds mit einer Periodendauermessung mit TCNT1 probieren, weil die am schnellsten ein Ergebnis liefert.

Besserwessi
07.01.2010, 11:25
Das selten Problem mit fast gleichzeitigen Interrupts gibt es, auch wenn es selten vorkommt. Wenn gleichzeit die Interruptfalgs für Überlauf und ICP gesetzt sind, wird immer erst die ICP routine aufgerufen, wegen der höheren Priorität. Das passiert auch, wenn zuerst der overflow aufgetreten ist, aber die Auswertung der Interruptflags durch einen längeren Befehl (oder einen CLI-SEI Block) verzögert wurde.
Das ist ein seltener Fall, aber er tritt gelgentlich (etwa 1 mal auf 100000 Fälle) auf.

Zumindest die älteren Versionen des Simulators im AVRstudio haben dabei einen Fehler, so daß der Effekt im Simulator nicht auftrat - das ist (bzw. war) aber ein Fehler der Simulation.

Für die Periodenmessung braucht man den Überlauf aber gar nicht. Ob man die Daten jetzt direkt aus dem Timerregister oder aus dem ICP Register ließt macht kaum einen Unterschied, der Rest des Programms kann gleich sein (Nur der Fall mit der Überschneidung der Interrupts tritt noch etwas häufiger auf).

kollimann
07.01.2010, 12:19
Es geht positiv voran.
Was hab ich gemacht.

1. Meinem Mega8 ne ordentliche Spannungsversorgung spendiert, war gestern etwas wirr, so an den Schienen wo auch Signale drüber gehen etc, jetzt direkt am Trafo
2. dem Mega nen 16Mhz Quarz spendiert, so das er auch so läuft wie die Codes geschrieben wurden
3. den Sensor ordentlich angeklemmt so mit 1K gegen Masse und 100nF so wie es der Hersteller bei seinen Weichen tut

So bin ganz schön gefahren, einzeln mit versch Autos und 2 Autos Stoßstange an Stoßstange

es gab 4 Fehlmessungen, 2 sind unerklärlich, die anderen beiden passieren wenn 1 Auto kurz vor dem Messpunkt rausfliegt, kann mir vorstellen das die LED im Auto auch bissel Zeit brauch um wieder mit der vorgegeben Frequenz zu leuchten da ja da auch nen Mega8 im Auto steckt und der ja sicher auch "hochfahren" muss......

Bin zufrieden erstmal.

So zum Timerüberlauf, ich glaube, obwohl ich den Code immernochnicht versteh das der Timer nur überläuft wenn die LED im Auto mit einer höheren Frequenz geht als vorgegeben, denn der Überlauf war immer nur nach dem einsetzen. Beim normalen Zählen ist der Timer nie übergelaufen, habs mir anzeigen lassen.
Kann auch wieder sein ich lieg völlig falsch mit meiner Theorie.

Gut, ich werd also Code 1 nutzen, der geht am besten, nun muss ich nur noch verstehen was in diesem Code passiert um unnützes raus zu nehmen und dann weiter am Rundenzähler zu proggen.

So ist erstmal der Stand.

Dank euch kollimann