Hallo allerseits, zur Zeit stelle ich allerhand Überlegungen zur Realisierung eines Geschwindigkeitsmessers an. Als Hardware steht ein ATMega168 zur Verfügung, der über ein PCINT mit einem Reed-Schalter verbunden ist. Ziel ist es, die Zeitabstände zwischen dem Schalten des Reed-Schalters zu erfassen. Leider ist kein normaler Interrupt-Pin frei, sodass auf einen Pin Change Interrupt ausgewichen werden muss. Das erschwert die Erkennung der Flanken bzw. das Entprellen des Signals. Ohne jegliche Unterdrückung zählt der Controller ca. 10 Schaltvorgänge, wo eigentlich nur einer sein dürfte. Mein größtes Problem ist aber die Erkennung der Zeitabstände. Die aktuellsten Überlegungen zielen dahin, bei jedem zweiten Signal einen 16bit-Counter zu starten bzw. dann ein Signal später zu stoppen bzw. zurückzusetzen. Ist das eine sinnvolle Methode? Der ATMega168 wird mit einem (timerfreundlichen) 3,6864 MHz Oszillator betrieben, was bei einem Vorteiler von 256 dann 14400 Counts pro Sekunde bringt. Aus den Anforderungen resultiert, dass im 'schlimmsten' Fall am PCINT alle ~ 50ms ein Signal anliegt. Mit den 14400 Counts erfasse ich alle 69,4µs ein Signal, habe also einen Messfehler <1%. Während die Erfassung des Signals unter Echtzeitbedingungen funktionieren muss, soll die Ausgabe auf einem LCD stattfinden, was entsprechend langsam ist. Daher macht es eigentlich wenig Sinn die Geschwindigkeit für jeden Interrupt zu berechnen, sondern alle z.B. 1/4s. Daraus würde ich eine zweite Variante erhalten, nämlich den Timer bis 1/4s (Beispiel) laufen lassen und in der Zeit einfach die Interrupts zählen. Über die Genauigkeit dieser Methode bin ich mir aber nicht sicher. Erschwerend kommt hinzu, dass durchaus langsame Geschwindigkeiten existieren, bei denen die Zeit zwischen den Interrupts über 1/4s beträgt. Die abzudeckende Zeitspanne ist 50ms bis 2800ms. Alles länger als 2800ms entspricht 0km/h und alles kürzer 50ms braucht nicht erfasst zu werden. Trotz, oder gerade wegen, dieser ganzen Bedingungen und Überlegungen konnte ich noch auf keine vernünftige Idee kommen. Hat jemand Ideen oder Anregungen?
Hi Drehzahlmesser... , hab ich auch grad einen in der Mangel. Sprache ASM, Controller Atmega8 Da ich die Genauigkeit nicht brauche und Drehzahl max. bis 5000 U/min geht, reicht mir das Einlesen des Impulses der Umdrehung im Polling. Also, ein Timer zählt in einer Variablen msek. Zum Zeitpunkt Impuls wird der Zählerstand in eine andere Variable kopiert und der Zähler zurückgesetzt. Anschließend wird mit ein bischen Mathe die Umdrehung aus dem abgelegten Wert errechnet und auf eine 7 Segment-Anzeige umgesetzt. Bis hier arbeite ich in der normalen Programmschleife. Die Anzeige wird alle 10 mSek. für eine Ziffer aktualisiert. Da keine Berechnungen durchgeführt werden und nur auf die abgelegten und bereits Codierten Werte zugegriffen wird, ist die Belastung der ISR gering. Ein LCD würd ich sogar auch aus der normalen Programmschleife versehen. Die Mathematik ür Assembler findest du in der Codesammlung. Gruß oldmax
Vielen Dank für deine Antwort. Zunächst einmal möchte ich erwähnen, dass ich das Programm in C schreibe, da eine Einarbeitung in Assembler mir zu viel Zeit kostet. Deine Idee scheint soweit nicht schlecht zu sein. Ich verfolge zur Zeit eine ähnliche Methode, allerdings will sie noch nicht so ganz... Mal ein wenig Pseudo-C-Code, um es zu verdeutlichen:
1 | uint_16t s_cnt=0, speed=0; |
2 | |
3 | void main(int) { |
4 | //der ganze init()-kram
|
5 | while(1) { |
6 | //ausgabe der geschwindigkeit auf lcd
|
7 | lcd_write(utoa(speed)); //Pseudo-Code |
8 | }
|
9 | return 0; |
10 | }
|
11 | |
12 | //PCINT-ISR (pin change interrupt)
|
13 | ISR(PCINT1_vect) { |
14 | if(s_cnt > 720) { //Berechnung erst, wenn Signalabstand >50ms |
15 | speed = (int) (r_umfang * 5184) / (100*s_cnt); |
16 | s_cnt=0; //Rücksetzten des Signal-Timers |
17 | }
|
18 | }
|
19 | |
20 | //timer-ISR
|
21 | ISR(TIMER0_COMPA_vect) { |
22 | s_cnt++; //Signal-Timer inkrementieren |
23 | if(s_cnt>=60000) { //overflow vermeiden |
24 | s_cnt=0; |
25 | }
|
26 | }
|
Eine kurze Erläuterung des Ganzen: Ein Timer läuft im Hintergrund mit 14400 Inkrementen pro Sekunde. Diese werden in einer Variable festgehalten und diese gegen Overflow geschützt. Ein längere Zeitspanne als 3 oder 4 Sekunden (enspricht rund 60000) ist ohnehin nicht von Interesse, daher wird die Variable einfach wieder zurückgesetzt (=0). Bei jedem Signal an PCINT1/PC0 wird überprüft, ob die Variable mindestens 720 beträgt, was einer Zeit von 50ms entspricht. Das dient als eine Art Entprellung. Ist die Variable größer, wird die Berechnung für die Geschwindigkeit vorgenommen, welche wiederum auf dem LCD ausgegeben wird. Da die ganze Sache nicht funktioniert, lasse ich mir testweise s_cnt auf dem LCD anzeigen. Die Beschränkung auf < 60000 scheint nicht zu funktionieren, da auch größere Zahlen ausgegeben werden. Stehe aber so sehr auf dem Schlauch, dass ich keinen Programmierfehler oder Denkfehler finde. Weiß jemand weiter? Wünsche einen entspannten 4. Advent!
>Ziel ist es, die Zeitabstände zwischen dem Schalten des Reed-Schalters >zu erfassen ... >Ein Timer läuft im Hintergrund mit 14400 Inkrementen pro Sekunde. Das passt nicht gut zueinander, da die gewünschte Auflösung nicht besser sein kann als die Prellzeit des Sensors. Hast Du die Möglichkeit einen Magnetfeldsensor zu nehmen? Beispielsweise TLE4905. Der prellt nicht.
Die Prellzeiten bzw. das gesamte Schaltverhalten wollte ich ohnehin kommende Woche mit einem Oszilloskop untersuchen, habe leider keins zu Hause. Theoretisch wäre es auch möglich mit einem Hallsensor zu arbeiten, dafür müsste ich mir aber einen bestellen, was bei den Versandkosten ein schlechtes Kosten/Nutzen-Verhältnis hat. Es muss doch auch mit einem Reedschalter gehen?! Von dem Reedschalter (Hamlin MARR-5) habe ich ein Datenblatt, wo die Operate Time und Release Time angegeben sind. Laut Angabe sind die Zeiten inklusive Bouncing < 1ms, was locker auf meine Anforderungen passt. So ganz traue ich dem Braten allerdings noch nicht, da es doch auch darauf ankommt, wie der Magnet an dem Schalter vorbei geführt wird (gleichmäßige Bewegung, Zucken, Geschwindigkeit, Gerade/Schräg). Problematisch ist bei meinem Aufbau, was ich bereits eingangs erwähnt habe: Es steht mir kein richtiger Interrupt mit Flankenerkennung zur Verfügung, da die Pins ungünstigerweise belegt sind. Somit muss ich auf den Pin Change Interrupt ausweichen, der natürlich für jede Flanke auslöst. Mit der Software habe ich noch keine geschickte Lösung finden können, um nur die negative Flanke zu detektieren.
>Mit der Software habe ich noch keine geschickte Lösung finden >können, um nur die negative Flanke zu detektieren. Immer den letzten Zustand des Schalters im Interrupt speichern: akt_zustand = EINGANG; zustand = (akt_zustand ^ alter_zustand) & akt_zustand; alter_zustand = akt_zustand; zustand == 1: Eingangspin = 1, sonst 0. Wie wäre es mit einer Lichtschranke? Auch zu teuer? :-)
Die XOR-AND-Methode ist prima, funktioniert sehr gut! Eine Lichtschranke geht prinzipiell natürlich auch, ist nur empfindlich gegen Verschmutzung. Der Kostenfaktor wäre grundsätzlich kein Problem. Da es sich hierbei aber um ein Lern-Projekt handelt und es in der Praxis wohl so nie eingesetzt wird, lohnt sich die Anschaffung von aufwändigerer Hardware nicht wirklich. Aufbauend könnte man anschließend natürlich relativ einfach eine Implementierung umsetzen, aber das ist Zukunftsmusik. :)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.