Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem mit Ausführungszeit bzw. micros() und delayMicroseconds()
Hallo,
ich habe folgenden Testcode für den Arduino Uno.
void setup() {
Serial.begin(115200);
while(!Serial){}
pinMode(3,INPUT);
}
void loop() {
int a = micros();
int c = digitalRead(3);
delayMicroseconds(1);
int b = micros();
b=(b-a)*4;
Serial.println(b);
delay(2000);
}
Ich will wissen, wieviel Zeit der Befehlsblock
int c = digitalRead(3);
delayMicroseconds(1); in Anspruch nimmt. Ich erhalte eine Ausgabe, die sehr wechselhaft ist:
32
16
16
32
16
32
16
16
32
16
16
16
32
16
32
16
So weit ich das verstanden habe ist es doch auf dem UNO so, das micros() ein Vielfaches von 4 zurückgibt. Also multipliziere ich das Ergebnis mit 4. Dennoch braucht er einmal dann die doppelte Zeit zur Ausführung des Befehlsblocks? Ich denke:
- dass der Controller hier entweder zwischendurch dann was anderes macht, was Zeit benötigt
- der Mikrosekundenzähler eine relative Abweichung hat
Vielleicht weiß jemand besser darüber bescheid und kann mal eine Erläuterung dazu geben, was diese Schwankungen hervorruft?
Gruß, Moppi
Hallo,
also was micros() zurück gibt sind schon Mikrosekunden. Sie werden nur nicht im Mikrosekundentakt weitergezählt, weil die Leistung der Hardware das nicht hergibt.
Letzteres kann auch ein Grund dafür sein, dass man eine Verzögerung von einer Mikrosekunde so eventuell nicht so hinkriegt.
digitalRead ist eine ziemlich fette Funktion, die macht eine Menge Sachen. Das dauert sicher viel länger, als das Warten danach. Wenn man so schnell mit IOs arbeiten will, sollte man direkt mit den Ports arbeiten, oder ein entsprechendes Gegenstück zu digitalReadFast auf dem Teensy verwenden, da kenne ich mich mit den verfügbaren Libs für den Uno nicht aus.
Zumindest theoretisch sollten bei digitalRead zeitliche Abweichungen entstehen, wenn da der Interrupt dazwischenfunkt, der die millis weiterzählt.
Ja das ist ja die Frage: was zwischendurch passiert.
Ich habe jetzt eigentlich nicht gedacht, dass er anfängt über einen Interrupt die Microsekunden zu zählen. Gibt es dafür keinen Zähler, der nebenbei herläuft?
Aufgrund dieser Sache mit der Auflösung von 4 Microsekunden pro Zählerwert, müsste dann als Minimum bei delayMicroseconds() eine 4 stehen, also eigentlich müsste man so schreiben: delayMicroseconds(1*4), was dann immer ein Vielfaches von 4 Microsekunden wäre.
Nachtrag:
Wenn ich mit dem Wert von 4 arbeite delayMicroseconds(4), dann habe ich immer denselben Wert von 32. Wenn ich delayMicroseconds() weg lasse dann erhalte ich immer wechselnde Werte von 16 und 32. Dasselbe, wenn ich delayMicroseconds(1) schreibe. Dauert das vielleicht mit dem Auslesen der Microsekunden via micros() unterschiedlich lange?
Er zählt die Millisekunden über einen Interrupt. digitalRead ist so groß, dass es da gelegentlich eine Unterbrechung geben kann.
Ich kenne nur die micros() Implementierung für die 32 Bit Teensys, um die für AVR zu suchen habe ich weder Lust noch Zeit.
Reduziert aufs wesentliche sieht der Code für micros() auf dem Teensy so aus:
uint32_t micros(void)
{
uint32_t count, current;
__disable_irq();
current = SYST_CVR;
count = systick_millis_count;
__enable_irq();
current = ((F_CPU / 1000) - 1) - current;
return count * 1000 + current / (F_CPU / 1000000);
}
Wird also aus millis und einem schnell laufenden Zähler berechnet.
Geht wahrscheinlich auf einem AVR ähnlich.
Das mit dem Multiplizieren mit 4 beim UNO Rev3 ist jedenfalls irgendwie Quatsch. Wenn ich micros auslese gibt er ganz normal micros zurück (nix mit 4 oder so) - wenn ich das mit millis vergleiche. Wenn ich millis auslese, soll er ja auch millis zurückgeben.
Na ja, entscheidend für mich ist, dass ich immer dieselbe Messeinheit dort auslese, um Verarbeitungszeiten untereinander zu beurteilen.
Danke für Deine Hilfe mxt!
Das mit dem Multiplizieren mit 4 beim UNO Rev3 ist jedenfalls irgendwie Quatsch.
Hast du schon mal 3 oder 5 oder 6 oder 7 als Ergebniss bekommen?
MfG Klebwax
Wie man hier lesen kann, ist micros() bei den Arduino 8-Bittern mit einem Zähler implementiert, der alle 4 us weiterzählt
https://ucexperiment.wordpress.com/2012/03/17/examination-of-the-arduino-micros-function/
Die Einheit ist also Mikrosekunden aber die Auflösung nur 4 Mikrosekunden. Zu multiplizieren gibt es da nichts, das macht micros schon intern.
Danke für den Hinweis!
Um aber nicht wieder einen neuen Thread aufzumachen:
Nachdem ich nun gestern ATmega328 ohne Bootloader bekommen habe, war ich gezwungen, mich den halben Tag damit auseinanderzusetzen, inkl. Beschaltung und Quarz.
Ich habe mal im Datenblatt geschaut, wegen Geschwindigkeit:
Speed Grade:
̶ 0 - 4MHz@1.8 - 5.5V, 0 - 10MHz@2.7 - 5.5.V, 0 - 20MHz @ 4.5 - 5.5V
Mal gucken, ob ich das richtig denke, zum 328P:
Man kann den mit max. 10 MHz bei 3.3V betreiben?
Man kann den mit max. 20 MHz an 5V betreiben?
Die unterste Grenze liegt bei 0 Hz? - Dann tut er nichts mehr.
Den 328P findet man immer mit 16MHz@5V betrieben. Warum nicht mit 18MHz oder 20MHz?
Weniger MHz = geringere Geschwindigkeit = geringerer Stromverbrauch?
Und wenn ich schon beim Fragen bin:
Der interne Taktgeber, so habe ich im Netz gelesen, kann auch benutzt werden. Das muss aber über diese Fuse-Bits eingestellt werden. Wo ändert man die? - Wohl beim Bootlader aufspielen. Aber wo stehen die im Sketch ArduinoISP? - Dort müssten die doch zu finden sein. Oder stehen die in einer extra Datei, die man ändern muss?
Noch was zu einem externen Takt: muss das ein Quarz sein oder kann das auch was anderes sein? Wie ein Takt am Digitalausgang eines anderen Mikrokontrollers? - Dann könnte man auch an einem andern ein PWM-Pin abgreifen.
Ich versuche mal einen Teil zu beantworten, den Rest werden ggf. Leute erklären, die sich mehr mit den AVRs auskennen.
Den 328P findet man immer mit 16MHz@5V betrieben.
Das stimmt nicht, ich kenne z.B. Displays, wo er als Controller verbaut ist, die arbeiten mit 10,... oder 14,... MHz. Das braucht man auch, um bestimmte Baudraten bei der seriellen Schnittstelle exakt hinzubekommen, die werden nämlich durch ganzzahlige Teilung aus dem Takt erzeugt.
Und ich bin sicher, hier im Forum gibt es Leute, die verwenden ihn bei 20 MHz.
Weniger MHz = geringere Geschwindigkeit = geringerer Stromverbrauch?
Das gilt für den Prozessor, aber nicht für Bauteile drum herum, wie z.B. Spannungsregler.
Aber wo stehen die im Sketch ArduinoISP?
Wenn der Sketch aus der IDE gemeint ist: Gar nicht. Dieser Sketch dient dazu aus einem Arduino einen Programmer zu machen. Das ist nicht der Code für einen Bootloader.
muss das ein Quarz sein oder kann das auch was anderes sein?
Bei einem normalen Uno ist das kein Quarz, sondern aus Kostengründen ein Keramikresonator. Der ist billiger, hat aber einer größere Toleranz bei der Frequenz.
Digitalausgang statt Quarz glaube ich nicht.
Auch darf die Frequenz eher nicht variabel sein, die Teilerverhältnisse für millis, Serial, I2C, SPI, PWM usw. sind bei den Dingern ja meist fest eingestellt.
Auch darf die Frequenz eher nicht variabel sein, die Teilerverhältnisse für millis, Serial, I2C, SPI, PWM usw. sind bei den Dingern ja meist fest eingestellt.
So etwas habe ich mir auch gedacht. Weswegen die UNOs wohl dann immer mit 16MHz betrieben werden - dazu habe ich gerade das hier gefunden: https://www.mikrocontroller.net/topic/341298
ZU den Fuse-Bits habe ich auch was passendes gefunden:
By editing the boards.txt file in the Arduino installation folder you can use any values you desire for the fuses. (http://www.martyncurrey.com/arduino-atmega-328p-fuse-settings/)
Warscheinlich laufen die meisten Einstellungen bei Arduino über die boards.txt. Ob der Bootlader da überhaupt beteiligt ist, weiß ich nicht.
Die Takteinstellungen im Menu der Arduino IDE, wie hier bei Teensy 3.2 wählen auch nur unterschiedliche Zeilen in der Boards.txt aus
33656
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.