Forum: Mikrocontroller und Digitale Elektronik AVR, progmenu array mit strings und unsigned char: will nicht so recht !


von Ralph S. (jjflash)


Lesenswert?

Ich habe mal eine wirklich dumme Frage und eigentlich sogar sehr 
peinlich, aber da peinliches immer nur für das Jahr gilt in dem man 
peinlich war und danach alles vergessen werde ichdas für den Rest des 
Jahres verkraften.

Ich wollte mir Klimmzüge über struct ersparen und habe folgendes 
Problem. Ich möchte bei einem AVR in einem Array zusaetzlich zu einem 
String noch ein einzelnes unsigned char integriert haben und kann das 
nicht mischen. Von daher suche ich einen praktikablen Weg.

Folgendes funktioniert logischerweise:
1
const uint8_t mnem[][10] PROGMEM =
2
{
3
  {  4,'m','v','i',' ','a',',','?',0 },
4
  {  "cmpg a,?" },
5
  {   "cdis"}
6
};

Nun möchte ich natürlich nicht einen String schön in Einzelchars 
eingeben, sondern als String.

Wie kann man das (was nicht funktioniert) elegant lösen?
1
const uint8_t mnem2[][10] PROGMEM =
2
{
3
  {  4,"mvi a,?" },
4
  {  "cmpg a,?" },
5
  {   "cdis"}
6
};

Hier meckert der Compiler mit:
1
cp1_term.c:37:3: error: initializer element is not computable at load time
2
cp1_term.c:37:3: error: (near initialization for 'mnem2[0][1]')

;-) und sagt mir nicht, dass der Fehler in Zeile 42 liegt, er liegt in 
Zeile 37

Einen guten Rutsch an alle

Beitrag #6532219 wurde von einem Moderator gelöscht.
von Ralph S. (jjflash)


Lesenswert?

... wenn man ganz alleine zu Hause sitzt ... und noch nicht mal vor die 
Haustüre darf, ist da eine schlechte Idee zu böllern. Im Übrigen böller 
ich seit Jahrzehnten nicht mehr

Beitrag #6532227 wurde von einem Moderator gelöscht.
von Ralph S. (jjflash)


Lesenswert?

In D ... und noch infektiös !

von fragender (Gast)


Lesenswert?

1
const uint8_t mnem[][10] PROGMEM =
2
{
3
  {  "\x04""mvi a,?" },
4
  {  "cmpg a,?" },
5
  {   "cdis"}
6
};
https://godbolt.org/z/1W9K3v

\x leitet ein Hex-String-Literal ein, einzelne Strings können einfach 
durch hintereinandersetzen verkettet werden.

Ansonsten nicht zu viel erwarten von der Trollarmee hier, schon gar 
keine sinnvollen Antworten.

Beitrag #6532263 wurde von einem Moderator gelöscht.
von Ralph S. (jjflash)


Lesenswert?

ich hatte Symptome (starke, jetzt noch leichte) ...

von Ralph S. (jjflash)


Lesenswert?

fragender schrieb:
> const uint8_t mnem[][10] PROGMEM =
> {
>   {  "\x04""mvi a,?" },
>   {  "cmpg a,?" },
>   {   "cdis"}
> };
> https://godbolt.org/z/1W9K3v
>
> \x leitet ein Hex-String-Literal ein, einzelne Strings können einfach
> durch hintereinandersetzen verkettet werden.
>
> Ansonsten nicht zu viel erwarten von der Trollarmee hier, schon gar
> keine sinnvollen Antworten.

boah, okay... vielen Dank (an den Kopf batsch). Das funktioniert. Haber 
jetzt aber schon die Programmstruktur geändert dahingehend, dass ich die 
Zahl mit in den String nehmen und beim Auslesen extrahiere.

Hmmm, ob ich noch einmal den Programmcode ändere ?

Beitrag #6532329 wurde von einem Moderator gelöscht.
von 2020 (Gast)


Lesenswert?

Ralph S. schrieb:
> {  4,'m','v','i',' ','a',',','?',0 },

Und 4 ist keine Variable, sondern eine Konstante?

Man könnte mit Macros arbeiten:
1
#define NUM 123
2
3
#define to_str1(x) #x
4
#define to_str(x) to_str1 (x)
5
6
char str[100] = { to_str (NUM) "hallo" };

und
1
4 + '0'

macht aus der (einstelligen) Zahl ihre ASCII-Darstellung. Das kann man 
dann in einem String ablegen.

von Veit D. (devil-elec)


Lesenswert?

Ralph S. schrieb:
>
1
> const uint8_t mnem2[][10] PROGMEM =
2
> {
3
>   {  4,"mvi a,?" },
4
>   {  "cmpg a,?" },
5
>   {   "cdis"}
6
> };
7
>

Du legst ein 2 dimensionales Array an in dem Daten fehlen. Das muss 
schief gehen. Deine Ausleseroutine macht bestimmt im RAM Nirwana weiter.
1
/*
2
  Arduino IDE 1.8.13
3
  avr-gcc 10.2.0
4
  Arduino Mega2560
5
  31.12.2020
6
  License: GNU GPLv3
7
*/
8
  
9
struct Struktur
10
{
11
  byte pin;
12
  char text[21];
13
};
14
15
Struktur daten[] = {
16
  {1, "mvi a,?"},
17
  {2, "cmpg a,?"},
18
  {3, '\0'},
19
  {4, "cdis"},
20
};
21
22
const byte ANZAHL = sizeof(daten) / sizeof(Struktur);
23
24
void setup()
25
{
26
  Serial.begin(115200);
27
  Serial.println("\nStart");
28
29
  // klassische Variante
30
  // for (byte i=0; i<ANZAHL; i++) 
31
32
  // for Range-Based Variante
33
  for (auto &i : daten)
34
  {
35
      Serial.print(i.pin);
36
      Serial.print('\t');
37
      Serial.println(i.text);
38
  }
39
}
40
41
void loop()
42
{}

Ab dem neuen Jahr zeigste den kompletten Code!

von A. S. (Gast)


Lesenswert?

Ralph S. schrieb:
> Ich wollte mir Klimmzüge über struct ersparen

Koste es, was es wolle.

Ralph S. schrieb:
> Hmmm, ob ich noch einmal den Programmcode ändere ?

Zu es. Mit einem struct ist es sauber, kleiner, einfacher, wartbarer, 
lesbarer.

Heute siehst Du die 10 Zeilen mehr beim Typ und merkst nicht, wie Du 
Dich auf 30 oder mehr Zeilen verrenkst. Mit einem struct machen weitere 
Änderungen auf einmal Spaß, weil es immer besser wird. Am Ende ist der 
ganze Code nur halb so groß.

von Ralph S. (jjflash)


Lesenswert?

Veit D. schrieb:
> Du legst ein 2 dimensionales Array an in dem Daten fehlen. Das muss
> schief gehen. Deine Ausleseroutine macht bestimmt im RAM Nirwana weiter.

Das war ja mein Problem. Ein String ist ein "Array of Char" und die 4 
sollte ein weiteres Char sein (kein Ascii-Zeichen). Ich wußte einfach 
nicht mehr, dass das so geht:

{"\x04""Text"}

wie es

fragender schrieb:
> const uint8_t mnem[][10] PROGMEM =
> {
>   {  "\x04""mvi a,?" },
>   {  "cmpg a,?" },
>   {   "cdis"}
> };

gezeigt hat.

Eine Struktur hatte ich anderst gemacht gehabt, die auch funktioniert 
hat (und NICHT im Ram-Nirvarna gewütet hat).

Veit D. schrieb:
> struct Struktur
> {
>   byte pin;
>   char text[21];
> };
>
> Struktur daten[] = {
>   {1, "mvi a,?"},
>   {2, "cmpg a,?"},
>   {3, '\0'},
>   {4, "cdis"},
> };

Genau das was du da schreibst, wollte ich vermeiden, weil die Strings 
hier auch RAM belegen, ich das aber im Flash haben wollte und deshalb 
den Zusatz PROGMEM gebraucht hab. Mache ich das über die Struktur, wird 
das auslesen über read_pgm_byte noch witziger.

Wie gesagt war das oben die Lösung. Im Übrigen mache ich das nicht mit 
einem Arduino (verstehe ich nicht, warum man häufig annimmt, wenn ein 
AVR im Spiel ist, dass das ein Arduino-Sketch wird).

Hier gings ums grundsätzliche und von probiere ich solche Dinge auf der 
Console mit GCC (für PC) aus  und nicht auf dem Controller. Wenn sie 
dort funktionieren wirds an den Controller angepasst (bei STM32 brauche 
ich in der Regel keine oder kaum Anpassung, bei AVR kommt immer das 
"depperte" read_pgm ins Spiel).

Veit D. schrieb:
> Ab dem neuen Jahr zeigste den kompletten Code!

den zeige ich in der Regel immer. Hier ging es aber ums Array an sich 
(und das was die Lösung war hatte ich schon mal gewußt und schlicht 
wieder vergessen gehabt).

von Ralph S. (jjflash)


Lesenswert?

By the way:

Das hier funktioniert genau so, wie ich mir das zuvor vorgestellt hatte:
1
#define mnemanz   25
2
3
4
const uint8_t mnemset[mnemanz][13] PROGMEM =
5
{
6
  { "\xff""db ?"},
7
  { "\x01""hlt"},
8
  { "\x02""cdis"},
9
  { "\x03""cdel ?"},
10
  { "\x04""mvi a,?"},
11
  { "\x05""mov a,?"},
12
  { "\x06""mov ?,a"},
13
  { "\x13""mov a,@?"},
14
  { "\x14""mov @?,a"},
15
  { "\x07""add a,?"},
16
  { "\x08""sub a,?"},
17
  { "\x0a""cmpe a,?"},
18
  { "\x0c""cmpg a,?"},
19
  { "\x0d""cmpl a,?"},
20
  { "\x09""jmp ?"},
21
  { "\x0b""jz ?"},
22
  { "\x15""jmp @?"},
23
  { "\x0e""notb a"},
24
  { "\x0f""andb a,?"},
25
  { "\x10""inb p1,?"},
26
  { "\x10""in p1"},
27
  { "\x11""outb p1,?"},
28
  { "\x11""out p1"},
29
  { "\x12""outb p2,?"},
30
  { "\x12""out p2"}
31
};

Ohne die Auswertung anzuzeigen (die ist für das Array auch ohne Belang, 
im Flash ist jetzt vor dem eigentlichen String eben ein Byte abgelegt.

von Veit D. (devil-elec)


Lesenswert?

Ralph S. schrieb:
> Im Übrigen mache ich das nicht mit
> einem Arduino (verstehe ich nicht, warum man häufig annimmt, wenn ein
> AVR im Spiel ist, dass das ein Arduino-Sketch wird).

Deine Annahme ist falsch. Mir ist es egal in welcher Umgebung du 
programmierst. Ich habe für mich den Code in der Arduino IDE getestet. 
Geht meistens schneller und bequemer, gerade für solche Dinge. Versteife 
dich nicht darauf wer was in welcher Umgebung programmiert und zeigt. 
Der eigentliche Code ist entscheidend.

von Kuddel (Gast)


Lesenswert?

Ralph S. schrieb:
>
1
> const uint8_t mnemset[mnemanz][13] PROGMEM =
2
> {
3
> ..
4
>   { "\x12""out p2"}
5
> };
6
> 
7
>
>
> Ohne die Auswertung anzuzeigen (die ist für das Array auch ohne Belang,
> im Flash ist jetzt vor dem eigentlichen String eben ein Byte abgelegt.

Da werden jeweils 2 Bytes abgelegt. Dein Byte und ein \0, das ist ja 
auch nur ein normaler String.

von Einer K. (Gast)


Lesenswert?

Kuddel schrieb:
> Da werden jeweils 2 Bytes abgelegt. Dein Byte und ein \0, das ist ja
> auch nur ein normaler String.
Ich sehe da 7 Char, plus eine Null.


Völlig egal, ob man  { "\x12""out p2"} oder  { "\x12out p2"} schreibt.

Beitrag #6533532 wurde vom Autor gelöscht.
Beitrag #6533534 wurde vom Autor gelöscht.
Beitrag #6533536 wurde vom Autor gelöscht.
von Ralph S. (jjflash)


Lesenswert?

Arduino Fanboy D. schrieb:
> Ich sehe da 7 Char, plus eine Null.
>
> Völlig egal, ob man  { "\x12""out p2"} oder  { "\x12out p2"} schreibt.

Absolut korrekt, und ich habe die Strings ja auch im Stile von "\x04mvi
a,?" dann abgelegt.

Es ging ja genau darum, vor dem eigentlichen String, ein einzelnes Byte
(in meinem Falle den Opcode einer Mnemonic) abzulegen. Das ein String
ein abschließendes 0-Byte hat ist klar.

Veit D. schrieb:
> Ich habe für mich den Code in der Arduino IDE getestet.
> Geht meistens schneller und bequemer, gerade für solche Dinge. Versteife
> dich nicht darauf wer was in welcher Umgebung programmiert und zeigt.
> Der eigentliche Code ist entscheidend.

;-) oki, dann hatte ich das falsch verstanden. Ich denke jeder hat seine 
Umgebung, um etwas schnell auszuprobieren.

von Einer K. (Gast)


Lesenswert?

Ich stimme meinen Vorrednern zu!
Es ist falsch, einfach ein Byte vor den String zu dengeln, nur weil es 
bequemer ist.

Ich will nicht bezweifeln, dass es funktioniert.
Aber: Es ist die falsche Denke.

Gewöhnst du dich an die falsche Denke, wirst du noch weit häufiger 
solchen "Mist" konstruieren.

Ich prophezeie dir: Damit wirst du irgendwann auf die Nase fallen. Und 
die Leute, welche deinen Code warten müssen werden sich bitterlich bei 
dir beschweren.

Strukturen wurden nicht ohne Grund erfunden!
Eben um unterschiedliche Datentypen zusammenfassen zu können.

Ja, Auch dieses Beispiel nutzt Arduino Code, allerdings nur für die 
Ausgabe.
Ich hoffe, dass es dich nicht überfordert, den Kern da raus zu 
operieren.

----------

Code:
1
#include <Streaming.h>
2
3
struct Struktur
4
{
5
  byte pin;
6
  char text[21];
7
};
8
9
const Struktur daten[] PROGMEM= {
10
  {7,   "ggcdis"},
11
  {5,   "mvi a,?"},
12
  {9,   "cmpg a,?"},
13
  {113, '\0'},
14
  {42,  "cdis"},
15
  {16,  "ffcdis"},
16
  {6,   "ggcdis"},
17
};
18
19
void setup() 
20
{
21
  char buffer[50];
22
  Serial.begin(9600);
23
  //Serial << "Start: "<< __FILE__ << endl;
24
  
25
  for(const Struktur &d:daten)
26
  {
27
    byte pin =  pgm_read_byte(&d.pin);
28
    strcpy_P(buffer,d.text); 
29
    Serial << pin << ": " << buffer << endl;
30
  }
31
}
32
33
void loop(){}

--------

Ausgabe:
1
7: ggcdis
2
5: mvi a,?
3
9: cmpg a,?
4
113: 
5
42: cdis
6
16: ffcdis
7
6: ggcdis

von Ralph S. (jjflash)


Lesenswert?

Arduino Fanboy D. schrieb:
> struct Struktur
> {
>   byte pin;
>   char text[21];
> };
>
> const Struktur daten[] PROGMEM= {
>   {7,   "ggcdis"},
>   {5,   "mvi a,?"},
>   {9,   "cmpg a,?"},
>   {113, '\0'},
>   {42,  "cdis"},
>   {16,  "ffcdis"},
>   {6,   "ggcdis"},
> };

das ist das, was ich ursprünglich gewollt hatte und weswegen auch immer 
nicht gleich geklappt hatte. Aus dem Grund hatte ich das prakmatisch 
machen wollen. Das hier ist natürlich die korrekte Art und Weise....

Nichts desto trotz werd ich mich mal für n paar Tage oder so aus dem 
Forum zurückziehen, Urlaub ist eh rum (und seit gestern darf ich auch 
wieder vor die Tür)

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.