delay Problem mit delay.h und eigener schleife

OP #788826
Lesenswert?

Hallo,
ich benutze die util/delay.h in meinem Code.

Sieht so aus:

    #define delayms 1

    void waitms (uint16_t ms){
        for(ms;ms>0;ms--)_delay_ms(delayms);
        }

Aufruf im Programm:

    waitms(100);


Wieso verdammt funktioniert die waitms Schleife nicht richtig?!?
Wenn ich nur z.B:_delay_ms(10); benutze geht es ja auch...(im zulässigen 
rahmen von 16mhz F_CPU)

Ich verstehe nicht wie es sein kann, dass ich nicht einfach 100 mal eine 
milli Sekunde warten kann. 1 milli Sekunde wird ja voll von dem Makro in 
der delay.h abgedeckt...

Hat da vielleicht einer eien Tipp?

Danke schonmal

Grüße Daniel
OP #788850
Lesenswert?

So definiere ich F_CPU

#define F_CPU 16000000
#include <util/delay.h>

Quelltext als Anhang.

Äh wieso kann ich keine zip Datei anhängen?!?

Mann, klappt auch garnix grad !

Na ja, also der ganze Controller bleibt irgedwie hängen, als wenn das 
delay einfach mal so 3-10 Sekunden braucht, sehr seltsam...
OP #788881
Lesenswert?

Da das hochladen der Datei nicht geht, sehe ich mich gezwungen den 
genzen Code zu posten, sorry...
1
#include <avr/io.h>
2
#include <string.h>
3
#include <avr/interrupt.h> 
4
#include <stdlib.h>
5

6
#define F_CPU 16000000
7
#include <util/delay.h>
8

9
#define BAUD 4800l
10

11
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
12
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // reale baudrate
13
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000) // fehler in promille 
14
#if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))
15
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch! 
16
#endif
17

18
#define BUFFER_LEN 100    
19

20
#define delay1ms 1
21

22
void uputc(unsigned char);    //Zeichen in Ring-puffer (trozdem nur über uprints!!)
23
void uputs (char *s);      //String/Zeichen/Daten in ring-puffer
24
void uinit (void);        //usart initial 8n1,tx enable
25
void adcinit(void);        //adc an ,channel adc0 ,AVcc, single conversion
26
char* getAdc(void);        //adc wert auslesen usw.. rückgabe wert als string
27
void waitms (uint16_t);
28

29
volatile char buffer[BUFFER_LEN];    // Ring-Puffer für zu sendende Daten
30
volatile uint8_t writePointer=0;      //schreib zeiger
31
volatile uint8_t readPointer=0;      //lese zeiger
32
volatile uint8_t a=0;            //adc fertig flag
33

34
int main(){
35
  
36
  sei();          //interupts an
37
  DDRD&=~(1<<PD2);    //PD2 ausgang
38
  PORTD=(1<<PD2);    //PD2 an
39
  uinit();          //uart initial (8n1, usw.)
40
  adcinit();        //adc initial mit interrupt, single conversation, mux=adc0  
41
    
42
  uputs("Booting... \n");
43

44
  _delay_ms(10);    
45
  
46
  ADCSRA |=(1<<ADSC);  //wandlung nach init = dump wandlung
47

48
  while (1){      
49
    
50
    if(a==1){              //adc wandlung fertig
51
      uputs(getAdc());        //daten ausgeben/holen      
52
      ADCSRA |= (1<<ADSC);       //neue ADC-Wandlung 
53
      a=0;
54
      }  
55
    
56
    _delay_ms(10);      
57
    //waitms(100);
58
      
59

60
    uputs("bla..");  
61
      
62
  }
63
}
64

65
char* getAdc(void){    //adc wert
66

67
  char *tmp;        //für umwandlung double to string (dtostrf)  
68
  uint16_t adc=0;    //adc wert
69

70
  adc = ADCL;       
71
  adc += (ADCH<<8);         //adc daten register auslesen  L and H            
72
  dtostrf(adc*0.004883,3,3,tmp);  //umwandlung der daten (umrechnugn in volt= (5/1024)*adc)          
73
  return tmp;//dtostrf(adc*0.004883,3,3,NULL);//tmp;
74
}
75

76

77
ISR(ADC_vect){                  // ADC wandlung fertig
78
  a=1;                //wandlung fertig flag
79
}
80

81

82
ISR(USART_UDRE_vect){             // UDR ist leer ISR 
83
  if(writePointer!=readPointer){    //daten in puffer
84
    UDR=buffer[readPointer];      //daten in uart hw puffer schreiben
85
    readPointer++;    
86
    if(readPointer==BUFFER_LEN)readPointer=0;          
87
    }
88

89
  else  UCSRB |= (0<<UDRIE);        // ISR aus, keine daten in puffer    
90
}
91

92

93
uint8_t bufferCeck(void){          //checkt platz in buffer
94

95
  if((readPointer-writePointer)>0){      //noch platz
96
    return (readPointer-writePointer);    //der abstand
97
    }
98
  else return 1;                    //alle anderen zustände
99

100
}
101

102

103
void uputc(unsigned char c){        // Zeichen in ring-puffer --auch ein zeichen nur über uputs !!
104
  
105
    buffer[writePointer]=c;
106
    writePointer++;
107
    if(writePointer==BUFFER_LEN)writePointer=0;
108
  
109
}
110

111

112
void uputs (char *s){            //String/Zeichen in ring-puffer
113
  if(bufferCeck()>=1){            //prüft ob noch plazt
114
    while (*s){            // so lange *s != '\0'        
115
       uputc(*s);
116
        s++;
117
        }
118
    UCSRB |= (1<<UDRIE);      //schaltet uart-hw puffer flag ein
119
    }
120
}
121

122

123
void adcinit(void){              //adc an ,channel adc0 ,AVcc, single conversion
124
  ADMUX |= (0<<REFS1)|(1<<REFS0)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0);//ref AVcc,mux0000=adc0
125
  ADCSRA |=(1<<ADEN)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(0<<ADPS0);//adc an,interupt an,single conversion,div factor 64
126
}
127

128

129
void uinit (void){              //init usart Tx, 8n1 ,UDRE interupt enable
130
  
131
   UCSRC |= (1<<URSEL)|(3<<UCSZ0)|(0<<USBS);    // URSEL = 1 dann wird UCSRC benutzt sonst UBRRH ; UCSZ0=data register- 8bit; USBS=1 stop bit 
132

133
   UBRRH = UBRR_VAL >> 8;                // baud rate hi & lo
134
  UBRRL=UBRR_VAL & 0xFF;
135

136
  UCSRB |= (1<<TXEN);//|(1<<UDRIE);            // UART TX einschalten,  data register empty interupt enable
137
}
138

139
void waitms (uint16_t ms){        //waitms bis max 65535 ms wegen uint16_t
140
  for(ms;ms>0;ms--)_delay_ms(delay1ms);
141
}


äh gut ok. Man kann nur Dateianhänge machen wenn man neue Posts macht, 
mit Bearbeiten geht das nicht...
Angehängte Dateien:
#788996
Lesenswert?

@ Daniel Rau (zerrome)

>Also eigentlich sollte der Code doch funktionieren oder?

Ein paar Anmerkungen.

sei() als ersten Befehl in main ist sehr gewagt. ZUERST muss man alles 
initialisieren, sei() kammt dann am Schluss! Kurz vor der Endlosschleife 
von main(). Ausserdem bin ich nicht ganz sicher, wie der Compiler das 
statement ms interpretiert. Die Variable Warteschleife im Tutorila ist 
anders. Nämlich so.

1
void waitms (uint16_t ms){        //waitms bis max 65535 ms wegen uint16_t
2
  for(; ms>0; ms--)_delay_ms(delay1ms);
3
  //  KEINE zusätzliche Initialisierung von ms
4
}

MFG
Falk
Moderator Persönliche Seite #789008
Lesenswert?

Falk Brunner wrote:

> Ausserdem bin ich nicht ganz sicher, wie der Compiler das
> statement ms interpretiert.

Ich würde vermuten, dass er beim Einschalten aller Warnungen etwas
von sich gibt wie "Statement has no effect".  Stört aber auch nicht.

Daniel, wenn du schreibst, dass _delay_ms(10) funktioniert: hast du
die Zeit dabei auch nachgemessen?  Oder könnten das auch 160 ms
sein?

Ich fürchte einfach mal, dein AVR läuft noch mit 1 MHz und du hast
jeweils schon vor Ablauf von 16 Sekunden (ist eine verdammt lange
Zeit, wenn man auf etwas wartet ;-) kalte Füße bekommen und gesagt:
,,Geht nicht!''.
OP #789268
Lesenswert?

Hallo,
1.
also der AVR läuft auf jeden fall mit externem 16mhz Quarz, die fuses 
sind so gesetzt und der uart funktioniert, was für mich eigentlich auch 
ein Beweis dafür ist, dass die 16 mhz eingestellt sind (die Baudrate 
errechnet sich ja anhand des Taktes).

2.
nein hab die 10 ms nicht gemessen, da ich kein Oszi oder Frequenz-messer 
habe, sind mehr gefühlte 10 ms (160ms wären ja schon weniger als 10 hz 
das könnte man mit ner led sogar sehen, was eideutig nicht so ist)

3.
sei() an anderer Stelle macht schon mehr sinn,
wenn man mal drüber nachdenkt :)

4.
hab die waitms schleife mal auf
1
for(; wms>0; wms--)_delay_ms(delay1ms);
geändert.
Wenn ich jetzt in der Eendlosschleife der main
1
waitms(15);
schreibe, macht der Controller einen totalen reset,
was sehr seltsam ist !

Bin ziemlich ratlos!
OP #789276
Lesenswert?

Hab grade was rumprobiert,
wenn ich in der waitms Schleife die übergebene Variable nochmal quasi 
lokal in der Funktion speichere macht der Controller keinen reset, 
kleiner Vortschritt...
1
void waitms (uint16_t ms){    
2
  uint16_t mis=ms;
3
  for(;mis>0;mis--)_delay_ms(delay1ms);
4
}
OP #789293
Lesenswert?

Hab mich da an eine lang vergangene c Programmier Stunde erinnert, es 
ist wegen was auch immer, wohl ein Unterschied ob die Variable übergeben 
wird oder übergeben wird und nochmal gespeichert (außer dem 
verschwendeten Platz)...

Kann man irgendwie rausfinden wie voll der Ram ist? Oder muss ich 
variablen zählen?
Moderator Persönliche Seite #789304
Lesenswert?

Daniel Rau wrote:

> Hab mich da an eine lang vergangene c Programmier Stunde erinnert, es
> ist wegen was auch immer, wohl ein Unterschied ob die Variable übergeben
> wird oder übergeben wird und nochmal gespeichert (außer dem
> verschwendeten Platz)...

Nein, ein Funktionsparameter ist effektiv eine lokale Variable
innerhalb der Funktion.  Hier der Vergleich:
1
#include <stdint.h>
2

3
#define F_CPU 16000000UL
4
#include <util/delay.h>
5

6
void
7
delay_ms(uint16_t ms) {
8
        while (--ms) _delay_ms(1);
9
}

Generierter Code:
1
.global delay_ms
2
        .type   delay_ms, @function
3
delay_ms:
4
/* prologue: frame size=0 */
5
/* prologue end (size=0) */
6
        movw r18,r24
7
        rjmp .L2
8
.L3:
9
        ldi r24,lo8(4000)
10
        ldi r25,hi8(4000)
11
/* #APP */
12
        1: sbiw r24,1
13
        brne 1b
14
/* #NOAPP */
15
.L2:
16
        subi r18,lo8(-(-1))
17
        sbci r19,hi8(-(-1))
18
        brne .L3
19
/* epilogue: frame size=0 */
20
        ret
21
/* epilogue end (size=1) */
22
/* function delay_ms size 14 (13) */

Und mit:
1
#include <stdint.h>
2

3
#define F_CPU 16000000UL
4
#include <util/delay.h>
5

6
void
7
delay_ms(uint16_t ms) {
8
        uint16_t copy = ms;
9
        while (--copy) _delay_ms(1);
10
}
ergibt sich:
1
.global delay_ms
2
        .type   delay_ms, @function
3
delay_ms:
4
/* prologue: frame size=0 */
5
/* prologue end (size=0) */
6
        movw r18,r24
7
        rjmp .L2
8
.L3:
9
        ldi r24,lo8(4000)
10
        ldi r25,hi8(4000)
11
/* #APP */
12
        1: sbiw r24,1
13
        brne 1b
14
/* #NOAPP */
15
.L2:
16
        subi r18,lo8(-(-1))
17
        sbci r19,hi8(-(-1))
18
        brne .L3
19
/* epilogue: frame size=0 */
20
        ret
21
/* epilogue end (size=1) */
22
/* function delay_ms size 14 (13) */

...auffällig dasselbe.

> Kann man irgendwie rausfinden wie voll der Ram ist?

avr-size

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren