Forum: Mikrocontroller und Digitale Elektronik Problem mit Funktion


von Hendrik (rermtoe8)


Lesenswert?

Hallo,
ich habe hier ein Problem, wo ich einfach nicht weiterkomme. Im Netz 
konnte ich bislang keine Lösung finden.
Ich habe eine Arduino-Library (LedControl) für die Ansteuerung des 
MAX7219-ICs für die Verwendung in C mit Microchip Studio (µC: 
ATmega88PA) umgeschrieben. Jetzt habe ich eine Funktion geschrieben, die 
Daten aus einem 2D-Array auf einer 8x8 LED-Matrix in einer Dauerschlaufe 
wiedergeben soll. Die Funktionsparameter sind das Zeit-Intervall , der 
Start und der Endpunkt der Durchlaufs. Allerdings bekomme ich beim 
kompilieren die Fehlermeldung "initializer element is not constant" in 
Bezug auf static uint8_t x = start;
Der selbe Code lässt sich in der Arduino-IDE (C++) allerdings 
anstandslos ausführen.
Wie kann ich der Variable x jetzt den Wert von start (in diesem Fall 0) 
zuweisen?

hier der Code:
1
// 2D-Array
2
const uint8_t squares[5][8] PROGMEM = {
3
  {0b11111111,0b10000001,0b10000001,0b10000001,0b10000001,0b10000001,0b10000001,0b11111111},
4
  {0000000000,0b01111110,0b01000010,0b01000010,0b01000010,0b01000010,0b01111110,0b00000000},
5
  {0000000000,0b00000000,0b00111100,0b00100100,0b00100100,0b00111100,0b00000000,0b00000000},
6
  {0000000000,0b00000000,0b00000000,0b00011000,0b00011000,0b00000000,0b00000000,0b00000000},    
7
  {0000000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000},      
8
};
9
10
// Funktion
11
void display_frames(uint16_t interval, uint8_t start, uint8_t end)
12
{
13
        static uint8_t x = start;  
14
  static uint32_t previous_ms = 0;
15
    
16
  if (millis() - previous_millis >= interval)
17
  {
18
    previous_millis += interval;
19
    
20
    for (uint8_t i = 0; i < 8; i++)
21
    {
22
      set_row(0,i,pgm_read_byte_near(&squares[x][i]));
23
    }
24
        x++;
25
        if (x == end)
26
      x = start;
27
  }
28
}
1
// Funktionsaufruf
2
display_frames(500, 0, 5);

Vielen Dank schonmal für eure Hilfe

von Thomas W. (goaty)


Lesenswert?

static weglassen ?

von Obelix X. (obelix)


Lesenswert?

Schau dir mal "static" an, was das macht. So macht das keinen Sinn.

von Oliver S. (oliverso)


Lesenswert?

C++ ist halt nicht C.

Lösen lässt sich das allerdings relativ einfach:
1
    static uint8_t x;
2
    x = start;

Warum x überhaupt static sind muß, darfst du mit dir selber diskutieren.

Oliver

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


Lesenswert?

Mal von der Sache mit dem static abgesehen.

Hendrik schrieb:
1
  x = start;  
2
  :
3
      x++;
4
      if (x == end)
5
          x = start;
6
 :
Ich habe ein potentielles Problem gefunden: was, wenn einer (aus welchen 
Gründen auch immer) end kleiner angibt als start? Oder start mit 
dem selben Wert wie end übergeben wird?

Abhilfe: ich würde da einfach auf *>=* vergleichen.

von Hendrik (rermtoe8)


Lesenswert?

> C++ ist halt nicht C.
>
> Lösen lässt sich das allerdings relativ einfach:    static uint8_t x;
>     x = start;
>
> Warum x überhaupt static sind muß, darfst du mit dir selber diskutieren.

static , da ich die variable nur in der funktion gültig sein soll (nicht 
global)

x = start funktioniert leider nicht

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


Lesenswert?

Hendrik schrieb:
> x = start funktioniert leider nicht
Dann ist der Compiler kaputt.

Ein paar Tipps zur brauchbaren Fehleranalyse:
Was funktioniert nicht?
Mit welchem Programm?
Was erwartest du und was passiert stattdessen?
Wie stellst du das fest?

von Hendrik (rermtoe8)


Lesenswert?

also ohne static bleibt der zähler bei 0 stehen. was das keyword static 
genau macht, habe ich ehrlich gesagt noch nicht zu 100% begriffen, aber 
hauptsächlich benutzte ich es, um globale variablen zu vermeiden

von Hendrik (rermtoe8)


Lesenswert?

> Ich habe ein potentielles Problem gefunden: was, wenn einer (aus welchen
> Gründen auch immer) end kleiner angibt als start? Oder start mit
> dem selben Wert wie end übergeben wird?
>
> Abhilfe: ich würde da einfach auf *>=* vergleichen.

danke! werde ich berücksichtigen

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Hendrik schrieb:
> static , da ich die variable nur in der funktion gültig sein soll (nicht
> global)
Pure Bequemlichkeit!

Hendrik schrieb:
> x = start funktioniert leider nicht

Da fehlt das Semikolon!

von Udo S. (urschmitt)


Lesenswert?

Hendrik schrieb:
> was das keyword static
> genau macht, habe ich ehrlich gesagt noch nicht zu 100% begriffen, aber
> hauptsächlich benutzte ich es, um globale variablen zu vermeiden

Es ist aber genau umgekehrt
https://stackoverflow.com/questions/5033627/static-variable-inside-of-a-function-in-c

Wenn du eine Variable in einer Funktion als "static" deklarierst, dann 
wird sie global angelegt und nicht nur temporär auf dem Stack.
Der eigentliche Sinn ist, dass man sich damit Dinge zwischen 
Funktionsaufrufen merken kann.

Da solche Variablen nur einmal initialisiert werden, meckert der 
Compiler auch, weil du in deinem Code versuchst sie jedes Mal mit dem 
übergebenen Wert zu initialisieren.

Nachtrag: bekanntes Beispiel für die Verwendung von statischen Variablen 
ist strtok() inclusive allen Nachteilen.

: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Hendrik schrieb:
> also ohne static bleibt der zähler bei 0 stehen. was das keyword static
> genau macht, habe ich ehrlich gesagt noch nicht zu 100% begriffen, aber
> hauptsächlich benutzte ich es, um globale variablen zu vermeiden

Leider der falsche Grund.

Punkt:
Eine Funktion hat sich bei gleichen Parametern immer gleich zu 
verhalten.
Das tut sie nicht, wenn sie statische oder globale Variablen nutzt.
Stichwort: Wiedereintrittsfähigkeit.

Gilt auch für Klassen und ihre Methoden. Dort macht es auch gerne die 
Vererbung kaputt.

Die Situation ist meist/immer vermeidbar.
Wiederverwendung statt Wegwerf Funktionen/Klassen/Methoden

: Bearbeitet durch User
von Uwe B. (boerge) Benutzerseite


Lesenswert?

wie wäre es mit dieser abgeänderten Funktion (ohne sie jetzt durch einen 
Compiler gejagt zu haben):
1
// Funktion
2
void display_frames(uint16_t interval, uint8_t start, uint8_t end)
3
{
4
  static uint8_t x = 0;  
5
  static uint32_t previous_ms = 0;
6
    
7
  if (millis() - previous_millis >= interval)
8
  {
9
    previous_millis += interval;
10
    
11
    for (uint8_t i = 0; i < 8; i++)
12
    {
13
      set_row(0,i,pgm_read_byte_near(&squares[x + start][i]));
14
    }
15
    x++;
16
    if ((x + start) >= end) 
17
      x = 0;
18
  }
19
}

Grüße Uwe

von Hendrik (rermtoe8)


Lesenswert?

danke erstmal an alle für die Lösungsvorschläge.

Uwe B. schrieb:
> wie wäre es mit dieser abgeänderten Funktion (ohne sie jetzt durch einen
> Compiler gejagt zu haben):

ich werde den Code nacher ausprobieren . vielen dank schonmal

von Uwe B. (boerge) Benutzerseite


Lesenswert?

...einen habe ich noch: die Geschichte, ob das nächste Intervall dran 
ist, würde ich auch anders lösen, also so ungefähr insgesamt:
1
// Funktion
2
void display_frames(uint16_t interval, uint8_t start, uint8_t end)
3
{
4
  static uint8_t x = 0;  
5
  static uint32_t previous_ms = 0;
6
    
7
  if ((previous_ms + interval) <= millis())
8
  {
9
    previous_ms = millis();
10
    
11
    for (uint8_t i = 0; i < 8; i++)
12
    {
13
      set_row(0,i,pgm_read_byte_near(&squares[x + start][i]));
14
    }
15
    x++;
16
    if ((x + start) >= end) x = 0;
17
  }
18
}

von Obelix X. (obelix)


Lesenswert?

Hendrik schrieb:
> was das keyword static
> genau macht, habe ich ehrlich gesagt noch nicht zu 100% begriffen

teste mal dies :
1
#include <stdio.h>
2
#include <stdlib.h>
3
4
int test1()
5
{
6
    static int x=0;
7
    x++;
8
    return x;
9
}
10
11
int test2()
12
{
13
    int x=0;
14
    x++;
15
    return x;
16
}
17
18
19
int main(int argc, char *argv[]) {
20
    printf("Hallo, Welt!\n");
21
22
    printf("x = %d\n",test1());
23
    printf("x = %d\n",test1());
24
25
    printf("x = %d\n",test2());
26
    printf("x = %d\n",test2());
27
28
    return 0;
29
}

PS: x ist in beiden test-Funktionen nur lokal.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Hendrik schrieb:
> static , da ich die variable nur in der funktion gültig sein soll (nicht
> global)

Dein C-Buch ist kaputt.

Oliver

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


Lesenswert?

Uwe B. schrieb:
> if ((previous_ms + interval) <= millis())
Das klassische Überlaufproblem. Es muss unbedingt so heißen:

if (millis() - previous_ms >= interval)

Nur dann rechnet sich mit der Unsigned Integer Arithmetik das 
Überlaufproblem automatisch heraus.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Oliver S. schrieb:
> C-Buch ist kaputt

C++, aber auch kaputt.

von Udo S. (urschmitt)


Lesenswert?

Uwe B. schrieb:
> ...einen habe ich noch: die Geschichte, ob das nächste Intervall dran
> ist, würde ich auch anders lösen, also so ungefähr insgesamt:

Eigentlich würde ich komplett darauf verzichten innere static Variablen 
zu benutzen.
Statt dessen würde ich eher eine Struktur mit allen notwendigen 
Zustandsvariablen deklarieren, die weiter außen (z.B. im main) definiert 
und initialisiert wird, und einen Zeiger auf die Struktur der Funktion 
mitgeben.

: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Udo S. schrieb:
> Statt dessen würde ich eher eine Struktur mit allen notwendigen
> Zustandsvariablen deklarieren, die weiter außen (z.B. im main) definiert
> und initialisiert wird, und einen Zeiger auf die Struktur der Funktion
> mitgeben.

Im Grunde richtig!
Nur:
1. in Arduino gibts eher setup() und loop()
2. donnert dir das den Stackbereich voll. Also auf heap_end(?) achten.

von Udo S. (urschmitt)


Lesenswert?

Arduino F. schrieb:
> . in Arduino gibts eher setup() und loop()

stimmt

Arduino F. schrieb:
> donnert dir das den Stackbereich voll.

Wir reden im konkreten Fall von einem uint8 und einem uint32.
Statisch verbraucht der genauso Platz im RAM.
Das einzige was man spart ist der Zeiger der auf dem Stack übergeben 
wird.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Udo S. schrieb:
> Wir reden im konkreten Fall von einem uint8 und einem uint32.

Die Begründung des TO liest sich so, als wird static aus Prinzip 
verwendet.

Dabei gilt:
> Wer mal kapiert hat, wie ein Hammer funktioniert,
> für den sieht die ganze Welt plötzlich wie ein Nagel aus.

von Hendrik (rermtoe8)


Lesenswert?

Uwe B. schrieb:
> wie wäre es mit dieser abgeänderten Funktion (ohne sie jetzt durch einen
> Compiler gejagt zu haben):
>
1
> // Funktion
2
> void display_frames(uint16_t interval, uint8_t start, uint8_t end)
3
> {
4
>   static uint8_t x = 0;
5
>   static uint32_t previous_ms = 0;
6
> 
7
>   if (millis() - previous_millis >= interval)
8
>   {
9
>     previous_millis += interval;
10
> 
11
>     for (uint8_t i = 0; i < 8; i++)
12
>     {
13
>       set_row(0,i,pgm_read_byte_near(&squares[x + start][i]));
14
>     }
15
>     x++;
16
>     if ((x + start) >= end)
17
>       x = 0;
18
>   }
19
> }
20
>
>

habe den code jetzt getestet und läuft perfekt . Besten Dank

Dass static einen Wert über das "Ableben" einer Funktion hinaus 
speichern kann, war mir schon bekannt, aber nicht, wie ich es sinnvoll 
einsetzen kann. Bin noch nicht allzu lange in der C-Programmierung 
unterwegs bzw. weiss noch nicht so genau, was unter der Haube vorsich 
geht, also was Wo , Wann, Wie, Warum gespeichtert wird. 
Stack,Heap,Pointer & Structs sind mir ein Begriff, allerdings habe ich 
mich damit noch nicht näher auseinandergesetzt.
Gibt´s da vielleicht ein halbwegs modernes Buch , was Ihr empfehlen 
könnt?

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?


von Oliver S. (oliverso)


Lesenswert?

Arduino F. schrieb:
> C++ nicht C

Hendrik schrieb:
> für die Verwendung in C mit Microchip Studio

Hier gehts tatsächlich um C.

Oliver

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Oliver S. schrieb:
> Hier gehts tatsächlich um C.

Du hast wahr.

Hendrik schrieb:
> Der selbe Code lässt sich in der Arduino-IDE (C++) allerdings
> anstandslos ausführen.
Naja...

von Obelix X. (obelix)


Lesenswert?

Hendrik schrieb:
> Dass static einen Wert über das "Ableben" einer Funktion hinaus
> speichern kann, war mir schon bekannt,

Warum verwendest du es dann?

Hendrik schrieb:
> aber nicht, wie ich es sinnvoll einsetzen kann.

Wirst du merken, wenn du es brauchst.

von Oliver S. (oliverso)


Lesenswert?

Obelix X. schrieb:
> Hendrik schrieb:
>> Dass static einen Wert über das "Ableben" einer Funktion hinaus
>> speichern kann, war mir schon bekannt,
>
> Warum verwendest du es dann?
> Hendrik schrieb:
>> aber nicht, wie ich es sinnvoll einsetzen kann.
>
> Wirst du merken, wenn du es brauchst.

Das braucht man dann, wenn man einen Wert über das "Ableben" einer 
Funktion hinaus speichern will ;)

Oliver

von Obelix X. (obelix)


Lesenswert?

Oliver S. schrieb:
> Das braucht man dann, wenn man einen Wert über das "Ableben" einer
> Funktion hinaus speichern will ;)

Das wissen doch alle sogar der TO wie er selbst schreibt, es aber 
trotzdem benutzt obwohl er es nicht braucht und sich dann über die 
Fehlermeldung wundert.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Udo S. schrieb:
> Wenn du eine Variable in einer Funktion als "static" deklarierst, dann
> wird sie global angelegt und nicht nur temporär auf dem Stack.

Solche Variablen sind nicht global, aber im Static Storage (anstatt 
Speicherklasse "automatic").

Dass sie nicht global sind erkennt man zum Beispiel auch daran, dass 
unterschiedliche Funktionen lokale (egal ob static oder nicht) Variablen 
gleichen Names haben können:
1
int func_count1 (void)
2
{
3
    static int count;
4
    return ++count;
5
}
6
7
int func_count2 (void)
8
{
9
    static int count;
10
    return ++count;
11
}
Die beiden "count" Variablen haben nichts miteinander zu tun, haben 
unterschiedliche Adressen, und sind außerhalb ihrer Funktionen nicht 
zugreifbar (es sei denn, ihre Adresse wird irgendwie verfügbar gemacht).

von Oliver S. (oliverso)


Lesenswert?

Obelix X. schrieb:
> Das wissen doch alle sogar der TO wie er selbst schreibt,

Er weiss, dass er weiss, dass er es nicht Weiss...

Hendrik schrieb:
> aber nicht, wie ich es sinnvoll einsetzen kann.

Oliver

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.