Forum: Mikrocontroller und Digitale Elektronik delayMicroseconds() Error. Keine Variable erlaubt.


von Erik H. (erik_h)


Lesenswert?

Guten Tag,

Warum funktioniert delayMicroseconds() nicht mit einer variable? Ich 
dachte delay() und delayMicroseconds() sind extra für variable geeignet. 
delay() spuckt auch keine Fehler aus, aber das andere ja.
1
unsigned int pwm = 2000;
2
int c = 0;
3
4
void setup() {
5
  // put your setup code here, to run once:
6
pinMode(1,OUTPUT);
7
}
8
9
void loop() {
10
  // put your main code here, to run repeatedly:
11
pwm = 100;
12
digitalWrite(1,HIGH);
13
delayMicroseconds(pwm);
14
digitalWrite(1,LOW);
15
delayMicroseconds(20000);
16
}

Fehlermeldung:
1
Arduino: 1.8.14 Hourly Build 2020/07/13 05:33 (Windows 10), Board: "ATtiny13, 9.6 MHz internal osc., BOD 2.7V, Micros disabled"
2
3
c:\users\reder\desktop\arduino-nightly\hardware\tools\avr\avr\include\util\delay.h: In function 'main':
4
5
c:\users\reder\desktop\arduino-nightly\hardware\tools\avr\avr\include\util\delay.h:276:28: error: __builtin_avr_delay_cycles expects a compile time integer constant
6
7
  __builtin_avr_delay_cycles(__ticks_dc);
8
9
                            ^
10
11
lto-wrapper.exe: fatal error: C:\Users\reder\Desktop\arduino-nightly\hardware\tools\avr/bin/avr-gcc returned 1 exit status
12
13
compilation terminated.
14
15
c:/users/reder/desktop/arduino-nightly/hardware/tools/avr/bin/../lib/gcc/avr/7.3.0/../../../../avr/bin/ld.exe: error: lto-wrapper failed
16
17
collect2.exe: error: ld returned 1 exit status
18
19
exit status 1
20
21
Fehler beim Kompilieren für das Board ATtiny13.

von Holger L. (max5v)


Lesenswert?

Entweder mit einer entsprechenden Funktion hinbiegen:
1
void long_delay(uint16_t us)
2
{
3
    for(; us>0; us--) delayMicroseconds(1);
4
}

Oder es gleich "richtig" mit einem Timer angehen.
Hier wäre ein Beispiel für den Arduino Uno: 
https://www.exp-tech.de/blog/arduino-tutorial-timer

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Erik H. schrieb:
> Warum funktioniert delayMicroseconds() nicht mit einer variable? Ich
> dachte delay() und delayMicroseconds() sind extra für variable geeignet.
Das ist bei den originalen Arduino Cores auch der Fall.

Warum der Ersteller deiner exotischen  Boarddefinition davon abgewichen 
ist, naja....
Vielleicht, wegen der Zwergigkeit des ATtiny13?

von Holger L. (max5v)


Lesenswert?

> void long_delay(uint16_t us)
> {
>     for(; us>0; us--) delayMicroseconds(1);
> }

Sorry, das war mal Unfug... beim herunterzählen der us wird durch die 
verwendeten Prozessortakte Zeit unterschlagen, welches massive 
Auswirkungen auf das Ergebniss hat.
Wenn dies bei Millisekunden angewandt wird ist es nicht so Dramatisch, 
wenn auch unschön. Das es bei der delay() Funktion funktioniert, könnte 
daran liegen das solch eine Funktion verwendet wird.

Beitrag #6349793 wurde von einem Moderator gelöscht.
von Erik H. (erik_h)


Lesenswert?

danke, auch die unschöne version ist ausreichend.
Dann liegt das also am Board, dass delayMicroseconds nicht funktioniert? 
Evtl finde ich noch ein anderes Board.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

lies dir das durch, es sollte funktionieren.
https://github.com/MCUdude/MicroCore

von Einer K. (Gast)


Lesenswert?


von Veit D. (devil-elec)


Lesenswert?

Hallo,

übersehe ich etwas wichtiges? Laut Beschreibung nutzt er unter "der 
Haube" von delayMicroseconds(us) das standardmäßige _delay_us(us). 
Deswegen gehe ich davon das es funktioniert. Von der Sache her kann man 
dann auch gleich _delay_us(us) verwenden.

: Bearbeitet durch User
von Veit D. (devil-elec)


Lesenswert?

Hallo,

bevor ich etwas übersehe habe ich mir eine Portable eingerichtet und den 
Blink Sketch auf delayMicroseconds(1000) abgeändert. Es kompiliert auch 
mit Variable. _delay_us(1000) kompiliert auch.

Falls man millis oder micros verwendet muss man in Boardmenü "Timing" 
auf enable setzen.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Veit D. schrieb:
> Es kompiliert auch mit Variable.

Teste mal dieses:
1
void setup() 
2
{
3
  volatile double test = 55.44;
4
  _delay_us(test) ;
5
}
6
7
void loop() 
8
{
9
10
}


Aus der Doku:
Note
In order for these functions to work as intended, compiler optimizations 
must be enabled, and the delay time must be an expression that is a 
known constant at compile-time. If these requirements are not met, the 
resulting delay will be much longer (and basically unpredictable), and 
applications that otherwise do not use floating-point calculations will 
experience severe code bloat by the floating-point library routines 
linked into the application.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

aha okay, funktioniert nur mit Konstanten.

von Einer K. (Gast)


Lesenswert?

Ja, so ist es!

von Pandur S. (jetztnicht)


Lesenswert?

Allenfalls auch mal delay_nanoseconds(z) probieren...

tssss.

von spess53 (Gast)


Lesenswert?

Hi

>aha okay, funktioniert nur mit Konstanten.

Man, das hat ja echt lange gedauert. Diese Einschränkung kenne ich schon 
aus den Zeiten von KHB. Aber dafür seit ihr wohl noch zu jung in C.

MfG Spess

von Jacko (Gast)


Lesenswert?

Und das ist gut so! Wie soll das (Gehirn einschalten!) sonst
mit µs-Genauigkeit funktionieren???

Aha?
Genau! :-)

von Norbert (Gast)


Lesenswert?

spess53 schrieb:
> Man, das hat ja echt lange gedauert. Diese Einschränkung kenne ich schon
> aus den Zeiten von KHB. Aber dafür seit ihr wohl noch zu jung in C.
>
> MfG Spess

Wenn man mal den Sourcecode anschaut, erkennt man setup() und loop()
Das ist zuerst einmal ziemlich Arduino typisch.
Schauen wir mal in die Dokumentation (hab' gerade 1.8.12 hier):
1
delayMicroseconds()
2
Description
3
Pauses the program for the amount of time (in microseconds) specified as parameter. There are a thousand microseconds in a millisecond, and a million microseconds in a second. Currently, the largest value that will produce an accurate delay is 16383. This could change in future Arduino releases. For delays longer than a few thousand microseconds, you should use delay() instead.
4
5
Syntax
6
delayMicroseconds(us)
7
8
Parameters
9
us: the number of microseconds to pause (unsigned int)
10
Returns
11
None
12
13
Caveats and Known Issues
14
This function works very accurately in the range 3 microseconds and up. We cannot assure that delayMicroseconds will perform precisely for smaller delay-times.

Also ich kann anhand der Dokumentation auf den ersten Blick NICHT 
erkennen das man hier nur mit Konstanten arbeiten darf.
Wer sich schon lange mit Thema beschäftigt hat, also vor der Arduino 
Zeit, weiß natürlich das die delay_us() Funktion so gestrickt sind.

Schauen wir mal in die Implementierung,
in hardware/arduino/avr/cores/arduino/wiring.c

Auch da wird nichts von Konstanten gesagt. Wir finden eine Reihe von 
Anpassungen für versch. Taktfrequenzen und dann...
1
        __asm__ __volatile__ (
2
                "1: sbiw %0,1" "\n\t" // 2 cycles
3
                "brne 1b" : "=w" (us) : "0" (us) // 2 cycles
4
        );

Es bietet sich also an auch mal den Ball flach zu halten und nicht 
einfach Trumpartig Meinungen heraus zu blasen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Norbert schrieb:
> und dann...
Natürlich ist eine Zahlervariable variabel,  aber jetzt ist da nur noch 
die Frage, ob an die Stelle, an der subtrahiert wird, zur Laufzeit ein 
variabler Wert geschrieben werden kann.
Und wie der ggfs. zur Laufzeit für eine Taktfrequenz von ż. B. 13, 792 
MHz innerhalb von 3us ausgerechnet werden kann...

BTW ein Programm sollte sich nie auf Delays im us Bereich verlassen. 
Denn immerhin war da noch die Sache mit den Interrupts, die da 
reinfunken können.

: Bearbeitet durch Moderator
von (prx) A. K. (prx)


Lesenswert?

delay() != delayMicroseconds()

Ersteres benötigt einen konstanten Parameter, weil der Wert per Formel 
umgerechnet wird und darin der Parameter enthalten ist. Zur Laufzeit 
durchgeführt kann diese Rechnung massiv beeinflussen.

Die Umrechnung von Letzterem wird bewusst so durchgeführt, dass die 
Umrechnung sehr einfach wird und keinen konstanten Parameter erfordert. 
Sie setzt jedoch eine Taktfrequenz von den im Quellcode gezeigten 
1/8/16/... MHz voraus. Deutlich abweichende Werte führen zu falschen 
Delays

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Norbert schrieb:
> Es bietet sich also an auch mal den Ball flach zu halten und nicht
> einfach Trumpartig Meinungen heraus zu blasen.

Bist du denn sicher, dass das überhaupt die richtige Implementation ist? 
Wo ist dort der Aufruf von __builtin_avr_delay_cycles, wo im 
Ursprungsposting der Fehler gemeldet wird?

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Rolf M. schrieb:
> Bist du denn sicher, dass das überhaupt die richtige Implementation ist?

Das auch noch. Das vom TE genutzte delayMicroseconds ist jedenfalls 
nicht das, was in wiring.c implementiert ist.

von Norbert (Gast)


Lesenswert?

Lothar M. schrieb:
> Natürlich ist eine Zahlervariable variabel,  aber jetzt ist da nur noch
> die Frage, ob an die Stelle, an der subtrahiert wird, zur Laufzeit ein
> variabler Wert geschrieben werden kann.

Ja kann, laut source code in wiring.c
Dort sieht man auch das für verschiedene Arduino boards mit festen 
Frequenzen gearbeitet wird. Muss mal eben den vi starten...
1
/* Delay for the given number of microseconds.  Assumes a 1, 8, 12, 16, 20 or 24 MHz clock. */
Und da hat es dann versch. Korrekturwerte.

> Und wie der ggfs. zur Laufzeit für eine Taktfrequenz von ż. B. 13, 792
> MHz innerhalb von 3us ausgerechnet werden kann...

Arduino boards mit festen Frequenzen lt. wiring.c

> BTW ein Programm sollte sich nie auf Delays im us Bereich verlassen.
> Denn immerhin war da noch die Sache mit den Interrupts, die da
> reinfunken können.

Selbstverständlich sollte man sich nie auf Delays im us Bereich 
verlassen, es sei denn man hat sie selbst geschrieben oder den 
Sourcecode verifiziert.
Der ist Arduino-typisch ziemlich schmutzig und macht einfach mal 
Annahmen die wohl zur Sourcecode-Erstellungszeit empirisch ermittelt 
(ausprobiert) wurden.

Wir reden hier aber eben vom Arduino Umfeld, also eher etwas für 
BWL-Abbrecher. ;-)

von Norbert (Gast)


Lesenswert?

Rolf M. schrieb:
> Bist du denn sicher, dass das überhaupt die richtige Implementation ist?

Sicher? Nö.
Ich habe gesehen das der OP eine Arduino Version 1.8.14 benutzt, und 
habe in meine Antwort geschrieben das ich hier nur eine 1.8.12 habe.

von Einer K. (Gast)


Lesenswert?

Norbert schrieb:
> Der ist Arduino-typisch ziemlich schmutzig und macht einfach mal
> Annahmen die wohl zur Sourcecode-Erstellungszeit empirisch ermittelt
> (ausprobiert) wurden.
>
> Wir reden hier aber eben vom Arduino Umfeld, also eher etwas für
> BWL-Abbrecher. ;-)

Dummschwätzer.
Brett vom Schädel.
Großes Maul aber Tomaten auf den Augen.
Und offensichtlich viel Luft zwischen den Ohren.

Wie genau die Arduino Implementierung ist, findet sich in der Arduino 
Doku.
https://www.arduino.cc/reference/de/language/functions/time/delaymicroseconds/
Tut hier aber überhaupt nichts zur Sache.

Dass auf einem ATTiny13 nicht die komplette Arduino Framework 
Implementierung nutzbar ist, sollte auch dir klar sein.
Ist es dir aber nicht.

Zu blöd, zu blind und zu doof zum hinschauen.



Von dieser, hier verwendeten, Boarddefinition wird statt dessen die AVR 
LibC  _delay_us() verwendet. Und aus der Ecke kommt auch die 
Fehlermeldung.

Dein Dummschwätz betrifft also ALLE AVR-Gcc Nutzer.

Norbert schrieb:
> Ich habe gesehen das der OP eine Arduino Version 1.8.14 benutzt, und
> habe in meine Antwort geschrieben das ich hier nur eine 1.8.12 habe.
Hat damit überhaut nichts zu tun.
NICHTS.
Einfacher Grund:
Die Boarddefinition gehört nicht zu Arduino selber.

Norbert schrieb:
> Ja kann, laut source code in wiring.c
Eine Lüge!
Eine dumm dreiste Lüge!
Ich habe eben/gestern schon die konkrete Stelle verlinkt.
Hier nochmal extra für dich, zum mitmeißeln:
https://github.com/MCUdude/MicroCore/blob/9199e45eb749d34c4f73b5112b62bad5698a1906/avr/cores/microcore/Arduino.h#L91
Du siehst: Nix wiring.c, sondern Arduino.h

von Dummer Programmierer (Gast)


Lesenswert?

Das ist doch nur ein Makro und nicht vorgesehen für eine dynamische 
Warteschleife, sondern nur für Konstanten ...

Beitrag #6350417 wurde von einem Moderator gelöscht.
Beitrag #6350419 wurde von einem Moderator gelöscht.
von Einer K. (Gast)


Lesenswert?

A. K. schrieb:
> Sie setzt jedoch eine Taktfrequenz von den im Quellcode gezeigten
> 1/8/16/... MHz voraus. Deutlich abweichende Werte führen zu falschen
> Delays
Kann bei der originalen Arduino Borddefinition nicht vor kommen, da die 
Frequenzen der originalen Boards bekannt sind.

Abweichler benötigen eine Extrawurst.
Wie diese hier, in diesem Thread, für den Tiny13.

von Christoph M. (mchris)


Lesenswert?

Der Link zur avr-libc fehlt hier vielleicht noch:
https://www.nongnu.org/avr-libc/user-manual/group__util__delay.html

Erstaunlich, im Funktionsheader ist ein "double" als Parameter, stimmt 
da die Doku?:
1
void _delay_us   ( double __us )

von Einer K. (Gast)


Lesenswert?

Christoph M. schrieb:
> Der Link zur avr-libc fehlt hier vielleicht noch:
> https://www.nongnu.org/avr-libc/user-manual/group__util__delay.html
>
> Erstaunlich, im Funktionsheader ist ein "double" als Parameter, stimmt
> da die Doku?:
> void _delay_us   ( double __us )
Ja, das stimmt!
Beitrag "Re: delayMicroseconds() Error. Keine Variable erlaubt."

Da der Wert zur Kompilezeit bekannt ist, kann er auch zur Kompilezeit 
umgerechnet werden.
Steht auch in der verlinkten Doku so.

von Rolf M. (rmagnus)


Lesenswert?

Christoph M. schrieb:
> Erstaunlich, im Funktionsheader ist ein "double" als Parameter, stimmt
> da die Doku?:
> void _delay_us   ( double __us )

Ja. Und genau deshalb muss man es mit einer Konstanten als Parameter 
verwenden. Sonst müssen die floating-point-Berechnungen zur Laufzeit 
durchgeführt werden, was ggf. länger dauert als das eigentliche Delay 
und sehr viel Flash benötigt.

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
Noch kein Account? Hier anmelden.