Matrice con 19 display 5x7 principio di funzionamento

Non mettere condensatori che rallentino lo spegnimento sulle linee o sulle colonne (a meno che tu non voglia saldarli su ogni singolo led, completi di diodo di carica e resistenza di scarica :stuck_out_tongue: :D), perche' ti falserebbero la visualizzazione creando code ...

Nelle matrici multiplexate, per ottenere una buona visibilita', di solito si aumenta la corrente ai led ... il led che sopporta, ad esempio, 20mA in continuazione, ne sopporta anche 40 per circa la meta' del tempo, o 80 per circa un quarto del tempo ... ovviamente, parliamo di commutazioni rapide, ma il multiplexing a 100Hz e' abbastanza rapido da consentirti come minimo di raddopiare la corrente sui led (triplicarla al massimo, non andare piu alto) senza danneggiarli, a patto che non "fermi" il multiplexing (quindi serve un controllo che riduca la corrente se la scansione si ferma, ma lo si puo realizzare anche hardware, volendo)

ma quelle matrici 57 puoi pilotarle singolarmente ma in contemporanea?
riesci ad accendere un pixel su una matrice e su un'altra insieme?
o la vedi solo come 96
7?

Puoi attivare una sola colonna alla volta delle 95, quindi dovrai fornire 95x la corrente nominale per 1/95 del tempo, quindi è obbligatorio usare led ad alta luminosità che con solo 1mA si accendono bene , gli si dà 100mA ed è tutto a posto, ci sono modelli di led di più bassa qualità che con 1mA non basta allora si arriva anche a 200-300mA per led, con un refresh di quadro da 10mSec(100Hz) un clock di 10Khz come ho detto prima è sufficiente, il conteggio si fà in interrupt mentre nel main si mette il refresh di quadro.

La corrente totale massima di consumo è 7 x iLed + qualcosa, se ci si tiene sotto i 150mA per led si è sotto i 1A , per questo un 7805 alimentato a 7V sarebbe sufficiente

Pilotando i led in questo modo non dureranno 30.000-50.000 ore ma un tempo inferiore che è già difficile calcolare avendo tutti i dati, quindi è una stima spannometrica

stavo dando un'occhiata al codice, penso che puoi ottimizzare parecchio.
Secondo me l'unica funzione per settare un pixel veramente utile è la XOR, tramite quella funzione puoi disegnare e cancellare andando a ritroso.
Per esempio se scrivi "ciao" e poi torni a scrivere "ciao" la scritta scomparirà.
Quindi sprecando qualche byte di memoria la funzione per invertire un pixel e per prelevarlo sarà:

uint8_t bitmap[8][16];

#define gpoint(G,C,R) do{ uint8_t adr = (C) >> 3;\
	                         uint8_t msk = (C) & 7;\
                          G = !!(bitmap[R][adr] & (1 << msk));\
                      }while(0)
                      
void xpoint(uint8_t c, uint8_t r)
{
	   uint8_t adr = c >> 3;
	   uint8_t msk = c & 7;
	   bitmap[r][adr] ^= 1 << msk;
}

o qualcosa di simile.
Già qui abbiamo come minimo triplicato le performance.
Volendo, come fanno tutte le librerie grafiche, la funzione xpoint andrebbe riscritta come macro in modo da aumentare ancora le performance.
Il resto del codice non l'ho ancora analizzato.

Si vbextreme il codice è la pecca, se accelero l'elaborazione dei bit e delle zone (facendo dei tagli di cicli) prelevati dai char , è vero che ottengo scritte illegibili, ma ho uno scorrimento fluido e luminosità massima senza sfarfallii ...
probabilmente piazzando i bit/byte già belli e pronti in sequenza elimino un sacco di cicli
Ad esempio mi scorrono AAAAAAAAAAAAArrrrrrrrrrrrrrrrrrddddddddddddddddd veloci e ben visibili

dimenticavo, in quel modo la colonna 0 e il bit meno significativo corrisponderà a x == 0 , sempre a colonna 0 il MSB a x == 7, colonna 1 LSB 8, etc,etc etc.
Così ti regoli su come inviare i byte.
Io tornerei a scrivere anche la shiftout perché quella di Arduino è basata su digitalwrite e se la scrivi usando direttamente i registri aumenti la comunicazione di quasi 10 volte.

si che poi sarebbe questa

void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, int val, uint8_t bits = 8, uint8_t del = 0)
{
  uint8_t i;
  for (i = 0; i < bits; i++)  {
    if (bitOrder == LSBFIRST)
      digitalWrite(dataPin, !!(val & (1 << i)));
    else    
      digitalWrite(dataPin, !!(val & (1 << ((bits - 1 - i)))));
    digitalWrite(clockPin, HIGH);
    delayMicroseconds(del);
    digitalWrite(clockPin, LOW);            
  }
}

tra H e L del clock bisogna dargli almeno 1 microsec altrimenti non lo legge
digitalWrite(clockPin, HIGH);
delayMicroseconds(1);
digitalWrite(clockPin, LOW);

riscrivila con i registri, vai più veloce!
con quella impieghi 10us prima della pausa da 1 e poi altri 5 totale 16us, nell'altro modo circa 2.5us , 4 volte più veloce...

se vuoi traslare tutto lo schermo con il codice che ti ho proposto basterebbe una cosa simile a questa:

void transleft()
{
	   int8_t y,adr;
	   for(y = 0; y < 8; ++y)
	   {
	       bitmap[y][11] <<= 1;
	   	    for(adr = 10; adr >= 0; --adr)
	   	    {
	   	    	   bitmap[y][adr+1] |= !!(bitmap[y][adr] & 0x80);
	   	    	   bitmap[y][adr] <<= 1;
	   	    }
	   }
}

prendila con le pinzette perché l'ho scritta dal cellulare..
[edit]
infatti mi ero scordato 0x80
[/edit]

comunque
16 * 12 * 7 = 1344us = 1.34ms
2.5 * 12 * 7 = 210us = 0.21ms
praticamente ti avanza un millisecondo, scusa se è poco....

vbextreme:
...
praticamente ti avanza un millisecondo, scusa se è poco....

... sufficente per bere il caffe', leggere il giornale, e se sei veloce pure andare in bagno ... :stuck_out_tongue: :smiley: :smiley: :smiley:

Icio: si, teoricamente potrebbe dargli 100 volte la corrente per 1/100 del tempo, ma nella pratica non lo si fa mai, ovviamente per aumentare la durata dei led ... secondo me gia con il triplo della corrente otterrebbe un discreto miglioramento della visibilita', ma anche in caso estremo, non consiglierei di salire a piu di 5 o 6 volte la corrente massima ... anche perche' con correnti piu alte, i led si strinerebbero piu velocemente di quanto possa intervenire la protezione, se la scansione si fermasse ...

Ok grazie mille per l'aiuto :slight_smile:
un miglioramento c'è stato con l'uso dei registri ben visibile, posso aumentare il delay senza sfarfalii
Come si può notare dal programma iniziale ad ora sono passato da un delay di scorrimento da 1000us a 2100us ottenendo sempre la stessa velocità e maggiore luminosità. Molto buono!

Ho sostituito la funzione shiftOut così:

void RefreshDisplay(){    
  for (uint8_t riga = 0; riga < 8; riga++) {     
       PORTC = 0b00000000; //mega2560 metto OFF i PIN da 30 a 37
    
    for (int zone = maxZoneIndex; zone >= 0; zone--) {
      
       //shiftOut(dataPin, clockPin, MSBFIRST, bitmap[riga][zone]) ;     
        for ( uint8_t i = 0; i < 8; i++)  {       
            digitalWrite(dataPin, !!(bitmap[riga][zone] & (1 << ((7 - i)))));
            PORTE |= (1<<4); //digitalWrite(clockPin, HIGH);    // cambio solo il PIN2         
            //delayMicroseconds(1);
            PORTE &= ~(1<<4); //digitalWrite(clockPin, LOW);    // cambio solo il PIN2                               
        }
    }
         
    PORTC = 1 << (8 - riga);  //digitalWrite (29+riga, 1);  //ON una riga alla volta PIN da 30 a 36
    delayMicroseconds(2100);
  }
}

Sarebbe bello togliere un ultimo "digitalWrite", ma come faccio a pilotare direttamente il registro PORTE con questa linea?
digitalWrite(dataPin, !!(bitmap[riga][zone] & (1 << ((7 - i)))));
Che poi sarebbe il BIT5 del registro E che mi fa il DATA
ciao grazie

Il display è questo, l'ho trovato dopo tanto girare
http://www.datasheetlib.com/datasheet/649023/lj2041-21_ledtech-electronics.html?page=2#datasheet
figura LJ2041-21

Ho fatto così e funziona

//digitalWrite(dataPin, !!(bitmap[riga][zone] & (1 << ((7 - i)))));
            //diventa così
            bool bitt = !!(bitmap[riga][zone] & (1 << ((7 - i))));
            if(bitt) PORTE |= (1<<5);
            if(!bitt) PORTE &= ~(1<<5);

Ma non riesco a fare un copy del bit ottenuto nel bit5 del registro

anche così funziona, ma non sono sicuro che tocco solo il bit5 del registro E

PORTE = !!(bitmap[riga][zone] & (1 << ((7 - i))))<<5;

Alzato il delay (refresh righe) a 2500us + di così non penso si possa spremere, ottima la luminosità :slight_smile:

void RefreshDisplay(){    
  for (uint8_t riga = 0; riga < 8; riga++) {     
       PORTC = 0b00000000; //mega2560 metto OFF i PIN da 30 a 37
    
    for (int zone = maxZoneIndex; zone >= 0; zone--) {     
       //shiftOut(dataPin, clockPin, MSBFIRST, bitmap[riga][zone]) ;     
        for ( uint8_t i = 0; i < 8; i++)  {                           
            PORTE = !!(bitmap[riga][zone] & (1 << ((7 - i))))<<5; //digitalWrite(dataPin, !!(bitmap[riga][zone] & (1 << ((7 - i)))));          
            PORTE |= (1<<4); //digitalWrite(clockPin, HIGH);    // cambio solo il PIN2         
            //delayMicroseconds(1);
            PORTE &= ~(1<<4); //digitalWrite(clockPin, LOW);    // cambio solo il PIN2                               
        }
    }
         
    PORTC = 1 << (8-riga);  //digitalWrite (29+riga, 1);  //ON una riga alla volta PIN da 30 a 36
    delayMicroseconds(2500);
  }
}

mldifica così il for che va più veloce.

int8_t i = 8;
while( i-- )
{
            PORTE = (!!(bitmap[riga][zone] & (1 << i ))) << 5;
            PORTE |= (1<<4); 
            PORTE &= ~(1<<4); 
        
}

controllalo perché dal cellulare potrei sbagliare.

hai usato anche la funzione xor per disegnare?
Dato che è moolto più veloce di quella che hai postato, dovrebbe calare ancora lo sfarfallio e aumentare di luminosità.
Quando non sei in refesh il display è spento fino a che non finisci il nuovo disegno, quindi più veloce disegni e piu refresh hai, e più luminoso sei....
Puoi vederla come una pulsazione pwm, il dutyOn è il refresh e il dutyOFF è il tempo di disegno.

Ahahhahaha vogliamo fonderlo sto 2560 .....

Dunque:
Applicando while( i-- ) nella scrittura seriale "sul DATA" i caratteri scorrono da sinistra verso destra invertit invece che da dx verso sxi, insomma in modo anche confusionale

Però ho pensato di applicare il tuo while al for di 0 to 8 che aggiorna le righe e funziona, ma (fantastico) i carrateri scorrono regolarmente, ma sono inclinati in diagonale \\\\ così ... mentre col for ///// così :slight_smile:
Incredibile ... bastano pochi numeri per cambiare tutti gli effetti

Però Vb** ho ottenuto buoni risultati grazie ai tuoi e altri suggerimenti.

Ora posso continuare e dedicarmi ad effetti vari, devo però scoprire alcune cose oscure, perchè l'intera matrice da 19 display è suddivisa in 12 blocchi da 8 bit ciascuna, qui non lavoriamo con ogni singolo display, ma con un blocco unico da 7x95 led

ciao

ciao

ahahah, il concetto è semplice, non è il while che va piu veloce, è il controllo sullo 0 e l'eliminazione della sottrazione ad aumentare la velocità.

se vedo la matrice cosi

95..........0
00000...00000

il primo bit che invii
bitmap[0][0] & 1
corrisponde a 95 o a 0 ?

queste sono le mie shiftout

void shiftOutMsb(const byte pdata, const byte pclock, byte val, byte syncclock)
{
    byte b = 8;
    while( b-- )
    {
        _pinWrite( pclock, !syncclock);
        _pinWrite(  pdata, val & 0x80);
        val <<= 1;
        _pinWrite( pclock, syncclock);
    }
    _pinWrite( pclock, !syncclock);
}

void shiftOutLsb(const byte pdata, const byte pclock, byte val, byte syncclock)
{
    byte b = 8;
    while( b-- )
    {
        _pinWrite( pclock, !syncclock);
        _pinWrite(  pdata, val & 0x01);
        val >>= 1;
        _pinWrite( pclock, syncclock);
    }
    _pinWrite( pclock, !syncclock);
}

Ah, proprio roba extrema :slight_smile:
Sta sera ci guardo e provo a reinserirla.

Attento che la _pinWrite è una macro che lavora con specifici valori.
Ovvero i pin io li setto cosi:
8bit di cui i 4 di sinistra sono la porta e i 4 di destra il bit corrispondente.
Quindi per Arduino Uno:

#define _OFF      0x20
    #define _OFF_IN   0x00
    #define _OFF_MODE 0x01
    #define _OFF_OUT  0x02
    #define _B_OFF    0x30
    #define _C_OFF    0x60
    #define _D_OFF    0x90
    #define _REG_OUT(R)  (*(volatile uint8_t*)(_OFF + _OFF_OUT + (R)))
    #define _REG_IN(R)   (*(volatile uint8_t*)(_OFF + _OFF_IN + (R)))
    #define _REG_MODE(R) (*(volatile uint8_t*)(_OFF + _OFF_MODE + (R)))
    #define _BSET(B) (1 << (B))
  
    #define PIN_MODE_INPUT  0x00
    #define PIN_MODE_OUTPUT 0x01
    #define PIN_MODE_PULLUP 0x02
  
    #define D0  (_D_OFF | 0x00 )
    #define D1  (_D_OFF | 0x01 )
    #define D2  (_D_OFF | 0x02 )
    #define D3  (_D_OFF | 0x03 )
    #define D4  (_D_OFF | 0x04 )
    #define D5  (_D_OFF | 0x05 )
    #define D6  (_D_OFF | 0x06 )
    #define D7  (_D_OFF | 0x07 )
    #define D8  (_B_OFF | 0x00 )
    #define D9  (_B_OFF | 0x01 )
    #define D10 (_B_OFF | 0x02 )
    #define D11 (_B_OFF | 0x03 )
    #define D12 (_B_OFF | 0x04 )
    #define D13 (_B_OFF | 0x05 )
    #define A0  (_C_OFF | 0x00 )
    #define A1  (_C_OFF | 0x01 )
    #define A2  (_C_OFF | 0x02 )
    #define A3  (_C_OFF | 0x03 )
    #define A4  (_C_OFF | 0x04 )
    #define A5  (_C_OFF | 0x05 )
    #define NO_PIN 255

    #define _pinLow(P)  _REG_OUT((P) >> 4) &= ~_BSET((P) & 0x0F)
    #define _pinHigh(P) _REG_OUT((P) >> 4) |= _BSET((P) & 0x0F)

    #define _pinWrite(P,V) do{if(V){_pinHigh(P);}else{_pinLow(P);}}while(0)

esempio di utilizzo:

const uint8_t led D13

...
...
pinSet(D13, OUTPUT);
_pinLow(led);
_pinHigh(led);

Cosi facendo se si dichiara il pin come costante o viene definito come macro va veloce come l'accesso diretto al registro.
Non spreca memoria, ed è molto versatile.

vbextreme:
non ho ben capito tutto lo schema, ma hai modo di accendere più led in contemporaneamente?

ma quelle matrici 57 puoi pilotarle singolarmente ma in contemporanea?
riesci ad accendere un pixel su una matrice e su un'altra insieme?
o la vedi solo come 96
7?

No, la vedo come in figura, in quel caso spedisco 1 byte con valore 0x01 a tutti i 12 blocchi

Per accendere un solo led al centro dovrei spedire invece
00000000 00000000 00000000 00000000 00000000 10000000 00000000 00000000 00000000 00000000 00000000 00000000 sulla zona 6 riga 3 e tutti 0 sulle restanti righe

riassumendo 5 byte con '0' ... 1 byte con '128' e 6 byte '0'
ciao

PS:
nuova funzione shiftOut()

byte mio_byte=170; // esempio byte da inviare (10101010)
int8_t i = 8; while( i-- ){ // che sarebbe for ( uint8_t i = 0; i < 8; i++)       
            PORTE = !!(mio_byte & (1 << (i)))<<5;  // <<5 registo del dataPin     
            PORTE |= (1<<4);   //  = digitalWrite (2, 1); // registro del clockPin 
            PORTE &= ~(1<<4);  //  = digitalWrite (2, 0); // registro del clockPin
            }

Salve a tutti
Come posso accelerare ancora questa funzione? a me non viene in mente altro ....
considerando che bitmap[riga][zone] contiene già tutti i bit necessari alla visualizzazione.

void RefreshDisplay(){ 
  uint8_t riga = 8; while( riga-- ){ 
     uint8_t zone = 12; while( zone-- ){   
            
            //Invio bit al pin DATA                   
            uint8_t i = 8; while( i-- ){    
            PORTE = !!(bitmap[riga][zone] & (1 << i))<<5;   //DATA
            PORTE |= (1<<4);        //CLOCK
           // PORTE &= ~(1<<4);    
            }  
     }
    
    PORTC |= (1<<(8-riga));   
    delayMicroseconds(3200);    
    PORTC =0;      
  } 
}

void loop() {
RefreshDisplay();
}

Purtroppo è ancora lenta del 50%, il refresh delle linee mi toglie molta luminosità

Saluti e grazie