PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Quellcode für Geschwindigkeitsmessung



Tanja1986
10.10.2008, 15:05
Moin,
wir bauen gerade eine Art Geschwindigkeitsmessung auf. Dabei verwenden wir 4 Lichtschranken. Diese ist sowohl hell als auch dunkel schaltend. D.h. wir erhalten bei der Durchfahrt der Schranke eine STEIGENDE und FALLENDE Flanke. Mit dieser Flanke wollen einen TIMER Starten. Bei jeder Durchfahrt des Probekörpers, soll der ZEITPUNKT der Durchfahrt notiert werden.
Für unseren Aufbau haben wir ein ATMEL EVALUATION-BOARD mit dem ATmega32 Mikrokontroller.
Dem Datenblatt haben wir schon die Belegung der PORTS entnommen. Allerdings bleibt immer noch das Problem eine Stoppuhr zu programmieren. Unser C-KURS hat uns leider diesbezüglich keine Informationen gegeben. Vielleicht kann uns jemand sagen wie man mit C (wir programmieren in AVR Studio) eine Art Stoppuhr basierend auf Digitalen Eingängen programmiert?

Wir sind für eure Hilfe sehr Dankbar.

Gruß Tanja

oberallgeier
10.10.2008, 15:40
Hallo Tanja,

willkommen im Forum.


... eine Art Geschwindigkeitsmessung ...Vermutlich also eine Geschwindigkeitsmessung. Nix "Art" (polemisch grinsend).


... STEIGENDE und FALLENDE Flanke. Mit dieser Flanke wollen einen TIMER Starten ...
... Bei jeder Durchfahrt des Probekörpers, soll der ZEITPUNKT der Durchfahrt notiert werden ...Prima, "steigende ..." und so zeigen, dass Du Dich mit der Materie schon auskennst. Wird die Geschwindigkeit eines Objekts gemessen oder können konkurrierende Objekte evtl. gemeinsam durch die Lichtschranke fahren? Ich nehme mal an - nur ein Objekt.

Noch mehr Polemik (aber nicht wirklich):
Ich gehe jetzt also davon aus, dass Du sowohl die Momentan-Geschwindigkeit als auch den Zeitpunkt dieser Geschwindigkeit haben willst. Um den Zeitpunkt festzuhalten, muss eine Uhr mitlaufen. Jetzt wäre die Frage offen, wie genau die Zeitnahme und die Geschwindigkeit sein muss. Die Genauigkeit der Geschwindigkeit hängt ja z.T. von der Länge der Messstrecke ab. Für ne Durchschnittsgeschwindigkeit würde ja die "Runden-"Zeit reichen.

Ich habe etwas ähnliches so gelöst, dass ich mir einen Timer so initialisiert hatte, dass der alle 50 µs in einer ISR einen Zähler hochsetzt. Bei 16bit-unsigned-integer sind das dann max. über 3 sec. Das kann man für Langzeitmessungen so abfangen, dass z.B bei > 20000 der 50µs-counter auf Null und ein Sekundenzähler eins rauf gesetzt wird.

Nun könntest Du den INT0 (ein "externer" Interrupt, löst einen Interrupt aus wenn ein Signal am Pin ansteht, der hat noch einen Bruder, den INT1) auf steigende (od. fallende) Flanke initialisieren und eine ISR dazu bauen. In dieser ISR liest Du den aktuellen Zeitstand aus, subtrahierst ihn vom alten Wert, sicherst den neuen Wert - der wird "neuer" alter *gggg* - und musst noch den/die Sekundenwechsel abfangen. Damit könntest Du die Torzeit (oder die Durchfahrtzeit) auf 50 µs genau auflösen und den momentanen Zeitstand notieren. Wenn Deine Genauigkeitsforderung höher ist, könnte man das auch etwas anders machen.

Bevor ich noch ein ätzend seitenlanges Tutorial schreibe,
Frage: Wäre das in Deinem Sinne?

Ach so, noch etwas: guck Dir vielleicht mal diesen Link an (https://www.roboternetz.de/wissen/index.php/C-Tutorial#int.2C_char.2C_short.2C_long_.28ganze_Zah len.29) und zur Abrundung auch noch diesen hier. (http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial)

Tanja1986
10.10.2008, 21:27
Hallo Joe,
Danke für deine schnelle Antwort.
Du hast schon richtig angenommen, dass immer nur ein Körper durch die Schranken gleiten soll. Und mit dem Begriff "gleiten" bin ich schnell beim Kern meines Vorhabens. Ich versuche mit Hilfe der Schranken und der Geschwindigkeitsmessung eine Beschleunigung (und somit eine "Art" Geschwindigkeit ;-) ) zu messen. Mit Hilfe der Beschleunigung lässt sich dann auf die Gleitreibung und somit den Gleitreibungskoeffizienten µ schließen. Die Schranken sind in einem Abstand von 10cm angebracht. Mit dem ersten Interrupt würde ich gerne eine "globale" Uhr starten. Dazu soll an jeder Schranke noch mal eine einzelne „lokale“ Stoppuhr bei steigender Flanke starten und bei fallender stoppen. Es soll dann lokal eine Geschwindigkeit gemessen werden, sowie die Zeit gestoppt werden die der Körper zwischen zwei Schranken braucht. Das soll eine redundante Messung ergeben. So viel zu meinem Vorhaben. Ich hoffe dir damit beschrieben zu haben was in meinem Sinne ist :-)

Zu deinem Vorschlag: So wie ich das verstehe, hast du durch den ersten Interrupt INT0 eine Uhr gestartet. Durch das hochsetzen des Zählers erhältst du durch Multiplikation der Anzahl mit 50µs die unterbrochene Zeit. So weit kann ich dir folgen. Mein Problem liegt aber viel eher darin, dies in einen funktionierenden Quellcode zu übersetzen :-( Wie sah denn dein Code aus? Ich hab mein hintergrund eher in Mechanik als im Programmieren, leider ! Meinst du, du kannst mir dabei trotzdem Helfen?

Grüße Tanja

Besserwessi
10.10.2008, 23:16
Man braucht für die Aufgabe nur eine Uhr. Die kann man wenn man will sogar vor der eigentlichen Messung starten. Bei jeder Flanke wird einfach die Zeit in die passende Variable geschrieben. Nachdem die Messung dann fertig ist, kann man die Zeitdifferenzen berechenen.

Wenn einem die 50 µs (oder etwas kürzer) ausreichen, kann man den Zähler im Interrupts nehmen. Alternativ kann man auch direkt den Timerstand auslesen und nimmt ggf. die Zahl der Überläufe dazu. Für die meisten Lichtschranken sollten aber 10-50 µs Schritte ausreichen.

Der Messteil des Programms besteht dann im Wesenlichen aus kruzen Schleifen die darauf warten, das die nächste Flanke kommt. Also z.B.:
while (PINA & 1) ;
cli();
zeit1= Zeit;
sei();
while (~ (PINA & 1)) ;
cli();
zeit2= Zeit;
sei();
usw.....


Das Cli / Sei wird man brauchen wenn "Zeit" im Interrupt hochgezählt wird.

oberallgeier
10.10.2008, 23:18
Hallo Tanja,


... wie ich das verstehe ... durch den ersten Interrupt INT0 eine Uhr gestartet ...Nein, in der beschriebene Version läuft "die Uhr" dauernd. Das hatte ich wegen der "Zeitmarke" als notwendig angesehen, Zeitmarke im Sinne einer laufenden Uhr.

Aber die Aufgabe sieht wohl so aus, dass Du nur die Laufzeit von einem Interrupt zum nächsten brauchst. Stimmts?


... mit Hilfe ... Geschwindigkeitsmessung eine Beschleunigung ... auf die Gleitreibung ... Gleitreibungskoeffizienten ...Heee, das klingt ja nach etwas richtig Sinnvollem *ggg*. Ist der Körper ein Webschütz? Hmmm, ich nehme so etwas als Richtwert. Schätzen wir rund 30 m/s als maximale Geschwindigkeit. Als fauler Denker rechne ich mit meiner 50µs-Zeitmarke, das hieße, dass Du in diesem Bereich, 100 kmh, allenfalls auf 1,5 kmh auflöst. Reicht das?

Besserwessi
10.10.2008, 23:34
Man braucht für die Aufgabe nur eine Uhr. Die kann man wenn man will sogar vor der eigentlichen Messung starten. Bei jeder Flanke wird einfach die Zeit in die passende Variable geschrieben. Nachdem die Messung dann fertig ist, kann man die Zeitdifferenzen berechenen.

Wenn einem die 50 µs (oder etwas kürzer) ausreichen, kann man den Zähler im Interrupts nehmen. Alternativ kann man auch direkt den Timerstand auslesen und nimmt ggf. die Zahl der Überläufe dazu. Für die meisten Lichtschranken sollten aber 10-50 µs Schritte ausreichen.

Der Messteil des Programms besteht dann im Wesenlichen aus kruzen Schleifen die darauf warten, das die nächste Flanke kommt. Also z.B.:
while (PINA & 1) ;
cli();
zeit1= Zeit;
sei();
while (~ (PINA & 1)) ;
cli();
zeit2= Zeit;
sei();
usw.....


Das Cli / Sei wird man brauchen wenn "Zeit" im Interrupt hochgezählt wird.

oberallgeier
11.10.2008, 07:51
Hallo Besserwessi,

ahhhhh, stimmt - Polling ist, wenn man NUR die Zeit braucht, sicher eine gute und einfache Möglichkeit. Andernfalls käme ich bei vier Lichtschranken auch mit den zwei externen Interrupts am m16 nicht aus, zumal der auch keinen PCI hat.

Ceos
11.10.2008, 13:49
der M16 hat 4 Timer!! ich versuch grad ins datenblatt zu schaun aber atmel hat ne bescheidene übertragungsrate ... wenn da 4 inputcapture einheiten dran sind könnte man die ja für exakte messungen einsetzen

EDIT: nein er hat nur eine input capture unit, aber man könnte ja dennoch alle lichtschranken auf die ICP legen und dann mittels interrupt einfach 4 werte hintereinander speichern udn dann asuwerten (inklusive überschlag, wenn der timer überlaufen sollte)

Besserwessi
11.10.2008, 14:15
Oft sind die Lichtschranken nicht so schnell, das man die ICP Einheit braucht, man kann sie aber nutzen. Man kann den ICP Eingang über den Multiplexer vom ADC auch an den ADC-eingängen nutzen. Damit geht zwar nur jeweils eine Eingang, aber wenn man weiss in welcher reihenfolge die Flanken kommen geht das auch so. Zur ICP funktion ist eine Beispielcode in WIKI-bereich:
https://www.roboternetz.de/wissen/index.php/Timer/Counter_(Avr)#Input_Capture

oberallgeier
11.10.2008, 14:31
Hi Ceos,


... Für unseren Aufbau ... mit dem ATmega32 ...
der M16 hat 4 Timer!! ...
– Two 8-bit Timer/Counters with Separate Prescalers and Compare Modes
– One 16-bit Timer/Counter with Separate Prescaler, Compare Mode, and Capture Mode... trotzdem vielen Dank für den Hinweis. Übrigens ist der M32 auch nicht besser bestückt. Das ist ja das zeitraubende für mich an einer halbwegs vernünftigen Antwort, dass ich nicht total firm bin - selbst bei meinen "Spezial-"Controllern - und immer wieder ins doc sehen muss, um einigermassen sinnig zu bleiben.


... ich versuch grad ins datenblatt zu schaun aber atmel hat ne bescheidene übertragungsrate ...Da ich am Rande der Zivilisation wohne, eher schon ausserhalb, habe ich viele solche Dinge "on board", besser "on disk" - und noch dazu die Atmel Parameterlisten etc.


... aber man könnte ja dennoch alle lichtschranken auf die ICP legen und dann mittels interrupt ...Ich meine, dass der Tip von Besserwessi wirklich sehr pfiffig ist und eine vermutlich aufwendige Schaltung mit Oder-Gliedern etc. erspart. Man legt alle vier Lichtschranken an vier Pinne, vielleicht die erste an einen extInt, und kann dann in einer gemütlichen Spaghettimethode (na ja, die gilt dann vielleicht als unschön oder popelig) den Durchlauf des Gegenstandes durch die Lichtschranken-Straße einschließlich der steigenden und fallenden Flanken abklappern.

Ceos
11.10.2008, 14:36
wieso denn oder-verschaltung ? die haben soch nur einen schliesser wenn cih mich nicht irre, dann reicht es wenn ich den internen pullup anmach und dann nach GND schliesse, 2 geschlossene lichtschranken gleichzeitig ist eher unwahrscheinlich bei einem einzigen objekt, daher einfach alle 4 an einen pin und in der ICP ISR dann werte speichern, war ja nur n vorschlag :p

EDIT: da das topic etwas länger läuft hab ich mich von deinem post
ahhhhh, stimmt - Polling ist, wenn man NUR die Zeit braucht, sicher eine gute und einfache Möglichkeit. Andernfalls käme ich bei vier Lichtschranken auch mit den zwei externen Interrupts am m16 nicht aus, zumal der auch keinen PCI hat. in die irre führn lassen weil ich den ersten post net nomma gelesen habe :p

oberallgeier
11.10.2008, 15:07
Au au, das mit dem m16 war ja ein böser Missgriff von mir, tut mir leid (ich dachte nachts mache ich meine Fehler, aber ich seh schon, ich war unausgeschlafen).

Ich weiß nicht, was EIN Pin macht, wenn ich vier Quellen anhänge und auf steigende bzw. fallend Flanke einer einzigen Quelle detektieren will. Ok, ich kann die alle auf low ziehen, und wenn dann eine high ist, muss die es halt bringen. Aber ich denke aus Gründen der Testbarkeit sind vier getrennte Anschlüsse einfacher (da weiss man dann eher, wo der Fehler steckt - wenn´s mal nicht funktioniert).

Ceos
11.10.2008, 15:21
naja wenns nur schliesser sind und keine logiklevel (die meisten "üblichen" lichtschranken mit denen ich es in der schule zu tun hatte waren schliesser .... z.T. mit relais, problematisch wegen prellen), gibts ja keine definierten pegel! also wenn eine geschlossen ist isses egal ob ich die 3 anderen offen oder geschlossen habe, low ist low bleibt low, der präzision wegen hatte ich halt den timer vorgeschlagen, wenn die lichtschranken logiklevel servieren wäre es ja ein kurzschluss (!!!) zwischen den lichtschranken wenn eine low geht und die anderen high bleiben oder umgekehrt :p

okay .... es fielen die worte steigende und fallende flanke ... klingt stark nach logiklevel .... guuuuuuut mein fehler ... erst lesen dann denken dann schreiben

Besserwessi
11.10.2008, 16:31
Was für Anschlüse die Lichtschranken haben, hängt von der speziellen Type ab. Ich habe welche Aufgebaut, die man nicht einfach prallelschalten kann, schon wegen der Kabelkapazitäten. Lichtschranken mit Relaisausgang sind ziehmlich ungewähnlich, schon wegen der Geschwindigkeit und des Prellens.
Die Controller haben genug Pins,um jeder Lichtschraunke einen Eingang zu spendieren. So hat man die volle Flexibilität. Von der geschwindigkeit sollte Polling eigentlich reichen, das sollte für 1µs Auflösung reichen, wenn man den Timer direkt ausließt. Schnellere Lichtschranken sind schon gar nicht so leicht zu bauen.

wkrug
12.10.2008, 10:06
Von der Polling Sache würde ich Abstand nehmen, da sich die Programmlaufzeit mit jeder Programmänderung wieder verändert und voll in die Messung mit eingeht.

Deshalb würde die Zeiterfassung komplett in Interrupts laufen lassen.
Als mögliche Quellen kämen beim ATMEGA16: INT0, INT1, INT2 sowie der ICP1 in Frage.
Man könnte auch noch den analog Komperator dazu verwenden.
Als Zeitquelle kommt der Timer1 in Frage.
Der Ablauf wäre:
INT0 liest die Zeit aus dem Timer1 ( + Uberlaufvariable ) aus und speichert sie in einer Variable

INT1 liest die Zeit aus dem Timer1 ( + Uberlaufvariable ) aus und zieht den Wert von INT0 ab, speichert diesen Wert ab und setzt ein Flag.

INT2 liest die Zeit aus dem Timer1 ( + Uberlaufvariable ) aus und zieht den Wert von INT0 ab, speichert diesen Wert ab und setzt ein Flag.

ICP1 liest die Zeit aus dem Timer1 ( + Uberlaufvariable ) aus und zieht den Wert von INT0 ab, speichert diesen Wert ab und setzt ein Flag.

Im Hauptprogramm werden dann die Flags abgefragt und die Messwerte ( Geschwindigkeit ) daraus berechnet.
Wenn die Messwerte verarbeitet wurden werden im Hauptprogramm die Flags wieder gelöscht.
Der bezug auf Timer 0 deshalb, wenn eine Lichtschranke nicht reagiert, wäre die komplette Messung der nachfolgenden Lichtschranken nicht mehr auswertbar.

Man kann auch im Timer1Overflow Interrupt noch eine weitere Variable hochzählen, die die höherwertigen Bytes der Zeitmessung darstellen.

Einen Schönheitsfehler hat die Messmethode mit dem Überlauf noch- während des Zeitmessinterrupts ( z.B. INT0 ) könnte gleichzeitig noch ein Timer Overflow Interrupt anliegen, der aber nicht verarbeitet werden kann.
Als "Bastellösung" könnte man kurz vor dem Auslesen der Timer Messwerte die Interrupts mit "SEI" freigeben ( sind normalerweise während eines laufenden Interrupts gesperrt ) und danach mit "CLI" wieder sperren.
Dadurch verringert sich die Chance auf eine Fehlmessung auf ein paar wenige Prozessortakte.
Also:
#asm ("sei");
#asm ("nop");
#asm ("cli");
ui_int0low=TCNT1;
li_int0high=ui_tcnt1overflow;
li_int0high=(li_int0high*65536)+ui_int0low;
ub_int0flag=1; // Bei INT0 wäre es eigentlich nicht nötig

Der gewünschte Messwert liegt also jetzt in der Variablen li_int0high als 32Bit Integer Wert.
Das wäre eigentlich schon die Ganze Interruptroutine.
Der Rest ( Berechnung ) kann bequem in der Hauptroutine erledigt werden.
Inlineassembler könnte das Problem noch weiter entschärfen.

Die Prellgeschichte könnte man durch ein MonoFlop lösen.
Wird ein Signal von der Lichtschranke ausgegeben wird eine MonoFlop getriggert, das für mindestens 10ms den Pegel festhält.
In dieser Zeit sollten eigentlich alle Prellimpulse abgeklungnen sein.
Ebenso könnte bei Deaktivieren des Gebers verfahren werden.
Das Ganze sollte sich mit ein paar Logikgattern lösen lassen.

Zur Lichtschrankengeschichte.
So lange man Lichtschranken des gleichen Typs verwendet, sollten auch die Latenzzeiten in etwa gleich sein.
Das bedeutet, die Messung kommt zwar später an, stimmt aber, da ja alle Lichtschranken verspätet reagieren.

Besserwessi
12.10.2008, 11:11
Eine kurze Schleife beim Polling ist nicht wesenlich schlechter als die Unsicherheit durch die Verzögerung bis der Interrupt aufgerufen wird.
Das größte Problem ist dabei der eher selten auftretende Timer überlauf. Der würde das Polling oder einen Interrupt etwas verzögern. Man könnte das eventuell vermeiden, indem man Hardwaremäßig (extern) die Timer hintereinanderschaltet. Genauer wird es aber mit der ICP Funktion.
Die Lösung mit externen interrupts hat aber auch was für sich: Man ist naich darauf angewiesen in welcher Reihenfolge die Flanken auftreten. Es ist ja nicht klar ob das der Körper aus der einen Lichtschranke raus ist bevor er in die Nächste reinkommt.


Das Problem mit dem Überlauf kurz vor / nach dem Auslesen der Zeit kann man mit Hilfe der Interrupt Flags lösen, so wie im ICP Beispiel:
Wenn man einen kleinen Wert aus dem Timer einließt und ein Overflow Interrupt noch aussteht, dann muß der Overflow interrupt vorher dran, sonst nicht.

oberallgeier
12.10.2008, 11:26
Hallo wkrug,


... Polling ... Abstand nehmen, ... Programmlaufzeit mit jeder Programmänderung wieder verändert ...Vermutlich ja, wenn man innerhalb der Pollroutine ändert. Warum sollte ich denn?

... soll an jeder Schranke ... bei steigender Flanke starten und bei fallender stoppen. Es soll dann lokal eine Geschwindigkeit gemessen werden, sowie die Zeit gestoppt werden die der Körper zwischen zwei Schranken braucht ...Sie will ja die steigende UND die fallende Flanke. Und warum eigentlich nicht?
... Das soll eine redundante Messung ergeben ...Soweit ich es (vorerst) verstehe, weill sie auf dem Board nur die beschriebene Geschwindigkeitsmessung machen. Eine Stoppuhr für insgesamt sieben Werte.

... wenn eine Lichtschranke nicht reagiert, wäre die komplette Messung der nachfolgenden Lichtschranken nicht mehr auswertbar ...Genau hier liegt eine mögliche Störquelle einer Kaskade. Da denke ich, das Pollen der Zustände an vier Pinnen und das Speichern der sieben Zeiten (blos nix rechnen!) ist so schnell, dass es selbst für über 100 kmh einen Fehler unter 1 % ermöglichen sollte. Aber ich weiß noch nicht, wie gross(lang) die zu messenden Objekte sind. Diese Angabe ist für eine saubere Auslegung notwendig.

Besserwessi
12.10.2008, 12:53
Über die Genauigkeit braucht man sich auch nicht so viele Gedanken machen. Selbst wenn die Testkörker sichmit 10 m/s bewegen, gibt das in 1 µs nur 10µm. So genau von der mechanischen Position sind allermeisten Lichtschranken ohnehin nicht. Schon 0,1 mm wäre recht gut für eine Lichtschranke.

Wenn man den Timer erst mit der ersten flanke startet, könnte man sogar schon mit der 16 Bit Auflösung von Timer 1 Auskommen, und kann sich den ganzen Umstand mit den Überläufen sparen. Das Hängt aber natürlich von konkreten Aufbau ab.