Comunicazione seriale

Salve a tutti sono ancora io! :stuck_out_tongue:
Volevo verificare un dubbio che mi è venuto sulla comunicazione seriale. Come ho già scritto in un precedente post sto costruendo un cubo led 8x8x8. Per comandare l’accensione diretta dei led uso arduino, mentre per decidere quali led utilizzare uso un programma in c# scritto da me. Tramite quest’ultimo io ho la possibilità di creare le animazioni grazie all’interfaccia grafica. In particolare creo frame per frame e li concateno uno dietro all’altro per poi salvarli in un file. In sostanza l’idea era quella di passare un frame per volta ad arduino in modo che lui lo accendesse. Io passo quindi una riga per volta (8 byte) di una matrice tridimensionale che rappresenta appunto il mio frame. Il codice del ciclo è qualcosa de tipo:

for (z = 0; z < 8; z++)
{
       for (y = 0; y < 8; y++)
        {
                 for (x = 0; x < 8; x++)
                 {
                  //Scrivi un byte 
                  }
        }
}

Di seguito io gli faccio aspettare un tempo che è il prodotto del tempo che arduino ci mette ad accendere per una volta tutti i piani (considerando che accendo un solo piano per volta) e il numero di volte che deve ripetere tale accensione in modo da far si che si possa vedere anche ad occhio nudo. In particolare il numero di volte dipenderà da un valore che passo precendentemente.
Il programma “lato arduino” sarà invece questo:

void loop()
{
  byte leggi = 0;
  while(Serial.available())
  {
    //Legge per prima cosa il numero di frame in modo da sapere il numero di cicli che deve fare
    if(nframe == 0)
    {
      nframe = Serial.read();
    }
    //Se si tratta degli stati dei led allora li aggiunge alla matrice
    else
    {
      //Legge la durata del frame
      Freq = Serial.read();
      //Legge un byte per volta e lo mette nella matrice di byte
      for(int z = 0; z < 8; z++)
      {
        for(int y = 0; y < 8; y++)
        {
          for(int x = 0; x < 8; x++)
          {
            Mat[x][y][z] = Serial.read();
          }
        }
      }
      //Freq è il parametro, passato anch'esso da seriale, che stabilisce quanto un frame deve "rimanere" acceso
      //così facendo la frequenza di aggiornamento dei frame di un'animazione non sarà costante.
      //Freq indica quindi il numero di cicli da eseguire
      for(int i = 0; i < Freq; i++) Accendi(Mat);
    }
  }
}

La mia domanda è: c’è un modo per essere sicuri che ogni volta che il programma in c# scrive quello su arduino legga? Voglio dire così come l’ho impostato dovrebbero essere già sincronizzati nella scrittura/lettura i due programmi?

Ti conviene usare la EasyTransfert e trasferisci in blocco la matrice senza impazzire con protocolli di trasmissione.
--> EasyTransfer Arduino Library « The Mind of Bill Porter
--> GitHub - madsci1016/Arduino-EasyTransfer: An Easy way to Transfer data between Arduinos

Se vuoi avere una visualizzazione in tempo reale ti conviene passare le varie righe con dei byte iniziali che definiscono la posizione.
Cosi leggendoli sai dove collocarli nella matrice.
Ti conviene aggiungere anche un carattere di stop.

PaoloP:
Se vuoi avere una visualizzazione in tempo reale ti conviene passare le varie righe con dei byte iniziali che definiscono la posizione.
Cosi leggendoli sai dove collocarli nella matrice.
Ti conviene aggiungere anche un carattere di stop.

Ma non si riesce anche senza? Se non ho capito male la seriale si comporta come una coda, ogni volta che scrivi qualcosa lo si accoda al resto già scritto. Così facendo nel buffer della seriale di arduino i byte saranno già in ordine, basterà leggerne uno per volta con un ciclo uguale a quello usato in c# no? Se proprio proprio potrei provare a diminuire il tempo di scrittura del c# e quindi accodare più velocemente senza rischiare che l'attesa di tempi vuoti
P.S. Ditemi se sbaglio nel ragionamento

Sai quanto grande é un array
Mat[8][8][8] ?
e che Arduino UNO ha 2kByte di RAM.

Perché trasmetti 512 Byte se bastano 64 Byte (64 * 8bit) per sapere se ogni singolo LED é acceso o spento?

perché trasmetti la frequenza dei Frame? non puoi andare in multiplexing con una frequenza fissa?

Ciao Uwe

Scusa ma come fai ad indicare lo stato di ogni led del cubo che sono 512 con solo 64 byte? Per quanto riguarda le frequenze era semplicemente per un fatto di effetto visivo niente di più. Quello di cui volevo essere sicuro era se il mio ragionamento precedentemente esposto era corretto

Scusa ma come fai ad indicare lo stato di ogni led del cubo che sono 512 con solo 64 byte?

ogni Shift Register ha un bit che controlla un Led. quindi con un Byte ne controlli 8 ( di Led )
hai 8 shift register…

Ah ho capito in che modo intendete, io in effetti utilizzavo un byte per definire uno stato di un led.. Ma non funzionerebbe anche nel modo che ho fatto io in ogni caso?

ClapClap:
Ah ho capito in che modo intendete, io in effetti utilizzavo un byte per definire uno stato di un led.. Ma non funzionerebbe anche nel modo che ho fatto io in ogni caso?

Probabilmente no, perché consumi troppa RAM.
Ciao Uwe

Nel caso io andassi a gestire i singoli bit però dovrebbe andare giusto?

Edit: Con un codice del genere su arduino funzionerebbe?

int regclr = 3;
int clk = 2;

int reg[8] = {4, 5, 6, 7, 8, 9, 10, 11};

byte Mat[8][8];

int tr[8] = {12, 13, A0, A1, A2, A3, A4, A5} ;
int nframe = 0;
byte Freq;


void setup()
{
	for(int i = 0; i < 8; i++)
	{
		pinMode(reg[i],OUTPUT);
	}
	pinMode(regclr, OUTPUT);
	pinMode(clk, OUTPUT);
	
	for(int i = 0; i < 8; i++)
	{
		pinMode(tr[i],OUTPUT);
	}
        Serial.begin(9600);
        nframe = 0;
}


void AccendiPiano(byte Mat[][8])
{
  for(int z = 0; z < 8; z++)
  {
    digitalWrite(regclr,HIGH);
    for(int y = 0; y < 8; y++)
    {
      for(int x = 0; x < 8; x++)
      {
        if(bitRead(Mat[y][z],x) == 1)
        {
          digitalWrite(clk,LOW);
          digitalWrite(reg[y],HIGH);
          delayMicroseconds(100);
          digitalWrite(clk,HIGH);
          delayMicroseconds(100);
        }
        else if(bitRead(Mat[y][z],x) == 0)
        {
          digitalWrite(clk,LOW);
          digitalWrite(reg[y],LOW);
          delayMicroseconds(100);
          digitalWrite(clk,HIGH);
          delayMicroseconds(100);
        }
      }
    }
    digitalWrite(tr[z],HIGH);
    delay(1);
    digitalWrite(tr[z],LOW);
    digitalWrite(regclr,LOW);
  }
}
	

void loop()
{
  byte leggi = 0;
  while(Serial.available())
  {
    if(nframe == 0)
    {
      nframe = Serial.read();
    }
    else
    {
      Freq = Serial.read();
      for(int z = 0; z < 8; z++)
      {
        for(int y = 0; y < 8; y++)
        {
          leggi = Serial.read();
          for(int x = 0; x < 8; x++)
          {
            if(bitRead(leggi,x) == 1) bitSet(Mat[y][z],x);
            else bitClear(Mat[y][z],x);
          }
        }
      }
      for(int i = 0; i < Freq; i++) AccendiPiano(Mat);
    }
  }
}