PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : KM/h Messung mit 2 Lichtschranken?



TobiasBlome
17.02.2010, 20:20
Hallo,
ich möchte mit 2 Lichtschranken die Geschwindigkeit meines RC-Autos messen.
Jede Lichtschranke ist an einem Interrupteingang des µC.

Ich benutze einen MEGA 8. Kann ich den internen Taktgeber nutzen oder sollte ich einen richtigen Quarz nehmen?

Hier mein (fast) fertiges Programm. Ich konnte es leider noch nicht testen, da die Hardware nocht nicht fertig ist(habe hier nur µC mit zwei Tastern):



'-------------------------------------------------------------------------------
'Konfiguration µC:

$regfile = "m8def.dat" 'MEGA8-Deklarationen

$hwstack = 32
$swstack = 8
$framesize = 24

$crystal = 8000000
$baud = 9600 'Baudrate definieren
'-------------------------------------------------------------------------------
'Ein / Ausgänge definieren:
Ddrd = &B00000000 '0=Eingang

'-------------------------------------------------------------------------------
'Variablen
Dim Schritte As Word 'Wert vom Timer
Dim Schritte_old As Word
Dim Kmh As Single
Dim Sperre As Byte '1= gesperrt, wenn Lichtschranke 1 betätigt wurde
'2= gesperrt, wenn Lichtschranke 2 betätigt wurde

'-------------------------------------------------------------------------------
'Timer1
Config Timer1 = Timer , Prescale = 256 'Teiler
Enable Timer1
Enable Interrupts
On Timer1 Errorhandler

Config Int0 = Rising 'Falling
Enable Interrupts 'einschalten Der Interrupts
Enable Int0 'einschalten Von Interrupt Int0
On Int0 Isr0

Config Int1 = Rising 'Falling
Enable Interrupts 'einschalten Der Interrupts
Enable Int1 'einschalten Von Interrupt Int0
On Int1 Isr1
'-------------------------------------------------------------------------------

'-------------------------------------------------------------------------------



Do 'Hauptschleife


If Schritte_old = Schritte Then 'Vergleich, ob neuer Messwert vorhanden oder nicht
'nix
Else
Kmh = 33750 / Schritte 'Timerwert in KM/h umrechnen
Print "Geschwindigkeit: " ; Fusing(kmh , "###.#" ) ; " KM/h"
Schritte_old = Schritte
End If



Loop



'-------------------------------------------------------------------------------
Isr0: 'Aufruf bei Lichtschranke 1 per Interrupt
If Sperre = 0 Then
Timer1 = 0 'Timer auf 0 setzen
Sperre = 1 'für Lichtschranke 1 sperren
End If
'Print "int0 geht" 'nur zum testen
Return



Isr1: 'Aufruf bei Lichtschranke 2 per Interrupt
If Sperre = 1 Then
Schritte = Timer1 'Timerwert übernehmen
Sperre = 2 'für Lichtschranke 1 UND 2 sperren
End If
'Print "int1 geht" 'nur zum testen
Return



Errorhandler: 'wenn Timer1 überläuft
Sperre = 0 'nächste Messung freigeben
'Print "ÜBERLAUF" 'nur zum testen
Return



kurze Beschreibung:
Die 1te Lichtschranke setzt den Timer1 auf 0. Die zweite Lichtschranke schreibt den Wert vom Timer1 in eine Variable. Da die Lichtschranken einen festen Abstand von 30cm haben kann in der Do...Loop in KM/h umgerechnet werden. Die beiden Lichtschranken zählen eine Variable hoch, um versehentliches doppelt betätigen einer Lichtschranke zu verhindern. Wenn der Timer1 nach ca 2 Sekunden Überläuft, wird die Variable zurückgesetzt um für eine neue Messung bereit zu sein.
Zum testen kommt das Ergebnis nur über RS232, später soll es auf eine große 7-Segmentanzeige :-)

Tobias

Besserwessi
17.02.2010, 21:43
Der interne Takt beim AVR hat schon ein paar % Tolleranz. Solange sich die Temperatur nicht wesentlich ändert bleibt der Takt dann aber einigermaßen Stabil. Wenn man Pech hat, macht auch die RS232 schon Probleme.

Wenn man damit klar kommt, weil z.B. der Abstand der Lichtschranke ohnehin nicht so genau bekannt ist, geht es auch ohne Quarz. Ein Quarz wäre natürlich wesentlich genauer.

TobiasBlome
17.02.2010, 21:46
na dann nehme ich natürlich einen :-)

Der Abstand soll ja genau 30 cm sein und ich messe ja im ms Bereich.

Vitis
17.02.2010, 21:49
und worin genau besteht das Problem?

Prinzipiell ist für genaue Messung ein Quarz oder noch besser n
temperaturstabilisierter Oszillator zu verwenden, die
interne RC-Taktquelle ist für timingunkritische Geschichten OK,
aber alles was exaktes Timing braucht kannst Du das ziemlich
knicken. Das gilt auch für USART-Kommunikation in Baudraten
>9600 Baud.

TobiasBlome
17.02.2010, 22:15
Hallo Vitis,
ich wollte nur mal fragen ob ich etwas gravierendes falsch gemacht habe. Fehler finden ist ja schwierig, da ich keine richtige Vergleichsmessung habe. (Ich wollte mal mit dem Fahrrad durch die Messung fahren und dann mit meinem Tacho vergleichen.)

Wie du schreibst, ist es wohl besser wenn ich eine möglichst kleine Baudrate nehme. D.h. wohl auch ich muss darauf achten, dass das Messergebnis NACH der Messung nur einmal gesendet wird und dann der µC wieder frei für die Messung ist(und keine USART Kommunikation stört).

Dann kann ich mich ja an die Hardware machen.

Danke - Tobias

Richard
18.02.2010, 15:38
Bei den internen Ozzilator klappt es oft nicht mit der RS 232
weil der Ozzilator die Baudrate nicht sauber halten kann. Mit
quarz kannst Du auch weitaus schneller arbeiten. Da Du ja über IRQ
die Zeit ermittelst kann Dir die RS "§" da eh nicht reinfummeln.

Ich würde aber eher nur mit einem Timer arbeiten. Lichtschranke
1 Start Timer Lichtschranke 2 Stop Timer, Timer Wert Speicher, Return
zur Haupschleife, Auswerten und senden...Den Timer SO einstellen
das nur über eine Flanke getriggert wird.

Gruß Richard

Besserwessi
18.02.2010, 18:02
So schlecht ist der interne TAkt auch nicht. Solange man keine ungewöhnlichen Temperaturen hat, klapt es noch meistens mit der RS232, aber halt nicht immer. Wenn das Programm keinen gravierenden Fehler hat, oder die Hardware extra langsam ist, hilft es auch nicht die Baudrate unter 9600 Baud zu senken. Dadrüber kann man zusätzliche Rundungsfehler bekommen so dass es dann etwas leichter Fehler gibt.

Wenn man so wie gezeigt die Auswertung im Interrupt macht, stört es auch kaum wenn während der Wessung noch eine UART Übertragung läuft. So schnell sind die meisten Lichtschranken ja auch nicht, und auch die Position wo die Lichtschranke anspricht ist oft nicht so genau definiert.
Wenn es sein muß hätte man mit der ICP-funktion auch noch Hardwareunterstützung für den Stop Eingang.

TobiasBlome
18.02.2010, 21:45
so der Testaufbau mit Laserlichtschranken ist fertig :-)

ich benutze 2 1mW Laserpointer und zwei Empfänger vom goßen "C" (Bausatz 117420).

leider erkennen die Lichtschranken bei zu großer Geschwindigkeit nichts mehr... Muss ich mir mal den Schaltplan ansehen, ob man da etwas an der Geschwindigkeit machen kann...

Hier erst mal mein fertiger Code mit 7Seg.Anzeige:



'7 Segmentanzeige im multiplexbetrieb mit 2 Laserlichtschranken an PIN 4 (INT0) & PIN 5 (INT1)
' für die Anzeige wird ein kompletter Port (0-7 = 7Seg+DP) benötigt
' für Anzeigen mit gemeinsamer Anode
'
' Anschlüsse:
' -----------
' 7 Segmente = PB 0 - PB 7 (PB0=DP)
' 4 Anzeigen = PC 4 - PC 1 (4 Anzeigen / 4 Transistoren)
'Z 5 Anzeigen = PC 5 - PC 1 (5 Anzeigen) PC5 = Einerstelle ganz rechts!!!!
'e
'i
'c
'h
'e
'n PORTB.X
'||7|6|5|4|3|2|1|0 |Dezimal
'| _________________
'||G|F|E|D|C|B|A|DP| \/
'0| |X|X|X|X|X|X| |126
'1| | | | |X|X| | | 12
'2|X| |X|X| |X|X| |182
'3|X| | |X|X|X|X| |158
'4|X|X| | |X|X| | |204
'5|X|X| |X|X| |X| |218
'6|X|X|X|X|X| |X| |250
'7| | | | |X|X|X| | 14
'8|X|X|X|X|X|X|X| |254
'9|X|X| |X|X|X|X| |222
'______________________
'=|X| | |X| | |X| |146 (drei waagerechte Striche)
'F|X|X|X| | | |X| |226
'-|X| | | | | | | |128
'
'weitere mögliche Buchstaben:
'A-B-C-D-E-F-G-H-I-J-L-O-P-R-S-U
'
'
'
'ZEITMESSUNG FUNKTIONIERT
'kurze Beschreibung:
'Die 1te Lichtschranke setzt den Timer1 auf 0.
'Die 2te Lichtschranke schreibt den Wert vom Timer1 in eine Variable.
'Da die Lichtschranken einen festen Abstand von 30cm haben,
'kann in der Do...Loop in KM/h umgerechnet werden. Die beiden Lichtschranken
'zählen eine Variable(SPERRE) hoch, um versehentliches doppelt betätigen
'einer Lichtschranke zu verhindern. Wenn der Timer1 nach ca 2,2 Sekunden Überläuft,
'wird die Variable zurückgesetzt um für eine neue Messung bereit zu sein.
'LED an = Messung bereit. LED aus = SPERRE aktiv


'RECHNUNG ms:
'8MHz / Teiler 256 = 31250 Schritte / Sec oder / 1000ms
'1Schritt = 0,032ms
'Also x Schritte * 0,032ms = ms

'RECHNUNG KM/h:
'0,0003*3600000/100ms=10,8KM/h
'3*360/100ms=10,8KM/h
'1080/100ms=10,8KM/h

'ZUSAMMEN:
'1080/0,032/Schritte = KM/h
'33750/Schritte = KM/h
'
'337500 eine NULL mehr um das Komma zu verschieben!!!
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------


$regfile = "m8def.dat" 'AT-Mega8

$hwstack = 32
$swstack = 8
$framesize = 24

$crystal = 8000000 'Quarz: 8 MHz
'$baud = 9600 'Baudrate der UART: 9600 Baud
'-------------------------------------------------------------------------------
''Konfiguration LCD
'Config Lcd = 20 * 4
'Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7 , E = Portd.0 , Rs = Portd.1
'Cursor Off Noblink

'-------------------------------------------------------------------------------
'Konfiguration Ein- / Ausgänge
Ddrb = &B11111111 '1 Ausgang, 0 Eingang => Pin PB7-0 als Ausgang
Ddrc = &B1111110 '1 Ausgang, 0 Eingang => Pin PC6-1 als Ausgang; 0 als Eingang
Ddrd = &B11110011 '1 Ausgang, 0 Eingang => Pin PD7-4,1&0 als Ausgang; 2&3 als Eingang

'Pullup´s
Portd = &B0001100 'PullUp von Pin PD2&3 aktivieren


'-------------------------------------------------------------------------------
'Konfiguration Timer0 für 7 Segmentanzeige, Taster
Config Timer0 = Timer , Prescale = 1024
On Timer0 Timer0_isr
Const Timervorgabe0 = 245 '781 mal / Sekunde!!!
Enable Timer0
Enable Interrupts


'-------------------------------------------------------------------------------
'TIMER1 Konfiguration für Messzeit Lichtschranke:
Config Timer1 = Timer , Prescale = 256 'Teiler
Enable Timer1
Enable Interrupts
On Timer1 Errorhandler
Enable Interrupts

'-------------------------------------------------------------------------------
Config Int0 = Rising 'Falling 'wechsel von High auf Low
Config Int1 = Rising 'Falling 'wechsel von High auf Low
Enable Int0
Enable Int1
On Int0 Isr0
On Int1 Isr1

'-------------------------------------------------------------------------------
'Alias
Led Alias Portc.6 'Status LED - 1=bereit

'-------------------------------------------------------------------------------
'Variablen Anzeige:



'Variablen für die 7Seg. routine
Dim Wertstr As String * 5
Dim Y As Byte
Dim Tempbyte As Byte

Dim Digit As Byte 'Variable für Digitansteuerung

Dim Fivedigitdisplay As String * 5 'Anzeige im Ganzen

'führende Nullen entfernen
Dim Digit_aus As Bit 'Merker =0 wenn Stelle =0


'KM/h Messung / Rechnung:
Dim Schritte As Word 'Wert vom Timer
Dim Schritte_old As Word
Dim Kmh As Long 'Single
Dim Sperre As Byte '1= gesperrt, wenn Lichtschranke 1 betätigt wurde
'2= gesperrt, wenn Lichtschranke 2 betätigt wurde


'Dim Lcdmerker As Word 'lcd anzeigen

'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
'Setzen:

Digit_aus = 0

'alle Segmente aus
Portb = 0
Digit = 0


'================================================= ==============================
Do
'================================================= ==============================
If Schritte_old = Schritte Then 'Vergleich, ob neuer Messwert vorhanden oder nicht
'nix
Else
Kmh = 337500 / Schritte 'Timerwert in KM/h umrechnen
'Print "Geschwindigkeit: " ; Fusing(kmh , "###.#" ) ; " KM/h"
Schritte_old = Schritte
'Lcdmerker = 1
End If

'Anzeige Messung BEREIT
If Sperre = 0 Then
Led = 1 'es kann gemessen werden
Else
Led = 0 'es kann nicht gemessen werden
End If


''Wert auf LCD ausgeben
'If Lcdmerker = 1 Then
'Cls
'Locate 1 , 1
'Lcd Kmh ; " KM/h:"
'Lcdmerker = 0
'End If

Loop




'-------------------------------------------------------------------------------
'================================================= ==============================
'-------------------------------------------------------------------------------
'Sprungmarken
'-------------------------------------------------------------------------------
'================================================= ==============================
'-------------------------------------------------------------------------------


'-------------------------------------------------------------------------------
'ISR für Lichtschranken
'-------------------------------------------------------------------------------
Isr0: 'Aufruf bei Lichtschranke 1 per Interrupt
If Sperre = 0 Then
Timer1 = 0 'Timer auf 0 setzen
Sperre = 1 'für Lichtschranke 1 sperren
Portb = 0 'alle Segmente aus
Stop Timer0
End If
'Print "int0 geht" 'nur zum testen
Return



Isr1: 'Aufruf bei Lichtschranke 2 per Interrupt
If Sperre = 1 Then
Schritte = Timer1 'Timerwert übernehmen
Sperre = 2 'für Lichtschranke 1 UND 2 sperren damit Auto wirklich komplett durchgefahren ist
Start Timer0
End If
'Print "int1 geht" 'nur zum testen
Return



Errorhandler: 'wenn Timer1 überläuft
Sperre = 0 'nächste Messung freigeben
'Print "ÜBERLAUF" 'nur zum testen
Return

'-------------------------------------------------------------------------------
Timer0_isr: 'Timer0-Interruptroutine (312 x pro Sekunde)
'-------------------------------------------------------------------------------
Timer0 = Timervorgabe0
'If Sperre = 0 Then
Gosub 7seganzeige 'Routine für 7 Segmentanzeige
'End If
Return




'-------------------------------------------------------------------------------
7seganzeige:
' Code 7 Segmentanzeige:
'-------------------------------------------------------------------------------



'Formatiere das Display
Wertstr = Str(kmh)
Fivedigitdisplay = Format(wertstr , " 00") 'Nullen geben die Anzahl der Stellen an, damit die Stellen richtig gesetzt werden


' jeder Lauf durch die Hauptschleife zeigt ein anderes Digit
Incr Digit

Portb = 0 'Ghosting vermeiden
If Digit = 5 Then 'mache das , bis 5 erreicht ist
Digit = 0

End If

' addiere 1 zum Digitcounter, weil MID 1-basiert ist
Y = Digit + 1
' und hol das Digit, das wir brauchen
Wertstr = Mid(fivedigitdisplay , Y , 1)


'Anzeige auswählen
Tempbyte = 2 ^ Digit 'Tempbyte = 1,2,4,8,16

'Digitansteuerung auf portC: PC1-5
Portc = Tempbyte * 2 'Umdreh = 2,4,8,16,32




'Führende Nullen entfernen:




'Dieser Teil erledigt die Wandlung in 7 Segment Code

'Für Anzeigen mit gemeinsamer Anode
Select Case Wertstr

Case "0" : Portb = 126 'NULL
Case "1" : Portb = 12 'EINS
Case "2" : Portb = 182 'ZWEI
Case "3" : Portb = 158 'DREI
Case "4" : Portb = 204 'VIER
Case "5" : Portb = 218 'FÜNF
Case "6" : Portb = 250 'SECHS
Case "7" : Portb = 14 'SIEBEN
Case "8" : Portb = 254 'ACHT
Case "9" : Portb = 222 'NEUN
Case " " : Portb = 0 'nichts - kein Segment
'Case Else : Portb = 128 'mittleres Segment
Case Else : Portb = 226 '"F"
End Select





'Komma setzen
'If Portc = 2 Then Portb.0 = 1 '4 Kommastellen
'If Portc = 4 Then Portb.0 = 1 '3 Kommastellen
'If Portc = 8 Then Portb.0 = 1 '2 Kommastellen
If Portc = 16 Then Portb.0 = 1 '1 Kommastelle