Forum: Compiler & IDEs Probleme mit _delay_us() bei #define Wert und int_8t Wert


von Ben S. (patersigmund)


Lesenswert?

Hallo allerseits!

Ich hab ein Problem, und zwar bin ich dran eine PWM per Software zu 
lösen. Es funktioniert soweit auch ganz gut. Nur sobald ich versuche die 
Zeiten per Taster zu regeln streikt er.
Achso hier die Fehlerbeschreibung:
Wenn ich die Argumente der delays per Hand setze ist die LED wirklich 
auf einer sehr niedrigen Leuchtstufe. Wenn ich aber dann das Argument 
durch eine Funktion in i ausdrücke, leuchtet die LED bei weitem heller.

Wobei sich mir dann die Frage stellt obs einen Unterschied zwischen 
einem
1
#define WERT
und einem
1
uint16_t WERT
gibt

Vielleicht erkennt ja jemand meinen Fehler.

Gruß,
  me


Hier dann der C-Code.
Kurze Einleitung:
Das debounce hab ich mir aus dem Forum kopiert. Da ich mich darum erst 
später kümmern wollt.
Am Anfang die viele defines sind nur dafür da, damit ich das Programm 
nachher einfach auf die andere Hardware portieren kann.
Der Hauptteol befindet sich eigentlich ganz zu Schluss im else Teil.
1
#include <avr/io.h>
2
#include <stdint.h>
3
4
#ifndef F_CPU
5
#define F_CPU 800000UL
6
#endif
7
#include <util/delay.h>
8
9
#define DDR     DDRD
10
#define PORT     PORTD
11
#define PIN     PIND
12
#define TASTER1   PD2
13
#define TASTER2   PD3
14
#define LED1     PD5
15
#define LED2     PD6
16
#define TRIGGER    100
17
#define TIME    2500
18
#define STEP    1
19
#define MAX    (TIME/STEP)
20
21
#define debounce(port, pin)          \
22
({                \
23
  static uint8_t flag = 0;        \
24
  uint8_t i = 0;                  \
25
                              \
26
    if(flag){            \
27
     for(;;){          \
28
       if(!(port & 1<<pin)){      \
29
          i = 0;        \
30
          break;        \
31
            }               \
32
            _delay_us(TRIGGER);       \
33
         if(--i == 0){        \
34
          flag = 0;      \
35
          i = 0;        \
36
          break;        \
37
          }          \
38
        }                  \
39
    }              \
40
  else{              \
41
        for(;;){          \
42
            if((port & 1<<pin)){      \
43
        i = 0;        \
44
          break;        \
45
            }          \
46
            _delay_us(TRIGGER);      \
47
            if(--i == 0){        \
48
          flag = 1;      \
49
          i = 1;        \
50
          break;        \
51
            }          \
52
        }            \
53
    }              \
54
    i;              \
55
})
56
57
int main(){
58
  
59
  DDR |= (1<<LED1) | (1<<LED2);
60
  DDRA |= 0xff;
61
  PORTA &= 0x00;
62
  uint16_t i = 1;
63
  
64
  for(;;){
65
    
66
    if(debounce(PIN, TASTER1)){
67
      if(i < MAX){
68
        i++;
69
      }
70
      else{
71
        i = MAX;
72
      }
73
    }
74
75
    if(debounce(PIN, TASTER2)){
76
      if(i > 0){
77
        i--;
78
      }
79
      else{
80
        i = 0;
81
      }
82
    }  
83
84
    PORTA = i;  
85
86
    if(i == MAX){
87
      PORT |= (1<<LED1);
88
    }
89
    else if(i == 0){
90
      PORT &= ~(1<<LED1);
91
    }
92
    else{
93
      PORT |= (1<<LED1);
94
      _delay_us(1); // Arg. sollte sein: i
95
      PORT &= ~(1<<LED1);
96
      _delay_us(2500); // Arg. sollte sein: 2500-i
97
    }
98
  }
99
100
  return 0;
101
}

von Rolf Magnus (Gast)


Lesenswert?

Benjamin Schwilling schrieb:
> Wobei sich mir dann die Frage stellt obs einen Unterschied zwischen
> einem#define WERT
> und einemuint16_t WERT
> gibt
>
> Vielleicht erkennt ja jemand meinen Fehler.

Doku nicht gelesen:

"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."
( http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html )

von Jannis C. (kabelwurm)


Lesenswert?

Hallo,
versuch mal einem Zustand einen Wert zuzuweisen. Hoppla geht nicht.
->mit define kann man einen Zustand definieren und diesen logisch 
verwenden
->mit uint definiert man einen Vorzeichenlosen Integer.
Es ist sinvoll die bein Typen unterschiedlich zu Schreiben, da es sonst 
Probleme geben wird.
Bsp Integer klein, Zustände groß.
Gruß Jannis

von Ben S. (patersigmund)


Lesenswert?

Ok ich seh schon, da muss ich mir dann doch was anderes einfallen 
lassen. Und einm Internet mich ein wenig über Timer schlau machen.

Danke für die Antworten!

von Uwe (de0508)


Lesenswert?

Hallo,

habe gerade noch diese Frage entdeckt :
1
 F_CPU 800000UL
 == 800khz ?

ist das Absicht ?

von Ben S. (patersigmund)


Lesenswert?

Ganz im Ernst. Ich hab keine Ahnung. Ich weiss zwar, dass die util/delay 
den F_CPU Wert brauch, aber in wie weit sich eine Veränderung dabei 
auswirkt weiss ich noch nicht so wirklich. ABER hab ja erst mit der µC 
Programmierung angefangen, von daher kommt das Wissen mit der Zeit.... 
hoffentlich ^^

BTW: Mir ist gestern noch ein Lösungsweg eingefallen. Ich hab einfach 
das Argument des _delay_us() auf 1 gesetzt und dieses dann in eine for() 
Schleife versteckt. Geht soweit eigentlich ganz schön.

von Rolf Magnus (Gast)


Lesenswert?

Benjamin Schwilling schrieb:
> Ganz im Ernst. Ich hab keine Ahnung. Ich weiss zwar, dass die util/delay
> den F_CPU Wert brauch, aber in wie weit sich eine Veränderung dabei
> auswirkt weiss ich noch nicht so wirklich.

delay_us macht ja an sich nichts weiter als eine Warteschleife, die n 
mal wartet. Daraus ergibt sich eine Wartezeit von n * x Taktzyklen, 
wobei x die Anzahl an Zyklen pro Schleifendurchlauf ist. Wenn du aber 
eine Zeit in Mikro- oder  Millisekunden warten willst, mußt du daraus 
erstmal die Anzahl an nötigen Schleifendurchläufen berechnen, und dazu 
wird natürlich die Taktfrequenz des Prozessors benötigt.
Wenn du da nun einen um Faktor 10 zu niedrigen Wert angibst, wird die 
Wartezeit auch nur ein Zehntel der angegebenen Dauer sein.

> BTW: Mir ist gestern noch ein Lösungsweg eingefallen. Ich hab einfach
> das Argument des _delay_us() auf 1 gesetzt und dieses dann in eine for()
> Schleife versteckt. Geht soweit eigentlich ganz schön.

Das ist auch das übliche Vorgehen, wenn man eine variable Anzahl von 
Mikro- oder Millisekunden warten will. So wie ich es verstehe, brauchst 
du aber nur zwei Wartezeiten, deren Verhältnis du angeben kannst, und 
die Dauer in Mikrosekunden ist eigentlich nicht so wichtig. Dann kannst 
du auch die Basis-Funktionen verwenden (Siehe avr-libc-Doku 
"util/delay_base.h"). Denen kannst du auch Variablen übergeben, dafür 
gibst du die Wartezeit eben nicht in Mikrosekunden, sondern je nach 
Funktion in Vielfachen von 3 oder 4 Taktzyklen an.

von Ben S. (patersigmund)


Lesenswert?

Danke für den Hinweis mit der delay_basic.h. Denn das _delay_loop 
arbeitet definitiv schöner. Vorallem kommt es ganz ohne Restflackern 
aus.

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.