Go Down

Topic: [RISOLTO]Creare Matrici di bit x Immagini B/W (Read 14861 times) previous topic - next topic

Deltoz

#30
Mar 12, 2014, 12:55 am Last Edit: Mar 12, 2014, 12:57 am by Deltoz Reason: 1
Esatto, hai capito perfettamente.
Tutta il calcolo lo faccio con una mia funzione che richiamo per tracciare la linea, ma il calcolo del seno e coseno lo faccio una sola volta, poi per "l" volte traccio il pixel moltiplicato per il teta ottenuto. In questo modo ho le coordinate di tutti i pixel che compongono la linea e posso confrontarli con lo sfondo. Altre soluzioni (a parte interrogare direttamente il display) non ne vedo.
Per quanto riguarda l' assorbimento, si ne sono consapevole, ma stiamo parlando di tracciare una linea su un display cha ha una risoluzione molto bassa, quindi l' assorbimento che effettua il display e' gia' di gran lunga superiore al calcolo che io faccio, qindi non mi preoccupa.
L' unica mia preoccupazione e' la velocita' di esecuzione, ma dalle prove che sto facendo (guarda l' orario...e non ho finito  :smiley-sleep:) sembra accettabile. Ora provo con 4 manometri contemporaneamente.
A lavoro finito (spero domani) posto il codice delle funzioni che ho creato, cosi' puoi visionarle.

Deltoz

Eccomi qua. Ecco il lavoro semifinito da ultimare e affinare.
Secondo voi e' ottimizzabile in termini di tempo di computazione?

Questa e' la funzione che mi restituisce il valore del bit richiesto all' interno del mapper:
Code: [Select]
boolean pixel_in_image(byte x,byte y, word larghezza, byte dimcella,const byte mapper[]){ //restituisce come risultato il valore del bit alle coordinate date
                                                               //alla funzione vengono passate le coordinate xy,la largherra dell' immagine e la dimensione delle celle
  static boolean esiste;                                              //per sapere se il pixel e' gia' esistente True
  static word cella,miobit;
  static byte resto,val;
  miobit=(y*larghezza)+x;                                      //n di bit corrispondente alle coordinate date
  cella=miobit/dimcella;                                       //numero progressibo del Byte, numero di cella
  val = pgm_read_byte_near(mapper + cella);                       //valore della cella letta all' interno del mapper
  resto=map(miobit%dimcella,0,7,7,0);                          //numero del bit nella cella (lo inverto perche' il primo bit e' quello a sx ed ed e' il piu' significante (7)
  esiste=bitRead(val,resto);                                   // e' il valore booleano del bit richiesto all' interno della cella
  return esiste;



Questa e' la funzione che mi visualizza l' intera immagine sul display alle coordinate date:
Code: [Select]
void visualizzamanometro(word fromx, word fromy, word larghezza, word altezza, byte dimcella){ 
                        //visualizza l' immagine partendo dal punto XY sul dispay(alto sx), gli vengono passate anche le misure dell' immagine e le dimensioni della cella
  boolean pixel;
  word i,j;
  myGLCD.setColor(coloremanometro);                //setta il colore scelto per il manometro
  for (i=0;i<altezza;i++){                        //per tutta l' altezza dell' immagine
    for (j=0;j<larghezza;j++){                     //per tutta la larghezza dell' immagine
      pixel=pixel_in_image(j,i,larghezza,dimcella,immagine);        //ricavo il pixel desiderato all' interno dell' immagine
      if (pixel==true){                                //solo se il pixel esiste
        myGLCD.drawPixel(fromx+j,fromy+i);            //Traccio il pixel nel punto richiesto con l' offset richiesto
      }
    }
  }
}


Questa e' la funzione che mi traccia la linea del manometro facendo il controllo dello sfondo, quindi ci passa sopra senza cancellarlo:
Code: [Select]
word aggiornamanometro(word fromx,word fromy,word larghezza,word altezza,byte dimcella,word gradi,word gradiold){  //aggiorna il manometro cancellando la vecchia linea e creando la nuova
                      // gli vengono passate le coordinate di inizio (from), le misure dell' immagine, la dimensione della cella e gli angoli di tracciamento (angolo vecchio e nuovo)
  byte offset1=18;            //% di offset dell' inizio della lancetta rispetto al centro
  byte offset2=80;           //% di offset della fine della lancetta rispetto al centro
  word xpixel,ypixel;        //coordinate del pixel
  byte xcentro=(larghezza/2)+fromx;            //coordinate del centro del manometro
  byte ycentro=(altezza/2)+fromy;
  float x,y,xold,yold;
  y=sin((gradi*3.14)/180);                  //calcolo
  x=cos((gradi*3.14)/180);
  yold=sin((gradiold*3.14)/180);
  xold=cos((gradiold*3.14)/180);
  byte inizio=offset1*altezza/200;          //inizio della lancetta, primo pixel
  byte fine=offset2*altezza/200;            //fine della lancetta, ultimo pixel
  for (byte n=inizio;n<fine;n++){           //tracciamento della linea
    xpixel=(xold*n);                        //coordinate del pixel della vecchia linea
    ypixel=(yold*n);
    boolean pixel=pixel_in_image(xpixel+xcentro-fromx,ypixel+ycentro-fromy,larghezza,dimcella, immagine);  //restituisce come risultato il valore del bit alle coordinate date
      if (pixel==false){
      myGLCD.setColor(sfondomanometro);                  //setta il colore scelto per lo sfondo del manometro
      myGLCD.drawPixel(xpixel+xcentro,ypixel+ycentro);   //cancellazione della vecchia linea con controllo dello sfondo   
    }
    xpixel=(x*n);                                        //coordinate del pixel della nuova linea
    ypixel=(y*n);
    myGLCD.setColor(coloremanometro);                    //setta il colore scelto per il manometro
    myGLCD.drawPixel(xpixel+xcentro,ypixel+ycentro);     //tracciamento della nuova linea
  }
  return gradi;    //salva il valore dei gradi attuali per usarli successivamente per la cancellazione
}


In allegato metto un sorgente in C# che ho modificato per ottenere l' immagine mappata in binario e per l' utilizzo nell' IDE Arduino. E' da aggiustare perché alla fine dell' immagine non conclude automaticamente l' ultimo Byte, cioe' se l' immagine ha un numero di bit non multiplo di 8 l' ultimo byte non viene completato.
Ma per ora mi andava bene cosi, poi sistemo.

leo72

Per convertire da gradi a radianti, usa la variabile predefinita DEG_TO_RAD che è il risultato di (PI/180). Acceleri l'esecuzione del programma perché così non costringi tutte le volte a far fare alla CPU la moltiplicazione per 3.14 e poi la divisione per 180.

Che poi, ripensandoci, perché non tratti gli angoli direttamente in radianti? Così eviti tutte le volte di dover passare da un sistema all'altro.

Deltoz

#33
Mar 13, 2014, 09:51 am Last Edit: Mar 13, 2014, 09:54 am by Deltoz Reason: 1
Grazie mille per la dritta del "DEG_TO_RAD", purtroppo al di fuori dell' IDE Arduino non conosco altre istruzioni per ora, quindi mi rifaccio sempre a loro, pian piano imparo nuove cose.
Per il passaggio diretto dei radianti devo pensarci un po su e verificare la fattibilita', in effetti io ho dei valori che vanno da un massimo ad un minimo, li posso mappare, trasformarli in RAD e poi passarlo alla funzione....devo provare.
Vi aggiorno appena faccio qualche prova sui tempi di miglioramento.

Edit: pero' pensandoci bene il calcolo dei RAD viene fatto sempre una sola volta, mo o lo faccio fuori o dentro la funzione non credo cambiera' molto.

Deltoz

una prova al volo.
Ho fatto una routine ciclica: lasciando il codice come era il tempo impiegato e' di 43045 millisec, sostituendo il 3.14/180 con DEG_TO_RAD il tempo impiegato per la stessa routine e' di 42685 millisec, in fondo una differenza davvero minima che sul singolo calcolo e' praticamente irrilevante, pero' sempre qualcosa e' :).

leo72

Controlla anche l'occupazione di Flash, perché semplificando i calcoli risparmi anche risorse.
Che su queste MCU ad 8 bit fa sempre comodo.

Deltoz

#36
Mar 14, 2014, 06:40 pm Last Edit: Mar 14, 2014, 06:42 pm by Deltoz Reason: 1

Controlla anche l'occupazione di Flash, perché semplificando i calcoli risparmi anche risorse.
Che su queste MCU ad 8 bit fa sempre comodo.

Si, anche qui piccolissima differenza in miglioramento. Flash occupata prima 58924, flash occupata dopo sostituendo con DEG_TO_RAD 58906.

leo72

Bene!
Ora sicuramente tu non avrai problemi nello specifico circuito perché di Flash ne hai in abbondanza  ;)
Ma imparare a fare le cose ottimizzando ti può tornare utile se poi ti capita di prendere in mano chippini con risorse limitate come i Tiny, dove ogni byte risparmiato vale doppio  :D

Deltoz

Si si infatti, sono pienamente d' accordo!!
il problema e' che per il momento sono purtroppo limitato ai comandi base dell' IDE Arduino, ma appena ne ho la possibilita' vorrei espandere le mie conoscenze studiando altri linguaggi fondamentali.
Sinceramente non so su quale puntare, ho dato uno sguardo veloce allo C#, ma sinceramente non so su quale puntare (considerando che il tempo per lo studio e' davvero limitato, visto che vengono prima la famiglia e il lavoro ;)).

leo72

Se parliamo di ambito "microcontrollori", devi studiarti C e C++ (più il primo del secondo).

Se parliamo di piattaforma "computer", la scelta è dettata solo dalle preferenze, dalla piattaforma e da cosa vuoi poi fare con quel linguaggio.

Deltoz

si, principalmente per microcontrollori, quindi mi buttero' di certo sul C.
Pero' avere anche la possibilita' di farmi qualche programmino in Windows, a maggior ragione poi per un' interfacciamento con i MPU, mi fa gola, quindi vorrei poi poter lavorare anche con uno di loro. Se poi sara' VB, VC#, Java o altro....bho...magari quello che si avvicina di piu' alla programmazione che conosco ora.

Go Up