Forum: Mikrocontroller und Digitale Elektronik expects an integer constant


von verwirrter (Gast)


Lesenswert?

Hallo zusammen.
Folgende Situation:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
5
volatile uint8_t i,p,pp,c,buf,ms,x;
6
7
int y = 1;
8
9
void ledon0(int ms){
10
  PORTD &= ~_BV(PD0);   _delay_ms(y);
11
}
12
13
void ledon1(int ms){
14
  PORTD &= ~_BV(PD1);   _delay_ms(ms);
15
}
16
17
void ledon2(int ms){
18
  PORTD &= ~_BV(PD2);   _delay_ms(ms);
19
}
20
21
void ledoff0(int ms){
22
  PORTD |= _BV(PD0);   _delay_ms(ms);
23
}
24
25
void ledoff1(int ms){
26
  PORTD |= _BV(PD1);   _delay_ms(ms);
27
}
28
29
void ledoff2(int ms){
30
  PORTD |= _BV(PD2);   _delay_ms(ms);
31
}
32
33
int main(void)
34
{
35
  
36
  
37
  DDRD |= _BV(PD0);
38
  DDRD |= _BV(PD1);
39
  DDRD |= _BV(PD2);
40
  
41
  PORTD = 0xFF;
42
  pp=1000;
43
  
44
  for(;;){
45
    PORTD &= ~_BV(PD0);
46
47
    for (i = 20; i < pp; i++)
48
    p=pp-i;   ledon1(i);   ledoff1(p);
49
  }
50
  PORTD &= ~_BV(PD1);
51
  
52
  for (i = 20; i < pp; i++){
53
    p=pp-i;   ledon0(p);   ledoff0(i);
54
  }
55
  
56
  PORTD &= ~_BV(PD1);
57
  
58
  for (i = 20; i < pp; i++) {
59
    p=pp-i;   ledon2(i);   ledoff2(p);
60
  }
61
  
62
  PORTD &= ~_BV(PD2);
63
  
64
  for (i = 20; i < pp; i++){
65
    p=pp-i;   ledon1(p);   ledoff1(i);
66
  }
67
  
68
  PORTD &= ~_BV(PD2);
69
  
70
  for (i = 20; i < pp; i++) {
71
    p=pp-i;   ledon0(i);   ledoff0(p);
72
  }
73
  
74
  PORTD &= ~_BV(PD0);
75
  
76
  for (i = 20; i < pp; i++){
77
    p=pp-i;   ledon2(p);   ledoff2(i);
78
  }
79
}

beim kompilieren entsteht diese Fehlermeldung:
1
__builtin_avr_delay_cycles expects an integer constant

und das 6mal. die Meldung bezieht sich ganz oben auf die Variable 'ms'

Die Meldung bedeutet, soweit ich gelesen hab, dass die Funktionen eine 
Konsztante als Parameterbraucht und keine Variable.

Deswegen hab ich ganz oben mal in ein delay y geschrieben.
Fehlermeldung bleibt.
aber warum bringt er hier keine Fehlermeldung.? :
1
int main(void){
2
     
3
  DDRD |= 0xff;
4
  int y = 500;
5
  while(1){
6
     PORTD|= (1<<PD0);
7
     _delay_ms(y);
8
     PORTD &= ~ (1<<PD0);
9
     _delay_ms(y);
10
   }
11
}

von Ralf G. (ralg)


Lesenswert?

verwirrter schrieb:
> aber warum bringt er hier keine Fehlermeldung.?

'y' wird nicht weiter gebraucht, deshalb wird der Wert gleich nach 
delay_ms übernommen.

Glück gehabt ;-)

von verwirrter (Gast)


Lesenswert?

und warum gehts hier nicht.?

int y = 1;

void ledon0(int ms){
  PORTD &= ~_BV(PD0);   _delay_ms(y);
}

hier wird y doch auch nicht weiter gebraucht


was kann man machen?

von Karl H. (kbuchegg)


Lesenswert?

verwirrter schrieb:

> aber warum bringt er hier keine Fehlermeldung.? :
>
1
> int main(void){
2
> 
3
>   DDRD |= 0xff;
4
>   int y = 500;
5
>   while(1){
6
>      PORTD|= (1<<PD0);
7
>      _delay_ms(y);
8
>      PORTD &= ~ (1<<PD0);
9
>      _delay_ms(y);
10
>    }
11
> }
12
>

Weil dein Compiler eine Datenfluss Analyse gemacht hat.
Die hat ergeben, dass sich der Wert von y innerhalb dieser Funktion 
nicht ändern kann und y daher immer den Wert 500 haben wird.
Daher kann der COmpiler die Variable y komplett eliminieren und überall 
dort, wo bisher y stand direkt die 500 einsetzen.

von verwirrter (Gast)


Lesenswert?

gut zu wissen...


aber irgendeine lösung muss es geben, da der code vor langer zeit 
schonmal funktionierte

von Karl H. (kbuchegg)


Lesenswert?

verwirrter schrieb:
> und warum gehts hier nicht.?
>
> int y = 1;
>
> void ledon0(int ms){
>   PORTD &= ~_BV(PD0);   _delay_ms(y);
> }
>
> hier wird y doch auch nicht weiter gebraucht

sagt wer?

Ich schreib ein zweites C-File, das so aussieht
1
extern int y;
2
3
void foo()
4
{
5
  y = 20;
6
}

und rufe die Funktion foo von main aus auf.
Und schon ist es dahin mit deiner Annahme, dass y immer den Wert 1 haben 
wird.

Da y hier eine globale Variable ist, kann nichts und niemand sicher 
stellen, dass diese Variable nicht von irgendwo anders verändert wird.
Ganz im Gegensatz zu hier
1
int bar()
2
{
3
  int y = 1;
4
5
...
hier ist y eine funktionslokale Variable. Es gibt keine Möglichkeit von 
ausserhalb diese Variable zu verändern. Wenn der Compiler die Funktion 
bar analysiert, kennt er die ganze Geschichte, was mit diesem y je 
passieren wird.

von Karl H. (kbuchegg)


Lesenswert?

verwirrter schrieb:
> gut zu wissen...
>
>
> aber irgendeine lösung muss es geben, da der code vor langer zeit
> schonmal funktionierte

Natürlich gibt es eine Lösung. Sogar mehrere

1) mach halt keine Variable
Was ist denn offensichtlich der Zweck dieser Variablen?
Der Zweck ist ja wohl, dass du quer durchs ganze Programm immer den 
gleichen Zahlenwert hast, wo auch immer du y benutzt.

Jetzt willst du natürlich nicht den Zahlenwert überall direkt im 
Programm stehen haben, weil das in einen Albtraum ausartet, wenn sich 
der WErt mal ändert.

In so einem Fall kann man dann zb den Präprozessor benutzen, der durch 
simple Textersetzung den konkreten Zahlenwert anstelle eines 
Platzhalters im Programm einsetzt. Und zwar überall dort, wo dieser 
Platzhalter vorkommt
1
#define DELAY_TIME  1
2
3
void ledon0(int ms){
4
  PORTD &= ~_BV(PD0);   _delay_ms( DELAY_TIME );
5
}

von Karl H. (kbuchegg)


Lesenswert?

2)
Du musst den Compiler davon überzeugen, dass es im Programm keine 
Möglichkeit gibt, wie y jemals seinen Wert ändern könnte.
Dazu gibt es das Schlüsselwort 'const'.
1
const int y = 1;

jetzt weiss der Compiler, dass du ihm die Zusicherung gibst, dass y 
immer den gleichen Wert haben wird. Das bedeutet nicht unbedingt, dass 
er dadurch immer bei _delay_ms( y ); diesen Zahlenwert auch benutzen 
wird. Aber die Chancen stehen schon mal nicht schlecht - zumindest die 
Voraussetzungen sind erst mal gegeben

von Karl H. (kbuchegg)


Lesenswert?

Lösung 3)

getreu dem Motto
_delay_ms ist selten die richtige Lösung, oft aber das Problem!

ein kompletter Verzicht auf _delay_ms und statt dessen die 
Implementierung nach den Regeln der Kunst mit einem Timer.

Bei Programmen, die ausser endlos ein paar LEDs blinken zu lassen, auch 
noch was anderes tun sollen, ist das sowieso das Um- und Auf, wie man 
eine derartige Funktionalität implementiert.

von Karl H. (kbuchegg)


Lesenswert?

Lösung 4)

anstatt _delay_ms direkt zu verwenden, machst du dir eben eine delay 
Funktion, der du die Anzahl der zu wartenden Millisekunden mitgibst. Die 
realisiert diese Wartezeit, indem sie entsprechend oft _delay_ms(1) 
aufruft. Denn 25 mal jeweils 1 Millisekunde gewartet sind in Summe auch 
25 Millisekunden gewartet. Oder eben verallgemeinert: x mal 1 
Millisekunde gewartet, ergibt eine totale Wartezeit von x Millisekunden
1
void delay( int ms )
2
{
3
  int i;
4
  for( i = 0; i < ms; i++ )
5
    _delay_ms( 1 );
6
}

Aber Achtung!
Die Zeiten werden nicht ganz genau stimmen, denn die for-Schleife 
braucht ja auch ein bischen Zeit für sich.

von Karl H. (kbuchegg)


Lesenswert?

> da der code vor langer zeit schonmal funktionierte

Nö. Dieser Code hat noch nie funktioniert.
Du magst ihn durch den Compiler gebracht haben, weil damals die Warnung 
noch nicht eingebaut war, aber funktionieren ist anders.
Funktionieren bedeutet, dass nicht nur der Compiler seinen Segen gibt, 
sondern das das Programm auch das tut, was drinnen steht.
Und wenn im Programm drinnen steht, dass 20 Millisekunden gewartet 
werden soll, beim Nachmessen sich aber rausstellt, dass die Wartezeit in 
Wirklichkeit 56 Millisekunden ist, dann kann man das nicht als 
funktionieren bezeichnen.
Und genau das passiert nämlich, wenn die Angabe für _delay_ms keine 
Zahlenkonstante ist: die tatsächlich realisierten Zeiten stimmen hinten 
und vorne nicht.
"Funktionieren" - geht anders.

von Kaj (Gast)


Lesenswert?

verwirrter schrieb:
> volatile uint8_t i,p,pp,c,buf,ms,x;
Warum global und warum volatile?
Bei dem Code den du gepostet hast, gibt es keinen Grund weshalb die 
Variablen global und/oder volatile sein sollten.

verwirrter schrieb:
> volatile uint8_t ...,pp,...
> pp=1000;
Und jetzt erklär doch mal, wie das jemals richtig Funktioniert haben 
soll...
Wenn es jemals Funktioniert hat, dann hat es irgendwie Funktioniert und 
mit viel Glück. Wertebereiche sollte man zumindestens ganz grob 
kennen...
Schlag doch nochmal in deinem C-Buch nach... Und wenn du keins hast, 
dann besorg dir eins.

von Ralf G. (ralg)


Lesenswert?

Karl Heinz schrieb:
> Natürlich gibt es eine Lösung. Sogar mehrere
>
> 1) mach halt keine Variable
> ...

1a)
Falls man mit unterschiedlichen Zeiten experimentieren will, welche 
(meistens) in einem Zusammenhang stehen, geht auch sowas:
1
#define DELAY_TIME  10
2
3
 _delay_ms( DELAY_TIME );
4
.
5
.
6
.
7
 _delay_ms( DELAY_TIME * 2 );
8
.
9
.
10
.
11
 _delay_ms( DELAY_TIME * 3 / 4 );

von Rolf Magnus (Gast)


Lesenswert?

verwirrter schrieb:
> aber irgendeine lösung muss es geben, da der code vor langer zeit
> schonmal funktionierte

In früheren Versionen der avr-libc/des Compilers wurde halt nicht mit 
Fehler abgebrochen, sondern man bekam nur eine Warnung, und die Delays 
waren alle falsch.

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.