Nuova libreria 74HC595 per controllo display LCD ed uscite digitali

ciao, oggi ho dato un'occhiata alla libreria in quanto voglio scrivermi una cosa simile per il mio progetto, sempre per dei 74hc595 solo che senza display, devo dire che hai fatto un bel lavoro ma volevo chiedere un paio di cose:

  • da quanto ne so io, fare un digitalWrite è abbastanza complesso per l'arduino, non sarebbe meglio agire direttamente sul portb? quindi con bitSet(PortB, arduinoPin-8)
  • stessa roba per la funzione ShiftOut, non sarebbe meglio gestirla più a basso livello la comunicazione SPI?

alla fine so che magari non ci sono differenze però se bisogna mettere tanti shift registers in serie inizia ad essere un po pesante

P.S. prendilo come una mia riflessione personale sul possibile miglioramento della libreria :slight_smile:

Eccomi qui, rispondo a tutti insieme:
@Leo72: tranquillo, non mi sento sotto processo, anzi, ho visto il tuo blog, d'ora in avanti quando mi vedranno ridere da solo sarà perchè ripenso alla "Sindrome di Gundam"....son ancora qui che mi spancio dalle risate. Per quanto riguarda Linux nel mio blog trovi articoli di programmazione multiplatform, per cui so benissimo che è case sensitive, come tutti gli OS tranne win :astonished: Mi aspettavo però che l'IDE di Arduino fosse in grado di "correggere" il nome del file proprio perchè è multiplatform, infatti se pensi la cosa all'inverso potresti fare due librerie simili, una in maiuscolo ed una in minuscolo che però su win non funzionerebbero (in realtà non potresti nemmeno metterle sulla stessa cartella per cui in realtà il problema non sussiste :~). Posso chiederti che plugin di wp hai usato per gli articoli in 2 lingue sul tuo blog?
@Lexip: Facci sapere come va, magari a progetto finito una bella foto dell'acquario la puoi condividere con tutti noi.
@LeonidRusnac: Tranquillo, io prendo in considerazione i suggerimenti di tutti, il bello di essere una cominità è proprio quello di poter condividere iddee, esperienza, capacità. Per quanto riguarda il settaggio diretto delle porte è vero e sbagliato nello stesso tempo. Proprio ieri ho letto l'articolo sul blog di Leo72 il suo articolo su questo argomento il che mi ha spinto a pensare un po'. La gestione diretta delle porte hai i suoi vantaggi in termini prestazionali, specialmente nelle applicazioni più critiche, ma una libreria deve funzionare su QUALUNQUE scheda Arduino per cui io devo essere sicuro che quel che facciamo con la Uno funzioni anche sulla Due, la Tre e la Yun. Ma siamo sicuri che la mappatura di quelle schede e delle future funzionino allo stesso modo? Poi uno dei vantaggi della mia libreria è la possibilità di scegliere qualunque pin della scheda, ma un utente potrebbe scegliere un pin su una porta e un'altro su un'altra per cui la gestione del software diventa un po' complessa. Arduino nella digitalWrite usa delle funzioni di più basso livello per mappare porta e bit relativi ad uno specifico pin di ogni scheda supportata per cui ho provato a scrivere una funzione simile alla digitalWrite, ma che non perde tempo a disattivare il pwm e non si dilunga a disattivare e poi riattivare gli interrupt. Purtroppo però la mia libreria ha solo 2 chiamate alla digitalWrite per cui il risultato finale è che la sketch occupa più spazio, mentre non ho ancora fatto test di velocità che farò nei prossimi giorni. Per quanto riguarda invece la ShiftOut non ho ancora visto com'è implementata, appena ho un attimo verifico se ci sono margini di miglioramento. Io uso una funzione sostitutiva ma che opera su buffers multibyte che utilizzo in una versione della IR-remote che sto ampiamente modificando, potrei eventualmente usare quella ma devo fare delle prove....vi aggiornerò....

smania2000:
@Leo72:
Posso chiederti che plugin di wp hai usato per gli articoli in 2 lingue sul tuo blog?

E' qTranslate.

Ciao,

complimenti per la libreria; al momento gli ho dato un occhio veloce e la trovo molto interessante.
Volevo chiederti una cosa in merito; vorrei realizzare una matrice a led modulare con arduino 1 rev3, e volevo sapere se con la tua libreria e aggiungendo degli shift register 74HC595 posso farlo.

Grazie per la risposta

Ciao
fiodavid

leo72:
E' qTranslate.

Grazie 1000 Leo72!

@fiodavid: certo che puoi farlo, MA non ti bastano i 74HC595 perchè non erogano sufficiente corrente per "tener su" tutti i LED. Se guardi nel mio blog c'è scritto come usare in accoppiata gli ULN2803A, alternativamente esistono led-drivers specifici per il pilotaggio di LED ma sinceramente è una materia in cui non mi sono mai inoltrato ma credo che su questo forum troverai tutte le informazioni di cui hai bisogno.

Come vi avevo promesso ho fatto dei test per vedere se è possibile incrementare ulteriormente la velocità della libreria, anche se francamente dai test che avevo fatto non ne sentivo il bisogno.
Come test ho usato l'esempio incluso nella libreria che non fa altro che settare il cursore e scrivere un carattere su un display lcd ad ogni ciclo. Senza fare alcuna modifica, con la libreria così come la trovate in rete, ho ottenuto un tempo di esecuzione di 7268 microsecondi. Andando a modificare la Send595 affinchè non usi la digitalWrite ma, come vi accennavo, una versione modificata che ignora la disattivazione del pwm e la disattivazione / riattivazione degli interrupt, ottengo 7244microsecondi. Un ulteriore miglioramento è ottenibile con la manipolazione diretta delle porte (7192us) , ma come vi dicevo in un post precedente andrei a perdere la possibilità di usare qualunque pin e la certezza di compatibilità con schede più sofisticate / recenti della Uno. A questo punto ho creato una versione modificata della ShiftOut che si affida alla digitalWrite modificata. Il risultato è notevole, il tempo di esecuzione scende a 4984 con un miglioramento prestazionale di circa il 30%.
Visto il risultato a breve avrete una nuova versione della libreria ed una piccola grande sorpresa a cui ho pensato, ma mi ci vuole qualche giorno per scrivere il codice e verificare che tutto funzioni a dovere.

Dopo un duro lavoro di ottimizzazioni eccomi qui con la nuova implementazione della mia libreria. Come detto nei precedenti post ho lavorato, grazie ai vostri consigli, sull'ottimizzazione della velocità e devo dire la verità che con l'uso dei display la differenza è notevole. C'è però una scelta da fare che volevo discutere con tutti voi. Ho infatti lavorato su due versioni distinte, non perchè sia impazzito, ma perchè ad un certo punto del lavoro ho notato che introducendo ulteriori ottimizzazioni del codice cpp, la velocità complessiva della sketch diminuiva invece che aumentare. Ho perciò pensato che fosse un problema dovuto all'incapacità del compilatore ad ottimizzare correttamente il codice cpp per cui ho scitto anche una versione in C che come presunto si è dimostrata più veloce. Ma non basta. Oltre ad usare i due linguaggi, ho usato sia codice ottimizzato all'interno della libreria, sia mi sono appoggiato ad una nuova microlibreria scritta apposta per l'occasione. Questa seconda opzione ha ovviamente il vantaggio di essere utilizzabile in qualsiasi altra vostra sketch o libreria. In entrambi i casi NON ho gestito in modo diretto le porte ma ho sfruttato le funzioni di basso livello di Arduino digitalPinToBitMask e portOutputRegister che sicuramente non permettono di raggiungere le massime velocità possibili ma dovrebbero garantire totale compatibilità con qualunque clone Arduino.
Vi riporto qui sotto le due sketch d'esempio, la prima in cpp, la seconda in c. La libreia Memoryfree che vedete mi serve solo a calcolare la memoria residua della Uno per ottimizzare anche quell'aspetto

// versione scritta in Cpp

#include <FastArduino.h>
#include <hc595.h>
#include <MemoryFree.h>

unsigned char Leds;
unsigned long time1,time2;

hc595 My595(12,11,13,2); // latch,clock,data,number of 74hc595


void setup() 
{
 Leds=0;
  My595.DisplayReset(LCD595_BASIC_DISPLAY_INIT | LCD595_MORELINES ,0); // multiline display
 My595.SetCursor(0,0,1,0); // cursor at 0,0, display type 1 on first 595
 My595.DisplayWrite("Setup is OK...",0); // Write string
 delay(1500); // waiting for...
 My595.DisplayClean(0); // clear display
Serial.begin(9600); 
}

void loop()
{
    time1 = micros();
  My595.SetCursor(Leds%13,Leds%2,1,0);
  My595.DisplayChar(32+Leds%96,0);
   time2 = micros();

  Serial.println(time2-time1);
   Serial.print("freeMemory()=");
  Serial.println(freeMemory());
  Leds++;
  delay(500);
}
// versione scritta in C
#include <FastArduino.h>
#include <hc595c.h>
#include <MemoryFree.h>

unsigned char Leds;
unsigned long time1,time2;

void setup() 
{
 hc595_hc595(12,11,13,2); // latch,clock,data,number of 74hc595
 Leds=0;
 hc595_DisplayReset(LCD595_BASIC_DISPLAY_INIT | LCD595_MORELINES ,0); // multiline display
 hc595_SetCursor(0,0,1,0); // cursor at 0,0, display type 1 on first 595
 hc595_DisplayWrite("Setup is OK...",0); // Write string
 delay(1500); // waiting for...
 hc595_DisplayClean(0); // clear display
 Serial.begin(9600);

 
}

void loop()
{
    time1 = micros();
  hc595_SetCursor(Leds%13,Leds%2,1,0);
  hc595_DisplayChar(32+Leds%96,0);
   time2 = micros();

  Serial.println(time2-time1);
   Serial.print("freeMemory()=");
  Serial.println(freeMemory());
  Leds++;
  delay(500);
}

I risultati che ho ottenuto sono i seguenti:
Con codice ottimizzato all'interno della libreria hc595:
C -len: 5178- speed: 4864- ram: 1763 (aggiornato dopo aver postato)
CPP - len: 5474 - speed: 5180- ram: 1761

e con libreria esterna FastArduino:
C - len: 5378 - speed: 4908- ram: 1763
CPP - len: 5670 - speed: 4932- ram: 1761

Con len si intende la lunghezza della sketch, speed i microsecondi medi per l'esecuzione e ram la memoria disponibile. L'utilizzo della ram risulta sostanzialmente uguale nelle varie "incarnazioni". Per quanto riguarda la grandezza della sketck in entrambi i casi la scrittura in C fa risparmiare circa 290 bytes ed altri 200 vengono risparmiati passando dall'uso della libreria esterna al codice bulti-in. L'estremo massimo si ha dalla scrittura in cpp con libreria esterna, al codice C builtin con risparmio di 480 bytes.
Anche la velocità di esecuzione porta ad alcune riflessioni. La versione in C è sempre la più veloce ed il codice built-in ottimizzato è di quasi l'1% più veloce rispetto alla libreria esterna. Usando il cpp invece si ha lo strano fenomeno che vi descrivevo all'inizio, ossia l'uso della libreria esterna MENO ottimizzata è paradossalmente più veloce di quasi il 5% nonostante il maggior numero di chiamate a funzioni e calcoli da eseguire. L'unica spiegazione che ho è appunto la scarsa capacità del compilatore ad ottimizzare il codice cpp rispetto il codice c puro, infatti se guardiamo la sola versione con codice built-in in cui il codice è fortemente più ottimizzato, vediamo che il divario fra la versione c e cpp è nettamente più marcato passando da meno dello 0.5% a quasi il 6%.
Dopo questa lunghissima ma necessaria introduzione la domanda è: che libreia terreste? Qualla in C con codice builtin o quella cpp con libreria esterna? Rispetto alla sketch d'esempio, la prima è dell'1% più veloce, fa risparmiare 480bytes in flash e 2 in ram, la seconda è leggermente più lenta, occupa più spazio in sketch ma essendo in cpp è più semplice da gestire / mantenere e si basa su una libreiria esterna su cui possiamo basare anche altre sketch che necessitino di un aumento prestazionale senza rischiare di pregiudicare la compatibilità con altre schede.
Voi cosa scegliereste?

Atroce dubbio... l'ho vissuto anch'io durante lo sviluppo del leOS.
Quei (pochi) utenti avanzati che l'hanno provata mi hanno suggerito forti trasformazioni verso il lato OOP che in parte ho implementato ed in parte no perché usando in modo intensivo gli oggetti e tutto il supporto offerto dal C++ arrivavo ad avere una libreria più semplice da gestire lato utente, sicuramente più "advanced" a livello di codice ma senz'altro più pesa.
Gli Atmel, come molte MCU ad 8 bit, sono ottimizzati per il C.

La scelta è doppia: o lasci la lib in C++ senza sfruttare però troppo le caratteristiche di questo linguaggio, ottenendo quindi un bilancio fra velocità ed occupazione di codice medio, ma rendendo la lib più agevole da gestire agli utenti (considerando che la stragrande maggioranza delle lib per Arduino è scritta in C++ e che quindi sono già abituati ad includere una lib e ad istanziarla) oppure ti appoggi al C, sfruttandone i vantaggi in termini di peso/prestazioni, richiedendo però all'utente un pò di impegno in più per gestirla.

Uh... bella scelta... :sweat_smile:

Ehi ragazzi non scannatevi a rispondere....se non fosse per Leo72 mi farei le domande e darei le risposte da solo :slight_smile: Comunque sia ho preso una decisione. Sono riuscito a spingere ancora un po' le prestazioni del codice cpp per cui alla fine la libreria resta per l'utente sostanzialmente identica, in più avete una libreria nuova chiamata FastArduino in cui avete le due funzioni FastdigitalWrite e FastshiftOut che funzionano allo stesso modo delle funzioni Arduino originali ma sono più veloci. Dettagli maggiori li trovate nel sito dove potete scaricare e testare la nuova versione.

Libreria molto interessante. :wink:
Hai provato ad associarla alla classe print per sfruttarne i metodi come fanno le classiche librerie per LCD?
Anche perché il quel modo, a parte l'istanza di classe, il codice sarebbe riusabile anche se si cambi metodo di collegamento del display.

scusa la mia assenza dopo aver postato la domande per le prestazioni, pensavo fosse attivo il Notify ma invece non lo era, comunque, secondo me è meglio lasciare la versione C++ (come hai già fatto) in quanto arduino viene usato da tanti che di programmazione ne sanno abbastanza poco ed è più facile gestirla a livello di OOP

P.S: gentilmente, se puoi e se non hai ancora cancellato la versione c, mi invieresti una copia? giusto per prendere spunto, questi giorni sono abbastanza impegnato e non sono riuscito ad andare avanti con il mio progetto e se avrei qualche spunto su come velocizzare la comunicazione spi sarei molto felice, ti ringrazio anticipatamente :slight_smile:

Recuperata appena in tempo dal cestino :D. Qui non mi pare ci sia qualche pulsantino per mettere allegati, ma se mi passi una mail ti invio la libreria in C. Mentre scrivevo ho fatto dei test in quanto volevo rispondere anche a PaoloP. Quel che volevo dire era che l'uso della print avrebbe rallentato la mia libreria e che comunque derivando la classe era possibile eseguire comunque tale operazione. A questo punto ho fatto dei test e mi accorgo che la Liquidcrystal segnava dei tempi migliori rispetto alla mia libreria, anche se non di tantissimo. Ho fatto un'analisi del codice e mi sono accorto di un baco da principiante, in un pezzo di codice ho scambiato nanosecondi con microsecondi :~ . Messo a posto il baco la mia libreria è diventata più veloce di 4 volte diventando 3 volte più veloce della LiquidCrystal. A questo punto due considerazioni: per LeonidRusnac puoi tranquillamente usare la versione in cpp che rispetto allla prima versione scritta è 7 volte più veloce ed annulla tutti i deficit prestazionali rispetto alla versione C. Per PaoloP se ti servono funzioni aggiuntive dovrebbe essere sufficiente creare una classa derivata, appena ho un attimo comunque faccio dei test così magari scrivo una sketch d'esempio per mostrare come fare.

smania2000:
Qui non mi pare ci sia qualche pulsantino per mettere allegati

Punto 8 --> [REGOLAMENTO] Come usare questa sezione del forum - Italiano - Arduino Forum

:smiley: :smiley: :smiley: :smiley: ....si vede vero che non ho scritto molto sul forum ? Allora allego qui la versione in C, tenete conto che l'ho presa nel cestino così com'era

hc595c.zip (4.64 KB)

Grazie mille :slight_smile:

Ciao ragazzi. Dall'ultima volta ci sono stati numerosi sviluppi ma non vi voglio annoiare con quelli, li trovate sul mio blog. Volevo segnalare che l'utente ogrenero ha individuato un problema con la IDE 1.5.5-r2, nello specifico non gli comparivano gli esempi della SS_hc595 e cercando di importare la libreria con l'apposita funzione gli compariva il messaggio "Trovata libreria non valida in C:\Program Files (x86)\Arduino\libraries\Ss_hc595: Missing 'architectures' from library". Ho indagato brevemente. La causa è il file library.properties che trovate nella relativa cartella.
Devo indagare sull'esatta origine del problema, comunque un semplice Work-around per sistemare il problema è cancellare quel file. Nel frattempo cercherò di capire la causa del problema.

Ciao, forse sarebbe bene segnalare questa cosa nel Topic di PaoloP in cui si parla specificatamente della versione 1.5.x ed è tenuto costantemente aggiornato, magari qualcuno potrebbe decidere di segnalare la cosa agli sviluppatori. Grazie.

Ho fatto come mi hai suggerito, prima però ho fatto delle prove per vedere se scoprivo la causa ma per ora nulla di fatto. E' comunque utile sapere che se qualcuno incorre nello stesso problema, anche con altre librerie, basta eliminare il file library.properties.

Credo dipenda dal fatto che il ramo 1.5.x è sotto pesante sviluppo e le specifiche cambiano anche radicalmente da rilascio a rilascio.
Ti quoto questo, preso dal changelog dell'IDE 1.5:

ARDUINO 1.5.5 BETA 2013.11.28

NOTICE:
The 1.5 library format is under heavy review on the Arduino Developers mailing list.
We suggest to delay the adoption of the new format until a stable 1.5.x is released.

Il formato delle librerie, a partire dalla 1.5.5 è oggetto di cambiamento (la R2 è solo un rilascio per correggere un problema con i driver certificati per Windows).