Problem mit Funktion

OP #7866053
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

Moderator (Firma: Titel) Persönliche Seite #7866063
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.

OP #7866066
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

#7866082
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.

(Firma: Gast) #7866085
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

Persönliche Seite #7866089
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

Persönliche Seite #7866107
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
}
#7866109
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.

#7866138
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.

(Firma: Gast) #7866153
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.
OP #7866221
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?

#7866463
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

Persönliche Seite #7866696
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).

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