Forum: Mikrocontroller und Digitale Elektronik AVR AtMEGA328P-PU u. I2C in Arduino: Probleme mit mehrdimensionale Arrays


von M. S. (marvs)


Lesenswert?

Guten Tag alle zusammen,

in diesem Beitrag möchte ich mit euch ein Problem von mir teilen.

Ich habe vor, mit I2C, ein mehrdimensionales Array zu versenden an
einen "Slave". Der "Master"- sowie der "Slavecode" bringen nicht das 
gewünschte Ergebnis trotz fehlerfreim Code (glaub ich... es gibt keine 
Compilerfehler.).
Um genauer zu sein: es geht um ein zweidimensionales Array der Größe 
8x8.
Beide Mikrocontroller werden über die Arduino-IDE programmiert. Beide 
sind
ein Klon...(glaub ich zumindest, dass beide Klons sind. Orginale sind es 
beide nicht XD ) von dem Arduino UNO Board.
(Maker Factory, ATMEGA328 UNO Entwicklungsboard)
(Controller:Atmel_1725_ATMEGA328P-PU und Atmel_1735_ATMEGA328P-PU)

Es geht darum, Nullen und Einsen zu versenden und vom anderen anzeigen 
zu
lassen.

Um das Array zu senden lass ich es, weil es wie auf der Arduino-Webseite 
nicht geht, durch eine For-Schleife Wert für Wert verseden.

Dies sieht so aus:
1
#include <Wire.h>
2
3
byte led[8][8] = {    //Array mit dem "Bild" aus Einsen.(Es ist ein Smiley)                
4
  {1,1,1,1,1,1,1,1},                  
5
  {0,0,0,0,0,0,0,0},                  
6
  {0,0,1,0,0,1,0,0},                  
7
  {0,0,0,0,0,0,0,0},                 
8
  {0,0,0,1,1,0,0,0},                 
9
  {0,1,0,0,0,0,1,0},                 
10
  {0,0,1,1,1,1,0,0},                  
11
  {1,1,1,1,1,1,1,1}                   
12
};  
13
int y=0, x=0;
14
int i;        //Ich weiß. Unnötig aber war ein anderer Ansatz.
15
16
void setup() {
17
  Serial.begin(9600);
18
  Wire.begin(9);
19
  //sendarr(led[8][8]);  //Erste Funktion.
20
  //sarr(led[8][8]);     //Zweite Funktion.
21
}
22
23
void loop() {
24
  //sarr(led[8][8]);    //Fehlgeschlagener Versuch,
25
  //delay(2000);        //es dauerhaft zu versenden mit Zeitabstand.
26
}
27
28
void sendarr(byte led[8][8]) {
29
  Wire.beginTransmission(8);
30
  for (int i=0;i<=64; i++) {
31
    Wire.write(led[y][x]);   //Das geht nicht, auch nicht wenn man versucht
32
    x++;                     // es auf Wire.write(led, 64); zu bringen.
33
    if (x==7) { 
34
      x=0;
35
      y++;
36
    }
37
    if (y==7) {
38
      x=0;
39
      y=0;
40
    }
41
  }
42
  Wire.endTransmission();
43
}
44
45
void sarr(byte led[8][8]) {
46
  Serial.println("Anfang");
47
  Wire.beginTransmission(8);
48
  for (i=0;i<=64; i++) {
49
    byte lol = led[y][x];   //Zweite Variante, die meistens Wirkung zeigt
50
    Serial.print(lol);
51
    Wire.write(lol);        //als es so wie oben zu machen.
52
    x++;
53
    if (x==8) {
54
      Serial.println();
55
      x=0;
56
      y++;
57
    }
58
    //if (y==7) {                   //Hiermit wurde versucht, die Schleife
59
      //Serial.println(y);          //zu verlassen, als das noch in loop()
60
      //Wire.endTransmission();     //stand zur dauerhaften wiederholung.
61
      //break;
62
    //}
63
  }
64
  
65
  //delay(500);                    //Relikte aus dem loop() bevor es zur
66
  //i=0;                           //Funktion wurde.
67
  Serial.println("Ende");
68
}

Weil der Code keine Fehler warf, nahm ich am Anfang an, der "Slave" wäre 
falsch programmiert. Erst als ich aus Interesse wie das Signal aussieht 
den Beispielcode laufen ließ mit angschlossenem Oszilloskop, fiel mir 
auf, das bei meinem Code noch nicht einmal was gesendet wird.

Der Fehler beginnt also schon am "Master writer".

Wenn jemand weiß, wie man sowas löst oder generell eine Idee dazu hat:
Ich bin stark dran interessiet.


PS: Ich möchte mich für Schreibfehler, falsche Formatierung des Codes 
und oder Programmierungsstil entschuldigen. Entschuldigung.
Ich hoffe, dass das dennoch alles Regelkonform ist was ich hier verzapft 
habe.

Mfg

MarvS

von Stefan F. (Gast)


Lesenswert?

> bringen nicht das gewünschte Ergebnis trotz fehlerfreim
> Code (glaub ich... es gibt keine Compilerfehler.).

Wenn das Ergebnis fehlerhaft ist, muss wohl der Code fehlerhaft sein. 
Dass der Compiler keinen Fehler meldet, heisst nicht viel. Zumal in der 
Arduino IDE standardmässig alle Warnungen unterdrückt werden (stelle das 
mal um!).

> for (i=0;i<=64; i++)

Das sind 65 Schritte - einer zu viel!

> x++;
> if (x==7) {
>    x=0;
> }

Damit kommst du nur von 0 bis 6 - einer zu wenig!

> if (y==7) {
>     x=0;
>     y=0;
> }

Gleicher Fehler nochmal.

Ich würde das Senden mit zwei verschachtelten Schleifen machen:
1
void sendarr(byte led[8][8]) 
2
{
3
    for (byte x=0; x<8; x++)
4
    {
5
        for (byte y=0; y<8; y++)
6
        {
7
            byte b=led[y][x];
8
            Serial.print(b);
9
        }
10
        Serial.println();
11
    }
12
}

> Erst als ich aus Interesse wie das Signal aussieht
> den Beispielcode laufen ließ mit angschlossenem Oszilloskop, fiel mir
> auf, das bei meinem Code noch nicht einmal was gesendet wird.

Aber Dir muss doch schon vorher aufgefallen sein, dass die Serial 
Ausgabe auch falsch ist. Wie sieht denn dein Schaltplan aus? Sind da 
Pull-Up Widerstände drin? Welchen Pegel haben die beiden Leitungen SDA 
und SDL während der Blockierung? Hast du die beiden Module mit GND 
untereinander verbunden?

von Elektro Heini (Gast)


Lesenswert?

Hi,

ich kenne zwar den Header Wire.h nicht und habe den Code nur kurz 
überflogen, jedoch kann ich dir einen Tipp geben:

Du willst 8x8 Nullen und Einsen versenden und verwendest dafür bytes. 
Das sind insgesamt 64byte. Das ist zwar noch möglichen aber für einen 
Atmega recht viel. Verwende doch lieber einen Array mit acht Bytes, bei 
denen du jedes Bit einzeln setzt, so in etwa:
1
byte led[8] = {                
2
  0b11111111,                  
3
  0b00000000,                  
4
  0b00100100,                  
5
  0b00000000,                 
6
  0b00011000,                 
7
  0b01000010,                 
8
  0b00111100,                  
9
  0b11111111               
10
};

Das ist nur 8byte RAM und wesentlich schneller vom Atmega zu 
verarbeiten. Auch dein Programm wird einfacher (keine geschachtelten 
Schleifen mehr). Überarbeite vlt. noch einmal deinen Code oder ändere 
das Konzept. Wofür brauchst du eigentlich 2 µC? Es ist nämlich meistens 
deutlich einfacher nur ein Programm zu schreiben als zwei die 
miteinander kommunizieren müssen (das ist wirklich aufwendig).

LG

von Einer K. (Gast)


Lesenswert?

M. S. schrieb:
> byte led[8][8]

Der Wire Sende und Empfangsbuffer ist nur 32 Byte groß.
Das Array passt da, in einem Block, nimmer rein.

Siehe: https://www.arduino.cc/en/Reference/Wire

M. S. schrieb:
> trotz fehlerfreim Code
Naja...
Wire.write() liefert eine Erfolgs- oder Fehlermeidung, welche du 
großzügig ignorierst.
"Fehlerfrei", ist da nicht das richtige Wort.

von Blabla (Gast)


Lesenswert?

Hi, ja als erstes mal die Beschaltung prüfen und auch ein 
Minimalbeispiel ausprobieren und daraus lernen.

z.B.: http://hlembke.de/arduinoablage/crate.php?20150411i2c
      https://www.arduino.cc/en/Tutorial/MasterWriter

Abgesehen von der wirklich suboptimalen Programmierung die schon erwähnt 
wurde solltest du auch versuchen zu Verstehen wie I2C funktioniert.

Dein Sender wird wenn ich das richtig sehe als Slave initialisiert. 
Jedoch Steuert der Master immer die Kommunikation. Kann also nicht 
gehen. Auch fehlt mir der Code der Gegenseite.

Dein Problem ist nicht der RAM.

von Einer K. (Gast)


Lesenswert?

> Blabla schrieb:
> Dein Sender wird wenn ich das richtig sehe als Slave initialisiert.
Ja, ist aber nicht schlimm....

Blabla schrieb:
> Jedoch Steuert der Master immer die Kommunikation.
Ja, ist aber nicht schlimm.

> Blabla schrieb:
> Kann also nicht gehen.
Doch doch.
I2C kann Multimaster.
Wire auch.

Blabla schrieb:
> Dein Problem ist nicht der RAM.
Aber der zu kleine Buffer.
Und der liegt im Ram.

von M. S. (marvs)


Lesenswert?

Hallo @Stefanus,

ich hätte eventuel anmerken sollen das ich mich bedingt auskenne.

>for (i=0;i<=64; i++) "Das sind 65 Schritte - einer zu viel!"
Ja.

>if (x==7) {

Das ist mir bekannt. Ich hatte das auch schon längst korrigiert.
Ich habe vergessen das so zu speichern.

>Aber Dir muss doch schon vorher aufgefallen sein, dass die Serial
Ausgabe auch falsch ist.

Nein.
Die Ausgabe war:
11111111
00000000
00100100
00000000
00011000
01000010
00111100
11111111
1 (<-Hier der Fehler mit der 65.)
Das war somit für mich richtig.

>Wie sieht denn dein Schaltplan aus? Sind da Pull-Up Widerstände drin?

A5 an A5. A4 an A4. GND an GND.
Auf die Widerstände habe ich verzichtet. Beide lagen direkt vor meiner 
Nase.
Da dachte ich:"Vier cm...brauch ich nicht.".

Das mit dem Ozilloskop war reine Neugier. Ich habe das Ding rausgekrammt 
und einfachmal angeschlossen. Ich bin kein Profi damit. Ich benutze es 
ja auch kaum bishin zu garnicht. Ich besitze es einfach nur.

Mfg
MarvS

von Stefan F. (Gast)


Lesenswert?

M. S. schrieb:
> Auf die Widerstände habe ich verzichtet.

Die sind aber notwendig.

Ich teste I²C gerne mit niedrigen Bitraten und LED's. Dann sieht man sie 
flackern - oder auch nicht. Und man sieht an Dauerleuchten auch, wenn 
der Bus hängt.
1
            4,7k Pull-Up
2
SDA o---+------[===]------+-----o 5V
3
        |                 |
4
        +---[===]---|<|---+
5
            2,2k    LED

Und das gleiche nochmal für SCL.

von M. S. (marvs)


Lesenswert?

@ Elektro Heini
Hallo,

> Tipp:
>
> Du willst 8x8 Nullen und Einsen versenden und verwendest dafür bytes.
> Das sind insgesamt 64byte. Das ist zwar noch möglichen aber für einen
> Atmega recht viel. Verwende doch lieber einen Array mit acht Bytes, bei
> denen du jedes Bit einzeln setzt, so in etwa:
>
>
1
> byte led[8] = {
2
>   0b11111111,
3
>   0b00000000,
4
>   0b00100100,
5
>   0b00000000,
6
>   0b00011000,
7
>   0b01000010,
8
>   0b00111100,
9
>   0b11111111
10
> };
11
> 
12
>
>
> Das ist nur 8byte RAM und wesentlich schneller vom Atmega zu
> verarbeiten. Auch dein Programm wird einfacher (keine geschachtelten
> Schleifen mehr). Überarbeite vlt. noch einmal deinen Code oder ändere
> das Konzept.

Ich werde versuchen, das abzuändern.

> Wofür brauchst du eigentlich 2 µC? Es ist nämlich meistens
> deutlich einfacher nur ein Programm zu schreiben als zwei die
> miteinander kommunizieren müssen (das ist wirklich aufwendig).

Einer der beiden ist stark beschäftigt. Da versuche ich den Code klein 
zu halten. Ich speichere auch deshalb das Array auch auf einem anderem 
zudem es auch auf dem geändert werden soll per Tastereingaben.

Mfg
MarvS

von Blabla (Gast)


Lesenswert?

Ok Fanby, dann kläre mich mal auf wie die Wire.h funktioniert. Da die 
Arduino Hilfe sa leider sehr dürftig ist und ich das nicht wirklich oft 
benutze kenne mich nicht so gut aus.

1. Darf ein Slave mit dem anderen Kommunizieren? (Vermutung da der 
zweite Teil des Codes fehlt. Aber es werden die Adressen 8 und 9 
verwendet.)

M. S. schrieb:
> Wire.write(led[y][x]);

2. Wo werden hier die Daten in den Puffer geschoben und wann wird die 
eigentliche Übertragung durchgeführt? Ich sehe da immer nur ein byte pro 
Aufruf der write Funktion.

von M. S. (marvs)


Lesenswert?

@ ufuf
Hallo,

>> byte led[8][8]
>
> Der Wire Sende und Empfangsbuffer ist nur 32 Byte groß.
> Das Array passt da, in einem Block, nimmer rein.
>
> Siehe: https://www.arduino.cc/en/Reference/Wire

Stimmt. (Facepalm)

>> trotz fehlerfreim Code
> Naja...
> Wire.write() liefert eine Erfolgs- oder Fehlermeidung, welche du
> großzügig ignorierst.
> "Fehlerfrei", ist da nicht das richtige Wort.

Das wirft eine Erfolgsmeldung?
Das es Fehlermeldungen wirft wusste ich aber es gab keins von beidem.
...

Mfg
MarvS

von Einer K. (Gast)


Lesenswert?

M. S. schrieb:
> Das wirft eine Erfolgsmeldung?

Ja!
Aber sie gesagt: Die ignorierst du gekonnt.

> *Returns*
> byte: write() will return the number of bytes written,
> though reading that number is optional
Aus: https://www.arduino.cc/en/Reference/WireWrite

von M. S. (marvs)


Lesenswert?

@ Stefanus
Hallo,
>> Auf die Widerstände habe ich verzichtet.
>
> Die sind aber notwendig.

Auch bei Kurzstrecken also.... . Ok, verstanden.

> Ich teste I²C gerne mit niedrigen Bitraten und LED's. Dann sieht man sie
> flackern - oder auch nicht. Und man sieht an Dauerleuchten auch, wenn
> der Bus hängt.
>
>
1
> 
2
>             4,7k Pull-Up
3
> SDA o---+------[===]------+-----o 5V
4
>         |                 |
5
>         +---[===]---|<|---+
6
>             2,2k    LED
7
>
>
> Und das gleiche nochmal für SCL.

Werde es beachten. Suche dann Morgen mir Widerstände aus meiner Kiste 
und
hänge sie mit dran.

Mfg
MarvS

von Stefan F. (Gast)


Lesenswert?

Blabla schrieb:
> Wo werden hier die Daten in den Puffer geschoben und wann wird die
> eigentliche Übertragung durchgeführt?

Die Übertragung findet erst ganz zum Schluss bei Wire.endTransmission() 
statt.

Anstatt hier so unterschwellig einen auf Oberlehrer zu machen, könntest 
du einen Blick in den Quelltext (Wire.c) werfen, der ist ja alles andere 
als geheim.

von Stefan F. (Gast)


Lesenswert?

M. S. schrieb:
>>> Auf die Widerstände habe ich verzichtet.
>> Die sind aber notwendig.
> Auch bei Kurzstrecken also.... . Ok, verstanden.

Ja sicher doch, denn die Mikrocontroller betreiben ihre Ausgänge im 
Open-Drain Modus (auch als Wired-And bekannt). Den High Pegel liefern 
die Widerstände.

https://hackaday.com/2017/02/08/taking-the-leap-off-board-an-introduction-to-i2c-over-long-wires/

von M. S. (marvs)


Lesenswert?

Hallo,

@  Blabla
> 1. Darf ein Slave mit dem anderen Kommunizieren? (Vermutung da der
> zweite Teil des Codes fehlt. Aber es werden die Adressen 8 und 9
> verwendet.)

Das stimmt. Das liegt daran, dass ich beide eine Adresse gegeben habe.
Ich weiß nur noch nicht wie ich das zum laufen bekomme.
Ob der "Master" mit Wire.onRequest(adresse); geht, weiß ich nur nicht.
Das ist der Grund warum beide eine Adresse haben.

> 2. Wo werden hier die Daten in den Puffer geschoben und wann wird die
> eigentliche Übertragung durchgeführt? Ich sehe da immer nur ein byte pro
> Aufruf der write Funktion.

Ich weiß von nichts. Muss ich das beachten? Geht das in der Arduino-IDE?

@ ufuf
>>M. S. schrieb:
>>Das wirft eine Erfolgsmeldung?

>Ja!
>Aber sie gesagt: Die ignorierst du gekonnt.

Oh.


Mfg
MarvS

von Einer K. (Gast)


Lesenswert?

Blabla schrieb:
> 1. Darf ein Slave mit dem anderen Kommunizieren? (Vermutung da der
> zweite Teil des Codes fehlt. Aber es werden die Adressen 8 und 9
> verwendet.)

Nein, es kommuniziert immer nur der Master mit dem Slave.
Das hattest du schon richtig erkannt.

Aber Wire ist so gebaut, dass es als Slave auf Adresse 8 lauschen kann, 
und als Master mit dem Slave welcher mit der Adresse 9 lauscht, 
quatschen kann.
Das kommt sich nicht ins Gehege.

Blabla schrieb:
> 2. Wo werden hier die Daten in den Puffer geschoben und wann wird die
> eigentliche Übertragung durchgeführt? Ich sehe da immer nur ein byte pro
> Aufruf der write Funktion.

Wire.write() stopft in den Buffer!
Wire.endTransmission() sendet den Buffer.

von Blabla (Gast)


Lesenswert?

return = Wire.write(buffer)
Serial.print(return)

Ach... vielleicht tut es ja.

void setup() {
  Serial.begin(9600);
  Wire.begin();
}

void loop() {
  Serial.println("Anfang");
  Wire.beginTransmission(8);
  sarr(led[8][8]);    //Fehlgeschlagener Versuch,
  Serial.println("Ende");
  delay(1000);        //es dauerhaft zu versenden mit Zeitabstand.
  Wire.endTransmission(8);
}

void sarr(byte led[8][8]) {
  byte return;
  for (byte x=0; x<4; x++)
    {
        for (byte y=0; y<8; y++)
        {
            return = Wire.write(led[y][x]);
            Serial.print(return);
        }
        Serial.println();
    }


Was ist den mit den internen PullUp Widerständen?

Stefanus F. schrieb:
> Anstatt hier so unterschwellig einen auf Oberlehrer zu machen, könntest
> du einen Blick in den Quelltext (Wire.c) werfen, der ist ja alles andere
> als geheim.

Das ist mir bewusst, jedoch sollte vielleicht der der das Problem hat da 
rein schauen dem hilft es mehr.

Welchen Zweck erfüllt das senden erst mit dem endTransmission?
Was wäre denn die bessere Strategie den Puffer zu nutzen?

Arduino Fanboy D. schrieb:
> Wire.write() stopft in den Buffer!
> Wire.endTransmission() sendet den Buffer.

Dann ist die Arduino Dokumentation falsch. Doof.

von Stefan F. (Gast)


Lesenswert?

Blabla schrieb:
> Was wäre denn die bessere Strategie den Puffer zu nutzen?

AUf solche Feinheiten darf man bei Arduino nicht achten. Das ist ein 
Quick&Dirty Framework, das nur einfachen Ansprüchen genügt. Mehr als die 
32 Bytes gehen halt nicht.

von Einer K. (Gast)


Lesenswert?

Blabla schrieb:
> Dann ist die Arduino Dokumentation falsch. Doof.

Nein ist sie nicht!

Siehe: https://www.arduino.cc/en/Reference/WireWrite
> Description
> Writes data from a slave device in response to a
> request from a master, or queues bytes for
> transmission from a master to slave device
> (in-between calls to beginTransmission() and endTransmission()).

Die Beschreibung ist korrekt!

von Stefan F. (Gast)


Lesenswert?

Es gibt Mikrocontroller, die nicht einzelne Bytes via I²C aneinander 
reihen können. So ist das z.B. beim STM32F103. Da muss man die letzten 
drei Bytes vor dem anders behandeln.

Es gibt vielleicht auch Mikrocontroller, wo das gesamte zu übertragende 
Paket an einem Stück vorliegen muss. Ich schätze, dass die Arduino 
Macher dabei Interrupt- oder DMA gesteuerte Übertragung als Möglichkeit 
offen lassen wollten.

Auf der einen Seite bemüht man sich bei Frameworks um Flexibilität, auf 
der anderen Seite muss man dazu woanders einschränken. Dieses Dilemma 
haben sehr viele Frameworks, weswegen ich sie kritisch betrachte. 
Frameworks bringen oft mehr Probleme als Nutzen.

von Einer K. (Gast)


Lesenswert?

Blabla schrieb:
> Was ist den mit den internen PullUp Widerständen?
Die ca 50K sind nicht ausreichend.
Manche Arduino Boards haben zusätzliche 10K drauf,
Auch das muss nicht reichen.

von Blabla (Gast)


Lesenswert?

??? Zumindest sind sie unpräzise..
Wire.write(x);              // sends one byte
Wire.endTransmission();    // stop transmitting

Arduino Fanboy D. schrieb:
> Blabla schrieb:
>> Was ist den mit den internen PullUp Widerständen?
> Die ca 50K sind nicht ausreichend.
> Manche Arduino Boards haben zusätzliche 10K drauf,
> Auch das muss nicht reichen.

Reichen? Wofür? Was sind deine bzw. gute Kriterien dafür?


Stefanus F. schrieb:
> Das ist ein
> Quick&Dirty Framework, das nur einfachen Ansprüchen genügt.

Sehe ich auch so.

Evtl eher so...
#include <Wire.h>

byte led[8][8] = {    //Array mit dem "Bild" aus Einsen.(Es ist ein 
Smiley)
  {1,1,1,1,1,1,1,1},
  {0,0,0,0,0,0,0,0},
  {0,0,1,0,0,1,0,0},
  {0,0,0,0,0,0,0,0},
  {0,0,0,1,1,0,0,0},
  {0,1,0,0,0,0,1,0},
  {0,0,1,1,1,1,0,0},
  {1,1,1,1,1,1,1,1}
};

void setup() {
  Serial.begin(9600);
  Wire.begin();
}

void loop() {
  Serial.println("Anfang");
  sarr(led);
  Serial.println("Ende");
  delay(1000);

}

void sarr(byte led[8][8]) {
  byte ret;
  Wire.beginTransmission(8);

  for (byte x=0; x<4; x++)
    {
        for (byte y=0; y<8; y++)
        {
            ret = Wire.write(led[y][x]);
            Serial.print(ret);
        }
        Serial.println();
    }
    Wire.endTransmission(8);
    Wire.beginTransmission(8);
    for (byte x=4; x<8; x++)
    {
        for (byte y=0; y<8; y++)
        {
            ret = Wire.write(led[y][x]);
            Serial.print(ret);
        }
        Serial.println();
    }
    Wire.endTransmission(8);
}

Das mit den schleifen hintereinander ist wirklich nicht schön.

von M. S. (marvs)


Lesenswert?

Stefanus F. schrieb:
> Ich würde das Senden mit zwei verschachtelten Schleifen machen:
>
>
1
> void sendarr(byte led[8][8])
2
> {
3
>     for (byte x=0; x<8; x++)
4
>     {
5
>         for (byte y=0; y<8; y++)
6
>         {
7
>             byte b=led[y][x];
8
>             Serial.print(b);
9
>         }
10
>         Serial.println();
11
>     }
12
> }
13
>

Ich habe den Code mal aufgespielt....

Das ist meine Ausgabe:

>01250818448184184
>017801841184184
>2551001961840184184
>2540016201840
>100121801841840
>0108018460
>0654305618470
>0080018470

... wie stelle ich das zu "0" u. "1" um?
Bin da jetzt etwas verwirrt. Wie kommt das zustande?
Die Variable "b" wird ja immer neu beschrieben, und es gibt nur
Zwei verschiedene Zahlen im Array... .


Mfg
MarvS

von Einer K. (Gast)


Lesenswert?

Blabla schrieb:
> Reichen? Wofür? Was sind deine bzw. gute Kriterien dafür?
Tja...
Die I2C Spezifikation als Richtwert.
Und Erfahrung.
Oszibilder zeigen dir das auch.
Musst nur hinschauen.

von M. S. (marvs)


Lesenswert?

Hallo,

Blabla schrieb:

> Evtl eher so...
> #include <Wire.h>
>
> byte led[8][8] = {    //Array mit dem "Bild" aus Einsen.(Es ist ein
> Smiley)
>   {1,1,1,1,1,1,1,1},
>   {0,0,0,0,0,0,0,0},
>   {0,0,1,0,0,1,0,0},
>   {0,0,0,0,0,0,0,0},
>   {0,0,0,1,1,0,0,0},
>   {0,1,0,0,0,0,1,0},
>   {0,0,1,1,1,1,0,0},
>   {1,1,1,1,1,1,1,1}
> };
>
> void setup() {
>   Serial.begin(9600);
>   Wire.begin();
> }
>
> void loop() {
>   Serial.println("Anfang");
>   sarr(led);
>   Serial.println("Ende");
>   delay(1000);
>
> }
>
> void sarr(byte led[8][8]) {
>   byte ret;
>   Wire.beginTransmission(8);
>
>   for (byte x=0; x<4; x++)
>     {
>         for (byte y=0; y<8; y++)
>         {
>             ret = Wire.write(led[y][x]);
>             Serial.print(ret);
>         }
>         Serial.println();
>     }
>     Wire.endTransmission(8);
>     Wire.beginTransmission(8);
>     for (byte x=4; x<8; x++)
>     {
>         for (byte y=0; y<8; y++)
>         {
>             ret = Wire.write(led[y][x]);
>             Serial.print(ret);
>         }
>         Serial.println();
>     }
>     Wire.endTransmission(8);
> }
>
> Das mit den schleifen hintereinander ist wirklich nicht schön.

Ich habe das jetzt aufgespielt und bekomme nur Einsen.

Die Ausgabe:
...
Anfang
11111111
11111111
11111111
11111111
11111111
11111111
11111111
11111111
Ende
Anfang
11111111
11111111
11111111
11111111
11111111
11111111
11111111
11111111
Ende
...

Versteh ich langsam das Programmieren nicht mehr oder habe ich ein 
Fehler wieder gemacht?
Ich habe den Code 1:1 aus deinem Beitrag übernommen.

Mfg
MarvS

: Bearbeitet durch User
von STK500-Besitzer (Gast)


Lesenswert?

M. S. schrieb:
> Ich habe das jetzt aufgespielt und bekomme nur Einsen.

Ist ja auch richtig.
Das laesst dir ja den Rueckgabewert der Funktion ausgeben.
Entweder bedeutet die 1 wahr, oder die Anzahl der uebertragenen Bytes
Das kann man anhand der Arduino-Doku herausfinden

von Blabla (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Tja...
> Die I2C Spezifikation als Richtwert.
> Und Erfahrung.
> Oszibilder zeigen dir das auch.
> Musst nur hinschauen.

Nee ich rechne, dann funktioniert es wie ich will.
Ach wenn es schon oft beantwortet wurde:
http://www.ti.com/lit/an/slva689/slva689.pdf

Egal..

M. S. schrieb:
> MarvS

Kannst du mal den ganzen Quellcode zeigen? Was übergibst du denn an die 
Funktion? Sieht mir aus als ob da was schief geht.


Nur Einsen ist super!
Es sind nicht die Daten an sich sondern die Anzahl an bytes die er je 
Aufruf von Wire.write in den Puffer geschrieben hat.

Das sollte interessanter werden:


void sarr(byte led[8][8]) {
  byte ret;
  Wire.beginTransmission(8);

  for (byte x=0; x<4; x++)
    {
        for (byte y=0; y<8; y++)
        {
            ret = Wire.write(led[y][x]);

        }
    }
    ret = Wire.endTransmission(8);
    Serial.println(ret);
    Wire.beginTransmission(8);
    for (byte x=4; x<8; x++)
    {
        for (byte y=0; y<8; y++)
        {
            ret = Wire.write(led[y][x]);
        }

    }
    ret = Wire.endTransmission(8);
    Serial.println(ret);
}

von Einer K. (Gast)


Lesenswert?

Blabla schrieb:
> Nee ich rechne, .....
Nein, tust du offensichtlich nicht!
Denn dann hättest du die recht unintelligente Frage mit den internen 
Pullup nicht stellen müssen.

von M. S. (marvs)


Lesenswert?

Hallo,

@ Blabla

naja, er übergibt das Array mit seinem Inhalt.
Die Einsen und Nullen sind ja der Witz dran. Die müssen rüber.
Eine Zwei macht überhaupt keinen Sinn.
Es MÜSSEN die EINSEN und NULLEN rüber kommen einfach.


Hier die Code wo er später drunter soll:
1
#include <Wire.h>                     
2
                                      
3
volatile int sendarray[8][8];         
4
                                      
5
byte led[8][8] = {                    
6
  {1,1,1,1,1,1,1,1},                  
7
  {0,0,0,0,0,0,0,0},                  
8
  {0,0,1,0,0,1,0,0},                  
9
  {0,0,0,0,0,0,0,0},                  
10
  {0,0,0,1,1,0,0,0},                  
11
  {0,1,0,0,0,0,l,0},                  
12
  {0,0,1,1,1,1,0,0},                  
13
  {1,1,1,1,1,1,1,1}                   
14
};                                    
15
                                      
16
byte ledp=0;                         
17
byte ledm=8;                 
18
byte x=0;                             
19
byte y=0;                             
20
                                      
21
void setup() {                        
22
  pinMode(0, OUTPUT);                
23
  pinMode(1, OUTPUT);                 
24
  pinMode(2, OUTPUT);                 
25
  pinMode(3, OUTPUT);                 
26
  pinMode(4, OUTPUT);                 
27
  pinMode(5, OUTPUT);                 
28
  pinMode(6, OUTPUT);                 
29
  pinMode(7, OUTPUT);                 
30
  pinMode(8, OUTPUT);                 
31
  pinMode(9, OUTPUT);                 
32
  pinMode(10, OUTPUT);                
33
  pinMode(11, OUTPUT);                
34
  pinMode(12, OUTPUT);                
35
  pinMode(13, OUTPUT);                
36
  pinMode(14, OUTPUT);                
37
  pinMode(15, OUTPUT);                
38
                                      
39
  //Serial.begin(9600);               
40
                                      
41
  Wire.begin(8);                      
42
  Wire.onReceive(getarray);   //Hier soll es passieren.           
43
}                                     
44
                                      
45
void loop() {                         
46
  //for (byte i=0; i<=64; i++) {      
47
      if (led[y][x]==1) {             
48
        setled(ledp, ledm);           
49
        delay(1);                     
50
        noled(ledp, ledm);            
51
      }                               
52
                                      
53
      if (led[y][x]==0) {             
54
        noled(ledp, ledm);            
55
      }                               
56
                                        
57
      x++;                            
58
      ledp++;                         
59
                                      
60
      if (x==8) {                     
61
        x=0;                          
62
        y++;                          
63
        ledp=0;                       
64
        ledm++;                       
65
      }                               
66
                                      
67
      if (y==8) {                     
68
        x=0;                          
69
        y=0;                          
70
        ledp=0;                       
71
        ledm=8;                       
72
      }                               
73
    //}                               
74
                                      
75
    //Serial.print("ledp: ");         
76
    //Serial.println(ledp);           
77
                                      
78
    //Serial.print("ledm: ");         
79
    //Serial.println(ledm);           
80
    //Serial.print("x: ");            
81
    //Serial.println(x);              
82
    //Serial.print("y: ");            
83
    //Serial.println(y);              
84
    //delay(100);                     
85
                                      
86
}                                     
87
void setled(byte ledp, byte ledm) {   
88
  digitalWrite(ledp, HIGH);          
89
  digitalWrite(ledm, LOW);            
90
}                                       
91
void noled(byte ledp, byte ledm) {    
92
  digitalWrite(ledp, LOW);            
93
  digitalWrite(ledm, HIGH);           
94
}
95
96
void getarray(byte led[8][8]) {    //Hier die leere Funktion.
97
                                   //Das Sorgenkind das ich mein eigen
98
                                   //nennen darf.
99
}



Dies ist der Code wo das Array später rein soll.

Mir ist vollkommen bewusst das es andere Wege gibt. Ich habe diesen 
Gewählt. Der Code läuft einwandfrei und zeigt auch das was ich will.
Unter der Funktion "noled()" soll die Funktion "getarray()" kommen.

Aufgrund der Uhrzeit und der Tatsache das ich Schlafmangel habe:
Vielen Dank schonmal für diese Hilfe von diesen abend ....dieser 
Nacht??...
Danke.

Morgen werde ich weiter suchen und mir die "Wire.h" Lib. durchlesen. 
Genauer.

NAbnd.

Mfg
MarvS

von Blabla (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Denn dann hättest du die recht unintelligente Frage mit den internen
> Pullup nicht stellen müssen.

Der war gut. Dann berechne mir doch bitte die Kapazität der Leitungen im 
verwendeten Aufbau, dann rechne ich dir den Widerstand aus ;-)

Auf welcher Seite des Datenblattes steht den der Wert des internen 
Pullup und lassen sie sich bei Verwendung der I2C Schnitstelle nutzen? 
Auch im Zusammenhang mit der verwendeten Bibliothek?

Spass bei Seite. Die frage wollte ich nicht ernsthaft beantwortet haben. 
Es geht mir eher darum Denkanstöße zu geben. Ich halte in der Regel 
recht wenig davon einfach fertige Lösungen hinzu pappen.


Hey MarvS,

für mich beginnt das Sorgenkind schon weiter oben aber das ist 
Geschmackssache.

Hier nochmal die Sendeseite zum Verständnis.
1
#include <Wire.h>
2
3
byte led[8][8] = {    //Array mit dem "Bild" aus Einsen.(Es ist ein Smiley)                
4
  {1,1,1,1,1,1,1,1},                  
5
  {0,0,0,0,0,0,0,0},                  
6
  {0,0,1,0,0,1,0,0},                  
7
  {0,0,0,0,0,0,0,0},                 
8
  {0,0,0,1,1,0,0,0},                 
9
  {0,1,0,0,0,0,1,0},                 
10
  {0,0,1,1,1,1,0,0},                  
11
  {1,1,1,1,1,1,1,1}                   
12
};  
13
14
void setup() {
15
  Serial.begin(9600);
16
  Wire.begin();
17
}
18
19
void loop() {
20
  Serial.println("Anfang");
21
  sarr(led);
22
  Serial.println("Ende");     
23
  delay(1000);    
24
25
}
26
//Prints the return values
27
/*  
28
 * Output   0 .. success
29
 *          1 .. length to long for buffer
30
 *          2 .. address send, NACK received
31
 *          3 .. data send, NACK received
32
 *          4 .. other twi error (lost bus arbitration, bus error, ..)
33
 */
34
void sarr(byte led[8][8]) {
35
  byte ret;
36
  Wire.beginTransmission(8);
37
38
  for (byte x=0; x<4; x++)
39
    {
40
        for (byte y=0; y<8; y++)
41
        {
42
            Wire.write(led[y][x]);
43
        }
44
    }
45
    ret = Wire.endTransmission(8);
46
    Serial.println(ret);
47
    Wire.beginTransmission(8);
48
    for (byte x=4; x<8; x++)
49
    {
50
        for (byte y=0; y<8; y++)
51
        {
52
            Wire.write(led[y][x]);
53
        }
54
55
    }
56
    ret = Wire.endTransmission(8);
57
    Serial.println(ret);
58
}
59
60
//Prints the actuall values
61
void sarrV(byte led[8][8]) {
62
  byte ret;
63
  Wire.beginTransmission(8);
64
65
  for (byte x=0; x<4; x++)
66
    {
67
        for (byte y=0; y<8; y++)
68
        {
69
            Wire.write(led[y][x]);
70
            Serial.print(led[y][x]);
71
        }
72
        Serial.println();
73
    }
74
    Wire.endTransmission(8);
75
    Wire.beginTransmission(8);
76
    for (byte x=4; x<8; x++)
77
    {
78
        for (byte y=0; y<8; y++)
79
        {
80
            Wire.write(led[y][x]);
81
            Serial.print(led[y][x]);
82
        }
83
        Serial.println();
84
    }
85
}

Ungetestet!
1
#include <Wire.h>
2
3
void setup() {
4
  Wire.begin(8);                // join i2c bus with address #8
5
  Wire.onReceive(receiveEvent); // register event
6
  Serial.begin(9600);           // start serial for output
7
}
8
9
void loop() {
10
  delay(100);
11
}
12
13
// function that executes whenever data is received from master
14
// this function is registered as an event, see setup()
15
void receiveEvent(int howMany) {
16
  while (Wire.available()) { // loop through all but the last
17
    char c = Wire.read(); // receive byte as a character
18
    Serial.print(c);         // print the character
19
  }
20
}

Jetzt müssen die Daten nur noch richtig einsortiert werde. Hoffentlich 
;-)

von Stefan F. (Gast)


Lesenswert?

M. S. schrieb:
> Das ist meine Ausgabe:
>
>01250818448184184
>017801841184184
>2551001961840184184
>2540016201840
>100121801841840
>0108018460
>0654305618470
>0080018470
>
> Bin da jetzt etwas verwirrt. Wie kommt das zustande?

Ich auch.

Blabla schrieb:
> Kannst du mal den ganzen Quellcode zeigen? Was übergibst du denn an die
> Funktion? Sieht mir aus als ob da was schief geht.

Ja bitte, ohne den ganzen Quelltext kann ich mir auch auf dieses 
seltsame Ergebnis keinen Reim machen.

von Einer K. (Gast)


Lesenswert?

> ret = Wire.endTransmission(8);

KA, wer, aber hier hat wieder jemand die Doku nicht gelesen.

Denn Wire.endTransmission() erwartet keine Adresse als Parameter, 
sondern ein Flag, ob eine Stop Condition gesendet werden soll.
Default, ist true
Die 8 wird beim impliziten Cast zu true.

> ret = Wire.endTransmission(8);
ist also nicht unbedingt ein Fehler, aber dennoch irreführend/unsinnig.

Besser
> ret = Wire.endTransmission(true);

oder ausreichend:
> ret = Wire.endTransmission();


Hier könnte man beim ersten Datenblock  Wire.endTransmission(false) 
verwenden, damit einem kein zweiter Master dazwischen funken kann, und 
beim Zweiten dann Wire.endTransmission().

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


Dieses ist eine sehr problematische Idee:

Blabla schrieb:
> void receiveEvent(int howMany) {
>   while (Wire.available()) { // loop through all but the last
>     char c = Wire.read(); // receive byte as a character
>     Serial.print(c);         // print the character
>   }
> }

Hier besteht das Problem, dass receiveEvent() im ISR Kontext aufgerufen 
wird und Serial seinerseits Interrupts benötigt.
Das wird sich verklemmen, sobald der Tx Buffer voll ist,

von M. S. (marvs)


Lesenswert?

Stefanus F. schrieb:
> M. S. schrieb:
>> Das ist meine Ausgabe:
>>
>>01250818448184184
>>017801841184184
>>2551001961840184184
>>2540016201840
>>100121801841840
>>0108018460
>>0654305618470
>>0080018470
>>
>> Bin da jetzt etwas verwirrt. Wie kommt das zustande?
>
> Ich auch.

Das kam raus. Ich kann es nicht nachvollziehen im Code. Es sollte immer 
umgeschreiben werden, machen tut er was anderes.


> Blabla schrieb:
>> Kannst du mal den ganzen Quellcode zeigen? Was übergibst du denn an die
>> Funktion? Sieht mir aus als ob da was schief geht.
>
> Ja bitte, ohne den ganzen Quelltext kann ich mir auch auf dieses
> seltsame Ergebnis keinen Reim machen.

Den Quellcode für die Ansteuerung ist da und das komplett.
Der Quellcode für den Sender des Arrays.... naja.
Wenn der laufen würde, wäre er schon drin. Bis jetzt besteht die
"aufgeräumte" Variante nur darin, auf alle Sieben Taster ein Ton 
abzugeben
und zu zeigen im Monitor, welcher es war.

Mfg
MarvS

von M. S. (marvs)


Lesenswert?

Hallo,

Arduino Fanboy D. schrieb:
> Dieses ist eine sehr problematische Idee:
>
>> Blabla schrieb:
>> void receiveEvent(int howMany) {
>>   while (Wire.available()) { // loop through all but the last
>>     char c = Wire.read(); // receive byte as a character
>>     Serial.print(c);         // print the character
>>   }
>> }
>
> Hier besteht das Problem, dass receiveEvent() im ISR Kontext aufgerufen
> wird und Serial seinerseits Interrupts benötigt.
> Das wird sich verklemmen, sobald der Tx Buffer voll ist,

Im späteren Code ist sowieso kein Serial mehr drin. Deshalb mache ich 
mir da keinen Kopf drum.

Der "Slave" liest es und hält es, dass macht der solange, bis ein neues 
kommt.

Mfg
MarvS

von M. S. (marvs)


Lesenswert?

Hallo,

kann es sein, dass die Probleme teilwese von meinen Funktionen kommen,
weil diese "void" haben?

> https://www.arduino.cc/en/Reference/FunctionDeclaration

Ich meine, ich will ja was haben, also muss ich das auch deklarieren, 
oder?
Sowas wie "byte getarr(byte y, byte x) { }" gibt mir ja dann als byte 
etwas,
"void" hingegen gibt ja nichts.

Mfg

MarvS

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Ich glaube, bis jetzt weißt nur du, was dein getarr() tun soll.
Also: Keine Antwort von mir.


Ausführliche Fehlermeldungen(Alle) aktiviert?
Datei --> Einstellungen

von M. S. (marvs)


Lesenswert?

Hallo,

Arduino Fanboy D. schrieb:
> Ich glaube, bis jetzt weißt nur du, was dein getarr() tun soll.
> Also: Keine Antwort von mir.

Ja es soll wie der Name sagt, das Array entgegennehmen.
Das "sarr()" steht für sendArray. Es soll es versenden.


> Ausführliche Fehlermeldungen(Alle) aktiviert?
> Datei --> Einstellungen

Habe ich eingestellt.

Mfg
MarvS

von Peter D. (peda)


Lesenswert?

M. S. schrieb:
> Ja es soll wie der Name sagt ...

Mach den letzten kompletten Stand in ein Zip und häng es an.
Sonst weiß niemand, wovon Du sprichst.

von M. S. (marvs)


Angehängte Dateien:

Lesenswert?

Hallo,

Peter D. schrieb:
> Mach den letzten kompletten Stand in ein Zip und häng es an.
> Sonst weiß niemand, wovon Du sprichst.

Der "Master" ist unfertig. bitte beachten.
Ansonsten hoffe ich das der Code vom "slave" verständlich ist. Ich habe 
den
mal komplett kommentiert.

Mfg
MarvS

von M. S. (marvs)


Lesenswert?

Hallo,

Stefanus F. schrieb:
> M. S. schrieb:
>> Auf die Widerstände habe ich verzichtet.
>
> Die sind aber notwendig.
>
> Ich teste I²C gerne mit niedrigen Bitraten und LED's. Dann sieht man sie
> flackern - oder auch nicht. Und man sieht an Dauerleuchten auch, wenn
> der Bus hängt.
>
>
1
> 
2
>             4,7k Pull-Up
3
> SDA o---+------[===]------+-----o 5V
4
>         |                 |
5
>         +---[===]---|<|---+
6
>             2,2k    LED
7
>
>
> Und das gleiche nochmal für SCL.

Ich habe nun mir etwas zusammengelötet das diesem nun nachgeht.

Funktioniert top.

Mfg
MarvS

von foobar (Gast)


Lesenswert?

Da die API anscheinend keine so großen Pakete verschicken kann, muß man 
entweder die Daten komprimieren oder bröckchenweise verschicken. Es 
bietet sich an, diese Zeilenweise zu übertragen.  Damit der Empfänger 
nicht durcheinanderkommt, wird als erstes Byte die Zeilennummer 
übertragen.

Hier mal Quick-n-Dirty runtergeschrieben:
1
#define L       8
2
#define C       8
3
uint8_t array[L][C];
4
5
void sendline(uint8_t l)
6
{
7
    Wire.beginTransmission(8);
8
    Wire.write(l);
9
    for (uint8_t i = 0; i < C; ++i)
10
        Wire.write(array[l][i]);
11
    Wire.endTransmission();
12
}
13
14
void sendarray()
15
{
16
    for (uint8_t i = 0; i < L; ++i)
17
        sendline(i);
18
}   
19
20
void onReceive(size_t n)
21
{   
22
    if (n == C+1)
23
    {   
24
        uint8_t l = Wire.read();
25
        if (l < L)
26
            for (uint8_t i = 0; i < C; ++i)
27
                array[l][i] = Wire.read();
28
    }
29
}

von M. S. (marvs)


Lesenswert?

Hallo,

foobar schrieb:
> Da die API anscheinend keine so großen Pakete verschicken kann, muß man
> entweder die Daten komprimieren oder bröckchenweise verschicken. Es
> bietet sich an, diese Zeilenweise zu übertragen.  Damit der Empfänger
> nicht durcheinanderkommt, wird als erstes Byte die Zeilennummer
> übertragen.
>
> Hier mal Quick-n-Dirty runtergeschrieben:
>
1
> #define L       8
2
> #define C       8
3
> uint8_t array[L][C];
4
> 
5
> void sendline(uint8_t l)
6
> {
7
>     Wire.beginTransmission(8);
8
>     Wire.write(l);
9
>     for (uint8_t i = 0; i < C; ++i)
10
>         Wire.write(array[l][i]);
11
>     Wire.endTransmission();
12
> }
13
> 
14
> void sendarray()
15
> {
16
>     for (uint8_t i = 0; i < L; ++i)
17
>         sendline(i);
18
> }
19
> 
20
> void onReceive(size_t n)
21
> {
22
>     if (n == C+1)
23
>     {
24
>         uint8_t l = Wire.read();
25
>         if (l < L)
26
>             for (uint8_t i = 0; i < C; ++i)
27
>                 array[l][i] = Wire.read();
28
>     }
29
> }
30
>

Bei dem Code habe ich ein paar Fragen:
Du verwendest diesen ...byte...(unitn8_t) in verbindung von 
"array{L][C]".
Was passiert damit?

(Ich habe unint8_t noch nie verwnedet und weiss daher nur minimal 
bescheit darüber.)

Lässt sich der Inhalt leicht verändern?

Und wieso "L" und "C" definieren?


Mfg
MarvS

von Stefan F. (Gast)


Lesenswert?

uint8_t = byte = unsigned char

uint8_t ist die offizielle Schreibweise seit einer gefühlten Ewigkeit.

byte ist ein Alias von Arduino - die finden das wohl genau so hilfreich, 
wie ihr eigenes Vokabular.

von foobar (Gast)


Lesenswert?

uint8_t ist die Ansi-Version eines Bytes - kannst du auch gerne was 
anderes nehmen. Die Konstanten L und C sind einfach die Anzahl Zeilen 
(Lines) und Spalten (Columns) deines Arrays - es ist üblich, solche 
Konstanten einmal im Programm zu definieren.

von M. S. (marvs)


Lesenswert?

Hallo,

Stefanus F. schrieb:
> uint8_t = byte = unsigned char
>
> uint8_t ist die offizielle Schreibweise seit einer gefühlten Ewigkeit.
>
> byte ist ein Alias von Arduino - die finden das wohl genau so hilfreich,
> wie ihr eigenes Vokabular.

Wenn es die von Arduino lustig macht.... dadann.

Mfg
MarvS

von M. S. (marvs)


Lesenswert?

Hallo,

foobar schrieb:
> uint8_t ist die Ansi-Version eines Bytes - kannst du auch gerne was
> anderes nehmen. Die Konstanten L und C sind einfach die Anzahl Zeilen
> (Lines) und Spalten (Columns) deines Arrays - es ist üblich, solche
> Konstanten einmal im Programm zu definieren.

Kann man damit dann auch das Programm kleiner machen?
Ansonsten habe ich bis heute keine Anwendung dafür gehabt.

Mfg
MarvS

von Stefan F. (Gast)


Lesenswert?

M. S. schrieb:
> Kann man damit dann auch das Programm kleiner machen?

Bytes sind kleiner als int und #defines sind Textersetzungen, die vor 
dem Compilieren angewendet werden. Diese werden beim Compilieren teil 
des Programmcodes (Flash-Speicher).

Im Gegensatz dazu liegen konstante Variablen wie:

const byte x=123;

bei AVR Controllern im RAM.

von pop (Gast)


Lesenswert?

M. S. schrieb:
> Kann man damit dann auch das Programm kleiner machen?

Bitte korrigiert mich, aber rechnet Arduino nicht standardmäßig mit 
int16_t ?

Auf einem 8bit MCU wie dem AVR macht es aus Effizienzgründen sinn wo es 
möglich ist mit 8Bit langen zahlen zu rechnen. Außerdem spart das Ram.


Elektro Heini schrieb:
> byte led[8] = {
>   0b11111111,
>   0b00000000,
>   0b00100100,
>   0b00000000,
>   0b00011000,
>   0b01000010,
>   0b00111100,
>   0b11111111
> };

Da du ein 8x8 array aus Nullen und Einsen übertragen möchtest, ist dies 
die effizienteste möglichkeit, die sowohl Ram als auch Übertragungszeit 
spart! solltest du auf das Arduino Framework an dieser Stelle 
verzichten, könntest du so auch die empfangenen Werte direkt auf einen 
(freien) Port legen.

von Einer K. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Im Gegensatz dazu liegen konstante Variablen wie:
>
> const byte x=123;
>
> bei AVR Controllern im RAM.

Nöö...
Eher selten.
Nur, wenn es mit der Optimierung gar nicht klappen will, weil z.B. in 
einer anderen Übersetzungseinheit definiert (und als extern deklariert).

von Stefan F. (Gast)


Lesenswert?

pop schrieb:
> Bitte korrigiert mich, aber rechnet Arduino nicht standardmäßig mit
> int16_t ?

Ich formuliere es mal so: Der Datentyp int ist 16 bit gross. Ob du den 
standardmässig verwendest, bleibt Dir überlassen.

von Stefan F. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Im Gegensatz dazu liegen konstante Variablen wie:
>
> const byte x=123;
>
> bei AVR Controllern im RAM.

Arduino Fanboy D. schrieb:
> Nur, wenn es mit der Optimierung gar nicht klappen will, weil z.B. in
> einer anderen Übersetzungseinheit definiert (und als extern deklariert).

Ich habe es gerade ausprobiert - scheinbar hast du Recht. Es wird sogar 
bei Zeichenketten gut optimiert. Beide Varianten belegen laut Compiler 
Ausgabe gleich viel RAM:
1
void setup() {}
2
3
//const char s[]="Hallo";
4
#define s "Hallo"
5
6
void loop() {
7
  Serial.println(s);
8
}

Beide Verianten lassen 1854 Bytes RAM übrig.

Jetzt wird es komisch:
1
void setup() {}
2
3
char s[]="Hallo";
4
5
void loop() {
6
  s[0]=0;
7
  Serial.println(s);
8
}

Auch dieser Programm lässt 1854 Bytes übrig, das kann aber nicht stimmen 
oder?

Ich habe es so in Erinnerung, das einem besonders bei String Literalen 
schnell das RAM ausgeht. Dazu gibt es diese Anleitung: 
https://playground.arduino.cc/learning/memory

Warum empfehlen die dort PROGMEM und F() obwohl const einfacher ist?

Auch hier schreiben mehrere Leute, dass Konstante Strings im RAM liegen: 
https://forum.arduino.cc/index.php?topic=79436.0

Jetzt bin ich verwirrt.

von Einer K. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Warum empfehlen die dort PROGMEM und F() obwohl const einfacher ist?

Bei Strings klappt das nicht so gut.
Darum F() usw.

Stefanus F. schrieb:
> Beide Varianten belegen laut Compiler
> Ausgabe gleich viel RAM:
1
Das wundert mich nicht!
2
void setup() {}
3
4
//const char s[]="Hallo";
5
#define s "Hallo"
6
7
void loop() {
8
  Serial.println(F(s)); // braucht weniger Ram
9
}

von Stefan F. (Gast)


Lesenswert?

Ach so, das passt hierzu:
1
void setup() {}
2
3
//char s[]="Halloxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
4
5
//const char s[]="Halloxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
6
7
//#define s "Halloxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
8
9
const char PROGMEM s[]="Halloxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
10
  
11
void loop() {
12
  Serial.println(s);
13
}

Alle auskommentierten Varianten belegen deutlich viel RAM. Nur die 
letzte Variante spart Speicher.

Werden denn nur Zeichenketten ins RAM kopiert, einfache numerische 
Variablen aber nicht?

von Einer K. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Werden denn nur Zeichenketten ins RAM kopiert,

Zeichenketten werden über Pointer manipuliert.
Dazu müssen die Ketten im Ram liegen.
Alles andere wäre ineffektiv bis unmöglich.


Stefanus F. schrieb:
> einfache numerische Variablen aber nicht?

Wenn sie als konstant deklariert sind, kann der Kompiler sie direkt in 
die ASM Statements einflechten. So landen sie um Code, im Flash.
Darum brauchen sie keine Repräsentation im Ram.
Sobald du einen Pointer darauf richtest, ist Schluss damit.

von leo (Gast)


Lesenswert?

M. S. schrieb:
> Kann man damit dann auch das Programm kleiner machen?

Du gehst das vollkommen verkehrt an, Stichwort "premature optimization". 
Hier snd die bestehenden Probleme (Stand dein rar-Archiv):

1) Generell:
- du zeigst kein Konzept/Skizze/Schaltplan
- du sprichst von "stark beschäftigt". Ich sehe in deinem Code 
keinerweise irgendeine Auslastung von CPU(s). Ev. sprichst du von einem 
Mangel an IO-Pins. Da scheint der Einsatz von Multiplexern einfacher zu 
sein, als ein Master/Slave I2C Einsatz.

2) Master:
- Verwende 8 x Bytes statt 64 x Bits, die du aufteilen musst um diese 
per TWI/I2C zu verarbeiten.
- Deine Schleifen sind immer noch Off-by-one.
- du kannst nicht 64/81 Byte am Stueck per I2c mit der Wire-Lib 
verarbeiten.

3) Slave:
- kompiliert nicht einmal - der onReceive()-Handler ist falsch 
deklariert, usw.
- die 2 Arrays sind zumindest tw. ueberfluessig
- deine pinModes gehoeren in eine Schleife
- der Anzeigecode ist unverstaendlich - delay(1) dort sicher falsch

Die meisten Tipps wurden dir schon gesagt.
wenn obiges mal geloest ist, kannst du Optimierungen angehen, falls 
noetig.

HTH, leo

von Stefan F. (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Sobald du einen Pointer darauf richtest, ist Schluss damit.

Danke für deine Erklärung.

von mIstA (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Sobald du einen Pointer darauf richtest, ist Schluss damit.

Bist Du sicher, daß schon das darauf richten eines Pointers damit 
definitiv Schluß macht?

Denn wenn der Pointer nie dereferenziert wird, könnte der Compiler ihn 
schließlich auch kurz und schmerzlos wegoptimieren.

von Stefan F. (Gast)


Lesenswert?

mIstA schrieb:
> Bist Du sicher, daß schon das darauf richten eines Pointers damit
> definitiv Schluß macht?
>
> Denn wenn der Pointer nie dereferenziert wird, könnte der Compiler ihn
> schließlich auch kurz und schmerzlos wegoptimieren.

Ich denke dass er nur Pointer meint, die tatsächlich verwendet werden.

von Peter D. (peda)


Lesenswert?

Ich verstehe immer noch nicht, warum man unbedingt 64 Byte senden muß 
für real 8 Byte Daten. Das mach doch alles nur unnötig kompliziert.

von Dirk B. (dirkb2)


Lesenswert?

Peter D. schrieb:
> Das mach doch alles nur unnötig kompliziert.

Naja, man muss hinterher die Bits wieder auseinander dröseln.
Das ist füe einige auch nicht einfach.

Zudem ist es doch auch gut, das Sendeproblem mit den 64 Byte zu lösen.
Kann man später auch noch gebrauchen.

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.