gcc array an mehrdimensionales array zuweisen

OP #7829746

Ich möchte per Pointer auf arrays zugreifen. Mehrere Arrays - also mehrere pointer in ein Pointer-array. Wie?

1
    u8  wr_bat_volt [] = { 0x00, 0x03, 0x02, 0x4B, 0x00, 0x01, 0xf4, 0x75 };
2
    u8* wr_bat_pow = { 0x00, 0x03, 0x02, 0x4E, 0x00, 0x01, 0xe4, 0x74 };
3
    u8* wr_soc = { 0x00, 0x03, 0x00, 0xD6, 0x00, 0x01, 0x64, 0x23 };
4

5
  
6
  volatile uint8_t *reg[] = { &wr_bat_volt, &wr_bat_pow, &wr_soc };
7
....
8

9

10
void main(void)
11
//
12
{
13

14
    wr_bat_pow[1]=0xff;//<==geht
15
       //*reg[1][1] = 0xFF; //<==geht nicht
16
    *reg[8*1+1]=6;//??

Danke für Nachsicht und Unterstützung

Gast

Lösung:

1
#include <stdint.h>
2

3
typedef uint8_t u8;
4

5
u8 wr_bat_volt[] = { 0x00, 0x03, 0x02, 0x4B, 0x00, 0x01, 0xf4, 0x75 };
6
u8 wr_bat_pow[] = { 0x00, 0x03, 0x02, 0x4E, 0x00, 0x01, 0xe4, 0x74 };
7
u8 wr_soc[] = { 0x00, 0x03, 0x00, 0xD6, 0x00, 0x01, 0x64, 0x23 };
8

9
u8* reg[] = {wr_bat_volt, wr_bat_pow, wr_soc};
10

11
int main()
12
{
13
    reg[0][0] = 0xFF; // overwrite first byte in wr_bat_volt
14
    reg[2][7] = 0xAA; // overwrite last byte in wr_soc
15
}

Tipp: Benutze die Qt Creator IDE. Sie zeigt neben den fehlerhaften Zeilen nützliche Hilfestellungen an. Sie hilft auch, Fehler zu vermeiden, die der Compiler nicht melden würde.

Du solltest vielleicht wissen, dass die Namen der Arrays (hier: wr_bat_volt, wr_bat_pow, wr_soc) bereits Zeiger sind. Deswegen sind die beiden folgenden Funktionen praktisch identisch:

1
void function1(u8* myArray)
2
{
3
    for (int i=1; i<7; i++)
4
    {
5
        u8 v=myArray[i];
6
    }
7
}
8

9
void function2(u8 myArray[])
10
{
11
    for (int i=1; i<7; i++)
12
    {
13
        u8 v=myArray[i];
14
    }
15
}
16

17
int main()
18
{
19
    function1(wr_bat_volt);
20
    function2(wr_bat_volt);
21
}

Da hat man offensichtlich das Anfänger Tutorial übersprungen.

Denn Pointer auf Pointer (bzw Pointer auf Array, in C praktisch dasselbe) ist einer der Übergabeparameter für main auf allem was kein µC ist:

1
int main (int argc, char ** argv)
2
{ 
3
  //...
4
  return 0;
5
}

D.h. jedes Beispiel was die Aufruf Parameter eines Programms auswertet würde OP zeigen wie man das programmieren kann.

Die Sprache C ist ohne Literaturstudium mit totem Holz (Büchern) schwer verständlich.

Karl K. schrieb:

u8* reg[] = {wr_bat_volt, wr_bat_pow, wr_soc};

danke, das war es.

Und warum der Zirkus? Hier reicht ein zweidimensionales Array.

1
u8 ups[3][8] = {
2
    { 0x00, 0x03, 0x02, 0x4B, 0x00, 0x01, 0xf4, 0x75 },
3
    { 0x00, 0x03, 0x02, 0x4E, 0x00, 0x01, 0xe4, 0x74 },
4
    { 0x00, 0x03, 0x00, 0xD6, 0x00, 0x01, 0x64, 0x23 }
5
};
6

7
ups[2][4] = 0xAA;

Karl K. schrieb:

Die Befehlsfolgen sind unterschiedlich lang:

Das ist zwar hier O.T., aber bei Deinen Pointer-Kenntnissen solltest Du erwägen, sie gleich lang zu machen und am Ende "leer" zu lassen. Alternativ die einzelnen Arrays mit Endekennung oder Längeninfo versehen und nur sequentiell abarbeiten (nicht 2D-indiziert).

Wie Harald geschrieben hat. Du benötigst sehr wahrscheinlich die Länge der Befehlsfolge. Also mach dir lieber für eine Befehlsfolge ein Struct mit einem sprechenden Namen z.B. "command" mit einer Variable für die Länge und einem Byte array für die eigentliche Folge. Bzw. mach dir gleich ein typedef dafür.

OP
1
     private void button4_Click(object sender, EventArgs e)
2
     {
3
         string line;
4
         string txt01 = "";
5
          string txt02 = "";
6
        bool cpy = false;
7
         bool whl = true;
8
     using (StreamWriter outputFile = new StreamWriter(@"C:\Users\karl\Desktop\rs485\2025_sim\sharp_types.h"))
9
     {
10
       System.IO.StreamReader file = new System.IO.StreamReader(@"C:\ra_vc\avr_sim_3\Form1.cs");
11

12
         while ((line = file.ReadLine()) != null && whl == true)
13
         {
14
             if (line.Contains("//start_01"))cpy = true;
15
             if(cpy==true )
16
             {
17
                 if (line.Contains("u8[]"))
18
                 {
19
                         int x1 = line.IndexOf(']')+1;
20
                         int x2 = line.IndexOf('=');
21
                         txt02 += line.Substring(x1, x2-x1)+",";
22

23
                         line = line.Replace("[]", "");
24
                     line = line.Replace ("=","[] =");
25
                 }
26
                 txt01 += line;
27
                  outputFile.WriteLine(line);
28

29
             }
30
              if (line.Contains("//end_01"))
31
             {
32
                cpy = false;
33
                whl = false;
34
                     txt01 += "u8* reg[] = { " + txt02 + "};";
35
                     outputFile.WriteLine("");
36
                  outputFile.WriteLine("u8* reg[] = { " + txt02 + "};");
37
            }
38
         }
39

40
     }
41

42
  }

generiert

1
         //start_01
2
            u8 wr_bat_volt [] = { 0x00, 0x03, 0x02, 0x4B, 0x00, 0x01, 0xf4, 0x75 };
3
            u8 wr_bat_pow [] = { 0x00, 0x03, 0x02, 0x4E, 0x00, 0x01, 0xe4, 0x74 };
4
            u8 wr_soc [] = { 0x00, 0x03, 0x00, 0xD6, 0x00, 0x01, 0x64, 0x23 };
5
            u8 wr_grid_pw [] = { 0x00, 0x03, 0x02, 0x83, 0x00, 0x01, 0x75, 0x8b };
6
            u8 wr_pvolt [] = { 0x00, 0x03, 0x02, 0xA4, 0x00, 0x01, 0xc5, 0x80 };
7
            u8 wr_off [] = {0x00, 0x10, 0x00, 0x50, 0x00, 0x01, 0x01, 0x00, 0x00, 0x57, 0x90 };   
8
            u8 wr_on [] = {0x00, 0x10, 0x00, 0x50, 0x00, 0x01, 0x01, 0x00, 0x01, 0x96, 0x50 };
9
        u8 wr_onoff [] = { 0x00, 0x03, 0x00, 0x50, 0x00, 0x01, 0x85, 0xca };
10
        u8 bat_on [] = { 0x02, 0x03, 0x00, 0x01, 0x00, 0x14, 0x14, 0x36 };
11
        u8 bat_off [] = { 0x02, 0x03, 0x00, 0x01, 0x00, 0x13, 0x55, 0xf4 };
12
     //end_01
13

14
u8* reg[] = {  wr_bat_volt , wr_bat_pow , wr_soc , wr_grid_pw , wr_pvolt , wr_off , wr_on , wr_onoff , bat_on , bat_off ,};

und wird über #include "sharp_types.h" eingebunden.

Vielleicht etwas oversized. Aber der Aufwand zum Testen des Programms ist so groß, dass es direkt auf dem avr sehr mühselig wäre.

Ja, ganz toll. Und woher weiß das, was auf "u8* reg[]" zugreift, nun, wie lang eines der Elemente darin sind? Diese Information geht verloren.

sizeof (wr_bat_volt)

funktioniert, aber

sizeof (reg[0])

liefert /ganz was anderes/.

Und .. u8? Wirklich? Spätestens seitdem es stdint.h gibt, ist sowas eine schlechte Idee.

OP

Harald K. schrieb:

Ja, ganz toll. Und woher weiß das, was auf "u8* reg[]" zugreift, nun, wie lang eines der Elemente darin sind?

Bislang gibt es nur 8- und 11-Byte-Befehle. Alle Befehle zum Messen haben 8Byte, alle Befehle zum Regeln haben 11Byte. Ein Problem, die Länge zu unterscheiden, stellte sich bislang nicht. Falls es auftreten sollte müsste die Länge ergänzt werden.

1
       private void sub_read_wr()
2
       { 
3
           
4
           bat_volt = sub_wr_tx_rx(reg[0], 8);
5
           bat_kw =   sub_wr_tx_rx(reg[1], 8);
6
           soc = sub_wr_tx_rx(reg[2], 8);
7
           grid_pw = sub_wr_tx_rx(reg[3], 8);
8
           pvolt = sub_wr_tx_rx(reg[4], 8);
9
....

Karl K. schrieb:

Harald K. schrieb:

Ja, ganz toll. Und woher weiß das, was auf "u8* reg[]" zugreift, nun, wie lang eines der Elemente darin sind?

Bislang gibt es nur 8- und 11-Byte-Befehle. Alle Befehle zum Messen haben 8Byte, alle Befehle zum Regeln haben 11Byte. Ein Problem, die Länge zu unterscheiden, stellte sich bislang nicht. Falls es auftreten sollte müsste die Länge ergänzt werden.

Pfuschen für Fortgeschrittene.

Karl K. schrieb:

private void sub_read_wr() {

1
       bat_volt = sub_wr_tx_rx(reg[0], 8);
2
       bat_kw =   sub_wr_tx_rx(reg[1], 8);
3
       soc = sub_wr_tx_rx(reg[2], 8);
4
       grid_pw = sub_wr_tx_rx(reg[3], 8);
5
       pvolt = sub_wr_tx_rx(reg[4], 8);

Warum dann indiziert? der naive Ansatz wäre:

1
    bat_volt = sub_wr_tx_rx(wr_bat_volt, sizeof(wr_bat_volt));  
2
    bat_kw   = sub_wr_tx_rx(wr_bat_pow , sizeof(wr_bat_pow ));
OP

Klaus schrieb:

Pfuschen für Fortgeschrittene.

ja - und? Solange es funktioniert sind mir Regeln relativ egal.

Bruno V. schrieb:

Warum dann indiziert? der naive Ansatz wäre: bat_volt = sub_wr_tx_rx(wr_bat_volt, sizeof(wr_bat_volt)); bat_kw = sub_wr_tx_rx(wr_bat_pow , sizeof(wr_bat_pow ));

guter Vorschlag. Das Programm ist in der Entwicklung - werde ich vielleicht einbauen.

Frage: Mein c#-programm ist ja nun in der Lage, gcc-code zu generieren. Wahrscheinlich kann man auch make über c# aufrufen. Dann hätte man irgendwo eine Datei main.hex in Maschinensprache für den avr. Es besteht eine serielle Verbindung zwischen avr und PC über RS485.

Kann man über diese Verbindung main.hex mittels Bootlader auf den avr schreiben?

Persönliche Seite

Karl K. schrieb:

gcc-code

Unterscheide bitte mal "C" und "GCC"...

  • C ist die Programmiersprache
  • GCC ist eine Sammlung von Compilern, inklusive einem C-Compiler, der ebenfalls "GCC" genannt wird
  • Der GCC C Compiler hat wie alle anderen Compiler auch diverse spezifische Erweiterungen, d.h. Code der diese nutzt ist GCC-spezifisch, aber es ist dennoch C-Code
  • Die GCC-Compiler können Code für viele verschiedene Plattformen generieren, insbesondere x86/amd64 (PC), ARM, und auch AVR. Die Variante der GCC-Compiler-Sammlung für AVR wird AVR-GCC genannt

Du generierst also C-Code. Den kannst du auch auf dem PC ausführen, solange du keine AVR-spezifischen Dinge nutzt. Dein Problem in diesem Thread ist ein gewöhnliches C-Problem, kein GCC-Problem, daher ist sogar der Threadtitel verkehrt.

Karl K. schrieb:

Kann man über diese Verbindung main.hex mittels Bootlader auf den avr schreiben?

Du kannst einfach den avrdude aufrufen.

Moderator Persönliche Seite

Sherlock 🕵🏽‍♂️ schrieb:

1
> void function1(u8* myArray)
2
> {
3
>     for (int i=1; i<7; i++)
4
>     {
5
>         u8 v=myArray[i];
6
>     }
7
> }

Arrays beginnen in C mit dem Index 0 und nicht 1. Außerdem läuft bei Dir der Index i durch die Prüfung i<7 nur bis 6. Damit wird dann nicht nur das erste Element, sondern auch noch das letzte (achte Element) ignoriert.

Korrekt wäre also bei 8 Elementen:

1
    for (int i=0; i<8; i++)    // 0,1,2,3,4,5,6,7

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über ein Jahr alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.