Nein, deine Idee ist absolut nicht unprofessionell. Das arbeiten mit "wait" wäre es, das hast du aber schon selbst festgestellt.
Hallo!
Ich habe einen roboter mit einem sharp entfernungssensor, der von einem Schrittmotor gedreht wird.
Alle 50 Microsteps wird ein Entfernungswert erfasst, d.h. 32 Entfernungswerte auf 180°.
Außerdem ist der Controller noch für das Fahren, Spannungen, Lichtstärke, ... und tausend andere Sachen zuständig.
Ich bin Anfänger, darum weiß ich nicht genau, wie ich das programmieren soll, dass er alles gleichzeitig machen kann.
Also jetzt habe ich die enfernungssensor-dreh-steuerung so gemacht, das er einfach in einer endlosschleife folgende schritte macht:
- Schrittmotor-Controller über I2C den Befehl geben, dass er 50 schritte drehen soll
- Die Aktuelle Schrittmotor position abfragen, und warten bis der Schrittmotor seine Position erreicht hat
- Mit der AD-Wandlung beginnen
- Warten bis die AD-Wandlung fertig ist
...und alles wieder von vorne.
Das war mal das Testprogramm für den Drehturm, bei diesem Test wurden alle anderen Funktionen vernachlässigt. Jetzt muss ich aber diese anderen funktionen wieder dazugeben, aber ich weiß nicht wie. Diese ganzen warteschleifen zerstören mir mein ganzes Programm.
Ich glaube die lösung sind Interrupts, nur ich weiß nicht wie ich das mit denen machen soll. Ich glaube, das warten auf den AD wandler kann ich leicht mit einem interrupt umgehen, weil ich ja einstellen kann, dass der AD-Wandler einen Interrupt auslöst, wenn er fertig ist. Dann müsste ich nicht auf das AD-Wandler-fertig-Flag pollen.
Wenn ich 100ms warten will, aber nebenbei auch was machen will, wie kann ich das machen? Kann ich einen Timer machen mit einem Interrupt auf diesen Timer, dann weiß ich in welchen Abständen der Interrupt ausgelöst wird. Dann zähle ich in der Interruptroutine eine globale variable hoch, und dies frage ich dann in meinem programm irgendwie ab und kann so mit einer if abfrage warten, bis irgendein wert erreicht ist, und dann irgendeine aktion machen?
Geht das oder hab ich überhaupt nichts kapiert?
Meine Idee klingt jedenfalls ziehmlich unprofessionell.
lg Christoph
Nein, deine Idee ist absolut nicht unprofessionell. Das arbeiten mit "wait" wäre es, das hast du aber schon selbst festgestellt.
Hi,
der Sharp gibt das Ergebnis eines Messzyklus alle 40 ms heraus. Da Du vermutlich nicht weißt, wann ein Messzyklus des Sharp beginnt, solltest Du für genaue Messwerte 80 ms auf einer neuen Position warten und erst dann den ADC starten. Andernfalls könntest Du den letzten aktuellen Wert des Sharp mit dem ADC einlesen.
Warum 80 ms? Nehmen wir im schlechtesten Fall an, Du erreichst die neue Sensorposition gerade zu Beginn eines angelaufenen Messzyklus - dann wird das Ergebnis dieses Zyklus nicht korrekt sein => also warte knapp 40 ms bis der nächste Zyklus startet. Nun beginnt der Sharp die neue, korrekte Messung - die ist nach weiteren 40 ms fertig. Jetzt bekommt der ADC korrektes Futter . . . .
Wenns bei mir schnell gehen soll, lasse ich in solchen Fällen den ADC frei laufen, lese den ständig ein und freu mich halt "irgendwann" über einen neuen Messwert. Dieses Verfahren ist aus der Schublade quick&dirty, klar.
Ciao sagt der JoeamBerg
Danke für die Antworten, ich hab das oben beschriebene mal als "programm" geschrieben:
Das mit dem ADC immer aktivieren hab ich jetzt nicht gemacht, weil ich sonst nicht weiß wann er fertig ist mit der wandlung, weil wenn ich ihn immer eingeschaltet lasse setzt er das flag ja nicht wenn er fertig ist glaub ich.Code:volatile uint8_t zaehler; (Interrupt routine) zaehler=zaehler+1; //prescaler so einstellen, dass alle 1ms zaehler erhöht wird (main) ... ... if(ad-wandlung-fertig-flag==1) { ad-wert speichern; setpos(schritte); //Befehl geben, dass er 50 schritte drehen soll } else { if(ap==tp) //wenn aktuelle position==target pos dann weitermachen { if(zähler ist 80 mal erhöht worden) //ka wie ich das mach { ad-wandlung starten; } } } ... ...
Kann mein "programm" so funktionieren?
Wie mache ich die Abfrage, ob zaehler 80 mal erhöht worden ist?
lg christoph
So könnte das etwa aussehen.Code:ISR(ADC_vect){ /* Interrupt auslösen wenn ADC-conversion komplett*/ Messwert=ADC; /*Register auslesen, */ flag.ADC_Mess=1; /* Flag messen fertig */ } ISR(TIMER1_COMPA_vect){ /*Takt 1 mSek*/ Zähler ++; } if(flag.ADC_Mess){ ADC_Messwert abarbeiten } if(Zähler >=80){ Mach was }
Einen Zähler bis 80 kann manoft besser rückwärts machen, also von 80 runter bis 0. Der test ist einfach den Wert des Zählers anschauen. Oft ist das auch dann sinnvoll wenn man ohnehin einen andernen Wert jedesmal erhöht.
Vielleicht noch zwei Hinweise um die Zuverlässigkeit und die Lesbarkeit des Codes zu verbessern:
1. Falls man längere Zeiten messen möchte, muss man logischerweise eine größere Timer-Variable nehmen, z.B. 16 oder sogar 32 Bit. Hier können aber Probleme auftauchen, da der AVR mehr als einen Befehl braucht um eine solche Variable zu lesen. In diesem Fall würde ich dringend eine Zugriffsfunktion wie GetTime() oder sowas empfehlen, die den Lesezugriff atomar durchführt (Interrupts aus, Variable lesen, Interrupts wieder an), denn sonst wirst du sicher früher oder später mal über seltsame, sporadisch auftretende Bugs stolpern.
2. Mach dir doch noch eine Funktion wie TimedOut(Start, End, Timeout) die dir überprüft, ob die gewünschte Zeitspanne bereits abgelaufen ist oder nicht. Das macht den Code noch etwas leichter lesbar, und außerdem muss man so wenger Tippen . Die kann dann auch gleich einen evtl. aufgetretenen Überlauf (Start > End) berücksichtigen (das ist sinnvoll um durch einen Überlauf ausgelöste Bugs zu vermeiden).
So viele Treppen und so wenig Zeit!
Ich will mir eh noch ein paar funktionen machen, aber ich verstehe die Abfrage noch nicht so richtig.
Wenn Zähler jetzt eine 8 bit Variable ist, zählt er von 0 bis 255 in 1ms Schritten.
Wenn der Zähler gerade bei 40 ist, und dann kommt diese If Abfrage
Dann wartet er bis der Zähler bei 80 ist, dann wird 255-80=175ms das "mach was" ausgeführt, und dann wieder 80 ms Pause gemacht, usw...if(Zähler >=80)
{ Mach was
}
Wenn ich aber 80ms warten will, dann irgendwas abarbeiten will, was ca. 0,5ms dauert, und dann wieder 80ms warten will, wie soll das gehen?
Ich weiß ja nicht wie lange das abarbeiten dauert, 0,5ms sind nur geschätzt.
lg Christoph
Hallo Christoph2, ich habe hier interessantes entdeckt ...
http://www.mikrocontroller.net/topic/132436#new
Bindet Assemblerroutinen ein!
Solche Multitaskingprogrammierung, wird unter anderem sehr gut beschrieben von Manfred Schwabel - Schmidt, im Buch „Systemprogrammierung für AVR - Mikrocontroller".
lg
albert
Christoph2
Die "if" Abfrage wartet nicht, wenn die Abfrage nicht wahr ist, wird nach der geschwungenen Klammer weitergemacht.
Lesezeichen