PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Geschwindigkeitsmessung via 2 Lichtschranken



D35troy3r
28.01.2012, 11:17
Hallo!

Bin gerade dabei eine Geschwindigkeitsmessung für Luftgewehre etc aufzubauen. Soweit so gut, ich habe nun 2 Lichtschranken im Abstand von 6cm aufgebaut. Der Mikrocontroller (Atmega8 ) soll die Zeit in us messen und die Geschwindigkeit in m/s auf einem Display wiedergeben.
Mein Aufbau funktioniert ganz gut, nur bei der Programmierung sitzt warscheinlich ein Fehler...
Denn bei einem ersten richtigen Test wo die Projektilgeschwindigkeit knappe 20m/s betrug zeigt er mir etwa 150m/s an :(.

Zur Funktion:
Das Projektil passiert Lichtschranke 1 und setzt Variable X = 1. Bei jedem Interrupt des Timers wird Y erhöht, solange bis Lichtschranke 2 unterbrochen und X auf 0 gesetzt wurde. Folglich wird die Geschwindigkeit ausgerechnet und auf dem Display für 30ms angezeigt. Durch den Timer ist es aber wesentlich länger als 30ms...
Die ADC-Werte von Licht1, Licht2, Licht3 und Licht4 werden verglichen damit X erst ab einem Wert unter 1022 verändert wird.

Das ganze wurde mit Bascom programmiert:


$regfile = "m8def.dat"
$crystal = 8000000
$hwstack = 100
$swstack = 100
$framesize = 100

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

Config Adc = Single , Prescaler = Auto , Reference = Avcc
Start Adc

Config Timer1 = Timer , Prescale = 8
Enable Timer1
On Timer1 Takt
Enable Interrupts
Timer1 = 65534

Dim Licht1 As Integer
Dim Licht2 As Integer
Dim Licht3 As Integer
Dim Licht4 As Integer

Dim X As Bit
Dim Y As Word
Config Single = Scientific , Digits = 4
Dim Geschwindigkeit As Single

Licht3 = Getadc(4)
Licht4 = Getadc(5)

Cls

Do
Licht1 = Getadc(4) + 2
If Licht1 < Licht3 Then X = 0

Licht2 = Getadc(5) + 2
If Licht2 < Licht4 Then X = 1

If X = 0 And Y > 0 Then
Geschwindigkeit = 60000 / Y
Locate 2 , 2
Lcd Geschwindigkeit ; "m/S"
Y = 0
Waitms 30
Cls
End If
Loop
End

Takt:
Timer1 = 65534
If X = 1 Then Incr Y
Return

Durch den Timer verlangsamt sich die Ausgabe auf dem Display extrem....könnte man da was machen?
Findet ihr einen Fehler bzw einen Verbesserungsvorschlag?
Wieso stimmt die Ausgabe auf dem Display nicht?

Vielen Dank im vorraus! :)
Gruß

D35troy3r

masasibe
28.01.2012, 12:10
Hallo,
ähm könnte es sein, dass das Problem auftritt, weil du den Timer immer von 65534 wegzählen lässt. Dann muss der Timer ja nach 2 durch den Prescaler geteilten Takten einen Interrupt auslösen. Ich glaube, Bascom kann da keinen so effektiven Maschinencode generieren. Und wenn der Timer etwas langsamer tickt würde das die zu hohe angezeigte Geschwindigkeit erklären.

D35troy3r
28.01.2012, 12:26
Ich hab den Wert mal auf 65535 geändert, nun sollte er einen Durchlauf wie gewünscht haben. Die Geschwindigkeiten die angezeigt werden liegen jetzt endlich nichtmehr bei 120m/s sondern viel niedriger bei 5,8m/s.
In Wirklichkeit sind es aberrund 16m/s.... :(
Am Atmega ist noch kein Quarz oder ähnliches angeschlossen (kommt noch), ich benutze also den internen RC-Oszi. Doch der hat doch nicht eine solch riesige Toleranz das es 10m/s unterschied ergibt?

Besserwessi
28.01.2012, 12:26
Von der Hardware-anbindung ist schon mal die Auswertung über den AD ein Problem: Der ADC ist relativ langsam. Schon da hat man ein Unsicherheit von vielleicht 0,1 ms - eventuell auch noch mehr. Bei einer gesamten Zeit von rund 3 ms ist das schon reichlich. Wenn die Lichtschranken das hergeben würde ich die Signal lieber Digital auswerten, also über Pina. Wenn es weiter mit dem ADC sein soll, kann man vermutlich die geschwindigkeit des AD-Taktes etwas höher wählen, z.B. ein Teiler von 16 oder gar 8.

Die Schleife ist auch recht lang und fragt alles mögliche ab - da kann man lieber 2 Schleifen haben: eine zum Warten auf Start und eine zum Warten aus Stop. Mehr sollte in den Schleifen nicht drin sein.

Die Zeitmessung sollte man auch nicht mit der ISR machen, sondern einfach den Timer das hochzählen überlassen. Man startet den Timer, wenn man die Startbedingung erkannt hat, und ließt dann beim Stop den Timer aus. So wie eingestellt zählt der Timer µs - das reicht also schon bis 65 ms oder für eine Geschwindigkeit bis 1 m/s runter. So wie das Programm jetzt ist braucht die ISR viel zu lange, und es kommt schon längst der Nächste Interrupt, bis die ISR fertig ist. Der µC macht dann einmal die 1 ISR (ca. 50-80 ASM Befehle) und dann einen ASM Befehl des Programm. Entsprechend läuft das Programm nur mit etwa 1-3 Prozent der normalen Geschwindigkeit.

Die genauste Lösung wäre die Benutzung der ICP Funktion - da muss dann aber das Signal der Lichtschranke mitspielen.

masasibe
28.01.2012, 12:41
Du hast beim Bascom ja eine Taktfrequenz von 8MHz eingestellt (Das hat zwar auf den Timer keine direkte Auwirkung) aber bei den ATmegas ist glaube ich standardmäßig der interne Taktteiler aktiviert, somit hätte der ATmega nur einen Takt von 1Mhz und wenn du aber für die Berechnung des Timers von 8Mhz ausgegangen bist ist das Ergebnis natürlich nicht richtig.

D35troy3r
28.01.2012, 14:01
Das Programm sieht nun folgendermaßen aus:

$regfile = "m8def.dat"
$crystal = 8000000
$hwstack = 100
$swstack = 100
$framesize = 100

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

Config Timer1 = Timer , Prescale = 8

Config Pinc.5 = Input
Config Pinc.4 = Input

Config Single = Scientific , Digits = 4
Dim Geschwindigkeit As Single

Cls

Do
If Pinc.5 = 0 Then
Enable Timer1
Exit Do
End If
Loop

Do
If Pinc.4 = 0 Then
Disable Timer1
Exit Do
End If
Loop

Cls

Locate 1 , 1
Lcd Timer1
Geschwindigkeit = 60000 / Timer1
Locate 2 , 2
Lcd Geschwindigkeit ; "m/S"

End


Ich lasse mir gerade die gemessene Zeit und die Geschwindigkeit anzeigen.
Funktioniert ganz gut bis jetzt...doch die Rechnung haut nicht ganz hin?! Ein beispiel: auf dem Display steht 5401us aber eine eine Geschwindigkeit von 5,6m/s lol...

Das verwirrt mich jetzt etwas -.-

Taktteiler ist aus bei meinem Atmega :)


P.s: gut Problem mit den Berechnungen behoben...Timer1 musste ich in eine variable packen..erst dann waren die Ergebnisse richtig. Ich teste mal weiter

Besserwessi
28.01.2012, 14:38
Die Befehle Enable Timer und Disable Timer steuern nur die Erzeugung von Interrupts - der Timer läuft trotzdem weiter. Ob BASCOM da extra Befehle zum Starten und anhalten des Timers hat, weiss ich nicht. Es geht aber auch beim Start einfach mit Timer1= 0 den Wert zurückzusetzen. Am Ende ließt man den Timer dann einmal aus und speichert die Zahl in einer Variable.

Damit wäre auch schon mal geklärt, wieso man nicht direkt mit der Größe Timer rechnen kann.

D35troy3r
28.01.2012, 15:41
Ich danke dir! Jetzt funktionierts auch richtig :D
Bis 30m/s hab ich eben gemessen...werde mir mal morgen das Luftgewehr suchen und damit eine Messung durchführen :)
Ich hoffe das es messbar ist da ichs ja nun nurnoch über einen digitalen port machen.

Hier noch der Code falls das Thema jemand aufsucht:


$regfile = "m8def.dat"
$crystal = 8000000
$hwstack = 100
$swstack = 100
$framesize = 100

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

Config Timer1 = Timer , Prescale = 8


Config Pinc.5 = Input
Config Pinc.4 = Input

Config Single = Scientific , Digits = 4
Dim Geschwindigkeit As Single
Dim Y As Word
Cls

Do
If Pinc.5 = 0 Then
Timer1 = 0
Exit Do
End If
Loop

Do
If Pinc.4 = 0 Then
Y = Timer1
Exit Do
End If
Loop

Cls
Locate 1 , 1
Lcd Y
Geschwindigkeit = 60000 / Y
Locate 2 , 2
Lcd Geschwindigkeit ; "m/S"

End