Forum: Compiler & IDEs Array zuweisen


von F. B. (flump)


Lesenswert?

Hallo,
ich habe ein kleines Problem.

Ich habe mehrere Arrays die einen bestimmten Programmablauf darstellen
Sprich 16 spalten für die 16 pwm ausgänge (stärke 0..255)
und 16 zeilen die quasi eine sequenz von 16 verschiedenen mustern 
darstellen

volatile uint8_t muster1 [16][16] = { Werte werden eingefügt };
volatile uint8_t muster2 [16][16] = { Werte werden eingefügt };
volatile uint8_t muster3 [16][16] = { Werte werden eingefügt };
usw.

nun habe ich einen soft pwm programmiert wecher

volatile uint8_t pwm_setting [16][16] benutzt um den PWM zu steuern

mein problem besteht nun darin, dass ich folgendes nicht schreiben kann

pwm_setting = muster2;

ich habe keine erklärung dafür gefunden! habe auch im forum gesucht aber 
auch drt habe ich nichts gefunden

kann man da was machen , dass man nur auf das gewünschte muster zeigt??

von Random .. (thorstendb) Benutzerseite


Lesenswert?

such mal nach pointern in C.

von Pako (Gast)


Lesenswert?

Ein Zuweisung wie bei einer einfachen Variablen
1
a = b;
funktioniert bei einem Array nicht. Du mußt entweder die Elemente in 
einer Schleife kopieren, oder z.B. memcpy() verwendet.
Oder Du übergibst nicht eine Kopie des Arrays, sondern eine Referenz auf 
das Array (sprich einen Zeiger).

von Clemens M. (panko)


Lesenswert?

Nimmt die Funktion soft_pwm einen parameter? Ich denke da an den Pointer 
auf das Array was bearbeitet werden soll.
Mit einer festverdrahteten globalen Variable zu arbeiten schränkt ja 
ein,

Wenn also soft_pwm( uint8_t* data ) existiert, die data mit deinem 
Datenlayout interpretiert (und du davon ausgehst, daß die die beiden 
Dimensionen konstant hast), kannst du ja einfach soft_pwm( muster1 ), 
soft_pwm( muster2 ) etc aufrufen. Ist die Dimension [16][16] nicht fest, 
müsstest du die noch mitübergeben, damit die Funktion das Array nicht 
verlässt.

Nachtrag: Spricht auch nichts dagegen bei den festen Grenzen soft_pwm( 
uint8_t daten[16][16] ) zu definieren.

von Oliver (Gast)


Lesenswert?

Florian Bauer schrieb:
> pwm_setting = muster2;
>
> ich habe keine erklärung dafür gefunden! habe auch im forum gesucht aber
> auch drt habe ich nichts gefunden

Nun ja, ein gutes C-Buch hilft da eher weiter. Das Forum hier ist ja 
kein generelles C-Grundlagenforum. Man kann halt in C keine Arrays per 
"=" kopieren, dafür benötigst du memcpy.

Allerdings willst du vermutlich die Array gar nicht kopieren, es reicht 
ja ein Pointer auf das jeweils aktuelle Array, umd damit was zu machen.

Oliver

von F. B. (flump)


Lesenswert?

Vielen Dank für die Tips!! Echt super feedback

Habe es jetzt so gelöst:

Nachtrag: Spricht auch nichts dagegen bei den festen Grenzen soft_pwm(
uint8_t daten[16][16] ) zu definieren.

Diese Lösung ist echt super für mich da ich ja nur 8 dieser Arrays/ bei 
mir sind es quasi muster/ habe

von F. B. (flump)


Lesenswert?

Irgendwie funktiniert das mit den Pointern nicht so wie ich das will.
Vieleicht könnt ihr mir helfen.

hier habe ich meine muster
uint8_t muster1 [16][16];
uint8_t muster2 [16][16];

dann habe ich einen Zeiger der auf ein Muster zeigen soll
uint8_t *muster_ptr;

in der MAIN weise ich dann dem Pointer die Anfangsadresse meines Arrys 
zu
muster_ptr = muster2;

dann rufe ich durch eine Interruptroutine meine Funktion auf
soft_PWM (&muster_ptr)

die funktion sieht dann wie folgt aus:
void soft_PWM (uint8_t **muster)
{
   for (uint8_t i=0;i<16;i++)
   {
    uint8_t temp = **(muster+i);   //hier wird mein array wert gelesen
    if(temp>10)                    //hier wird der wert verarbeitet
    {
     setzte bits in einem register
    }
   }
}

irgendwie funktioniert jedoch der aufruf nicht
im avr studio kommt auch immer eine warnung:
assignment from incopatible pointer type

weis echt nicht mehr weiter, hab schon alles durchsucht....
kann des sein, weil mein array 2 dimensional ist???
ich könnte es ja eigentlich auch in ein 1 dimensionales array 
reinschreiben . Aber normalerweise dürfte es keinen unterschied machen , 
weil die daten ja eh in einer reihenfolge im speicher stehen.

von YEAH (Gast)


Lesenswert?

Florian Bauer schrieb:
> in der MAIN weise ich dann dem Pointer die Anfangsadresse meines Arrys
> zu
> muster_ptr = muster2;

Ich habe mich damals auch etwas mit C/C++ beschäftigt. Ich bin der Crack 
aber müsste das nicht

*muster_ptr = &muster2;

heissen? Du weisst ja den Pointer den die Anfangsadresse mit.

Und warum

Florian Bauer schrieb:
> void soft_PWM (uint8_t **muster)  ????????

Hier ein einfacher Beispiel
--------------------------------------------------------

int EinUndAusgabe (int *uebergeben)
{
  printf("Gib eine beliebige Zahl ein: ");

  scanf("%i",uebergeben); //wieder ist der Adressoperator (&) nicht 
nötig, weil der Pointer breits die Adresse enthält

  printf("Ausgabe ueber Pointer: %i",*uebergeben);
}

int main ()
{
int Eingabe;
int *Pointer = &Eingabe;

  EinUndAusgabe(Pointer);

  getch();

--------------------------------------------------------


Hoffe das ist richtig so. Habe nur gefährliches Halbwissen :)

von YEAH (Gast)


Lesenswert?

Sorry für Doppeleintrag :)  Noch zu früh

"Ich habe mich damals auch etwas mit C/C++ beschäftigt. Ich bin der 
Crack
aber müsste das nicht"

sollte heissen


"Ich habe mich damals auch etwas mit C/C++ beschäftigt. Ich bin NICHT 
der Crack aber so müsste das sein" :-)

Sorry

von Pako (Gast)


Lesenswert?

Florian Bauer schrieb:
1
 uint8_t muster1 [16][16];
2
 uint8_t muster2 [16][16];
3
 uint8_t *muster_ptr;
4
 muster_ptr = muster2;
5
 soft_PWM (&muster_ptr)
6
 void soft_PWM (uint8_t **muster)
7
 {
8
    for (uint8_t i=0;i<16;i++)
9
    {
10
     uint8_t temp = **(muster+i);   //hier wird mein array wert gelesen
11
     if(temp>10)                    //hier wird der wert verarbeitet
12
     {
13
      setzte bits in einem register
14
     }
15
    }
16
 }

Da stimmt etwas grundlegendes nicht:
1. Deine "muster1" und "muster1" sind 2-dimensionale 16x16er Arrays. In 
der Funktion "soft_PWM" liest Du aber ein 1-dimensionales 16er Array 
aus. D.h. in Deinem Code würden überhaupt nur 16 von 256 Bytes 
verwendet.
2. Was für einen Datensatz willst Du denn in soft_PWM() überhaupt 
verarbeiten? Willst Du ein 16er-Array oder ein 16x16er-Array?

von Rolf Magnus (Gast)


Lesenswert?

Florian Bauer schrieb:
> dann habe ich einen Zeiger der auf ein Muster zeigen soll
> uint8_t *muster_ptr;

Das ist ein Zeiger auf einen uint8_t. Den kannst du nutzen, um auf den 
Anfang eines Arrays aus uint8_t zu zeigen. Ein Muster ist aber kein 
Array aus uint8_t, sondern ein Array aus Arrays aus uint8_t.

> in der MAIN weise ich dann dem Pointer die Anfangsadresse meines Arrys
> zu
> muster_ptr = muster2;

Das sollte zu einer Warnung führen, weil der Typ falsch ist.

> dann rufe ich durch eine Interruptroutine meine Funktion auf
> soft_PWM (&muster_ptr)

Warum übergibst du die Adresse des Zeigers statt einfach nur den Zeiger 
selbst?

> irgendwie funktioniert jedoch der aufruf nicht
> im avr studio kommt auch immer eine warnung:
> assignment from incopatible pointer type

Sicher, daß die beim Aufruf kommt? Da stimmen die Typen überein, aber 
bei deiner Zuweisung in main nicht.

> ich könnte es ja eigentlich auch in ein 1 dimensionales array
> reinschreiben . Aber normalerweise dürfte es keinen unterschied machen ,
> weil die daten ja eh in einer reihenfolge im speicher stehen.

Es macht einen Unterschied, weil C eine typisierte Sprache ist. 
Datentypen gibt es nicht ohne Grund, und sie müssen zusammenpassen.

Du könntest es so machen:

statt
> uint8_t *muster_ptr;

nimmst du:
1
uint8_t (*muster_ptr)[16]; // Zeiger auf ein Array aus 16 uint8_t

Dann aus
// soft_PWM (&muster_ptr)
1
soft_PWM (muster_ptr);

und aus:
// void soft_PWM (uint8_t **muster)
1
void soft_PWM (uint8_t (*muster)[16])

dann kannst du über den Pointer genau so zugreifen, wie du es auch bei 
direkter Verwendung eines Musters tun würdest:
1
    uint8_t temp = muster[a][c]; // a und c im Bereich 0...15

PS: Falls sich jemand fragt, warum der zweite Index c statt b ist: 
Das liegt daran, daß das Forum mein Posting mit b in eckigen Klammern 
nicht akzeptiert, da das angeblich Spam sei...

von F. B. (flump)


Lesenswert?

> Da stimmt etwas grundlegendes nicht:
> 1. Deine "muster1" und "muster1" sind 2-dimensionale 16x16er Arrays. In
> der Funktion "soft_PWM" liest Du aber ein 1-dimensionales 16er Array
> aus. D.h. in Deinem Code würden überhaupt nur 16 von 256 Bytes
> verwendet.
> 2. Was für einen Datensatz willst Du denn in soft_PWM() überhaupt
> verarbeiten? Willst Du ein 16er-Array oder ein 16x16er-Array?

Die Grundidee ist 16 PWM Ausgänge mit 16 bestimmten Werten für eine 
bestimmte zeit ca.2-3 sekunden laufen zu lassen und dann auf quasi auf 
den nächsten "frame" (die zweite zeile des arrays) zu springen und diese 
einstellung wieder für ein par sekunden zu nutzen. Und das eben 16 mal.

von F. B. (flump)


Lesenswert?

> Das ist ein Zeiger auf einen uint8_t. Den kannst du nutzen, um auf den
> Anfang eines Arrays aus uint8_t zu zeigen. Ein Muster ist aber kein
> Array aus uint8_t, sondern ein Array aus Arrays aus uint8_t.

Was meinst du mit Muster denn genau?? Ich habe mir nur die 
Speicherstruktur  von 2 dimesionalen Arrays angesehen und dort ist es ja 
im prinzip egal ob ich ein 1 dimensionales oder ein zweidimensionales 
Array mache, weil die werte ja der reihe nach gespeichert werden. 
Deswegen habe ich mir auch gedacht, dass ich genauso wie bei einem 1 
dimensionalen array nur die Adresse der Startposition angebe und dann 
durch das wissen von der Zeilenlänge und der anzahl von reihen die 
einzelnen elemente abfragen kann.
Oder ist es nicht möglich die Startadresse von 2 dimensionalen arrays zu 
übergeben?

>
>> in der MAIN weise ich dann dem Pointer die Anfangsadresse meines Arrys
>> zu
>> muster_ptr = muster2;
>
> Das sollte zu einer Warnung führen, weil der Typ falsch ist.

Aber wie kann hier der Typ falsch sein? ich weise einem pointer die 
Startadresse des 2 dimensionalen arrays zu.
Das wäre ja "laut literatur" genau das gleiche wie
muster_ptr = &muster2[0]

> Du könntest es so machen:
>
> statt
>> uint8_t *muster_ptr;
>
> nimmst du:
>
1
> uint8_t (*muster_ptr)[16]; // Zeiger auf ein Array aus 16 uint8_t
2
>
........habe hier abgekürzt
> [C]
>     uint8_t temp = muster[a][c]; // a und c im Bereich 0...15

Das verstehe ich nicht ganz. Wie ist es möglich auf ein 
zweidimensionales array (muster[a][c]) zuzugreifen wenn ich nur ein 
eindimensionales array erstelle(Zeiger auf ein Array aus 16 uint8_t)??


irgendwie will der groschen bei mir nicht fallen

von F. B. (flump)


Lesenswert?

> Du könntest es so machen:
>
> statt
>> uint8_t *muster_ptr;
>
> nimmst du:
>
1
> uint8_t (*muster_ptr)[16]; // Zeiger auf ein Array aus 16 uint8_t
2
>
>
> Dann aus
> // soft_PWM (&muster_ptr)
>
>
1
> soft_PWM (muster_ptr);
2
>
>
> und aus:
> // void soft_PWM (uint8_t **muster)
>
>
1
> void soft_PWM (uint8_t (*muster)[16])
2
>
>
> dann kannst du über den Pointer genau so zugreifen, wie du es auch bei
> direkter Verwendung eines Musters tun würdest:
>
1
>     uint8_t temp = muster[a][c]; // a und c im Bereich 0...15
2
>
>
> PS: Falls sich jemand fragt, warum der zweite Index c statt b ist:
> Das liegt daran, daß das Forum mein Posting mit b in eckigen Klammern
> nicht akzeptiert, da das angeblich Spam sei...

Hallo,
habe es gerade so ausprobiert.
Und was soll ich sagen.... Es funktioniert einfach super.
Vielen vielen Dank dafür.
Habe des mit 2 dimensionalen arrays und den pointern nochmla nachgelesen 
und verstehe jetzt so halb wie das funktioniert.

Am einfachsten wäre immernoch wenn man 2dimensionale arrays einfach per 
= zuweisen könnte

von Pako (Gast)


Lesenswert?

Florian Bauer schrieb:
> Die Grundidee ist 16 PWM Ausgänge mit 16 bestimmten Werten für eine
> bestimmte zeit ca.2-3 sekunden laufen zu lassen und dann auf quasi auf
> den nächsten "frame" (die zweite zeile des arrays) zu springen und diese
> einstellung wieder für ein par sekunden zu nutzen. Und das eben 16 mal.

Das Problem ist, daß es mir nicht ersichtlich ist, wo Du mit welcher 
"Datenbreite" arbeiten willst.
Willst Du
1. eine Funktion soft_PWM() für jeden Kanal einzeln machen?
-> dann würdest Du ihr ein 1-dim. 16er-Array übergeben.
2. eine gemeinsame Funktion soft_PWM() für alle 16 Kanäle machen?
-> dann würdest Du ihr ein 2-dim. 16x16er-Array übergeben.

Wenn Du einen Zeiger "uint8_t*" benutzt, enthält dieser nichts anderes 
als eine Adresse im Speicher. Ob Du diese Adresse als Basis eines 16er 
oder eines 16x16er Arrays oder irgendetwas anderem interpretierst, liegt 
in Deiner Handlungsfreiheit.

Bsp für 1-kanalige soft_PWM:
1
uint8_t muster1 [16];
2
uint8_t *muster_ptr;
3
muster_ptr = muster2;
4
soft_PWM_nur1kanal(muster_ptr);
5
6
void soft_PWM_nur1kanal(uint8_t *muster)
7
 {
8
    for (uint8_t i=0;i<16;i++)
9
    {
10
     uint8_t temp = muster[i];  // ist das gleiche wie = *(muster+i);   
11
     if(temp>10)                   
12
     {
13
      ...
14
     }
15
    }
16
 }

Bsp für 16-kanalige soft_PWM:
1
uint8_t muster1 [16][16];
2
uint8_t *muster_ptr;
3
muster_ptr = muster2;
4
soft_PWM_16kaenale(muster_ptr);
5
6
void soft_PWM_nur1kanal(uint8_t *muster)
7
 {
8
    for (uint8_t kanal=0;kanal<16;kanal++)
9
    {
10
      for (uint8_t i=0;i<16;i++)
11
      {
12
       uint8_t temp = muster[kanal*16+i];   
13
       if(temp>10)                   
14
       {
15
        ...
16
       }
17
     }
18
    }
19
 }

Du siehst, man kann in beiden Fällen die gleiche Mimik benutzen, da Du 
nichts anderes benögtist, als eine Basisadresse.
Allerdings muß Deine soft_PWM()-Funktion natürlich das richtige damit 
anfangen.

von F. B. (flump)


Lesenswert?

Jetzt hab ichs endlich gechekt mit den pointern.

Habe selber viel zu kompliziert gedacht!!!!!

Danke an alle die hier wirklich sehr gute Kommentare abgeliefert haben.
Ohne eure Hilfe wäre ich sicher noch verzweifelt.

Schöne Grüße aus Innsbruck

Florian

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.