MAX7219 - requisiti hardware

Ciao a tutti.
Sto utilizzando dei MAX7219 per visualizzare dei dati provenienti da un simulatore di volo (integer o string).
Ho realizzato 2 pcb: uno per gestire 2 MAX a catena (che gestiscono 2 display composti ognuno da 7 display led a 7 segmenti) e il secondo per un singolo MAX (1 display composto da 7 display a 7 segmenti).
Il tutto lo sto testando in una rete comunicante su RS485; la rete è composta da 4 arduino nano + 1 mega. Schematicamente, gli arduino gestiscono:
2 nano: switch, potenziometri, encoder, led
1 nano: switch e una striscia led WS2812 (con libreria FastLed)
1 nano: i 2 pcb per i MAX, collegati a catena (in pratica i 3 MAX sono in daisychain, prima il doppio poi il singolo)
1 mega: switch, potenziometri, encoder, led
Ingenuamente, poichè le singole schede (testate su RS485) funzionavano, mi illudevo che una volta collegate tutte, funzionassero a dovere.
Invece quello che succede è:

  • in ogni prova che ho fatto, i 3 nano e la mega (switch, encoder, potenziometri, WS2812 e led) continuano a funzionare regolarmente.
    per quanto riguarda il nano con i 3 MAX in cascata:
  • se ci sono collegate tutte le altre schede, vengono visualizzati solo i 2 display del pcb doppio, mentre i display collegati al pcb singolo non danno segni di vita
  • se collego all'RS485 il solo nano con i 3 MAX, tutti i display visualizzano le informazioni che mi aspetto
  • se collego a quel nano 1 solo pcb per volta (o quello doppio o quello singolo) e con il relativo codice, e con tutte le altre schede connesse all'RS485, le informazioni di quel display vengono visualizzate correttamente

Ho deciso di usare un nano dedicato solo ai display proprio per evitare in qualche modo un sovraccarico del processore, ma a quanto pare 3 MAX già diventano un ostacolo insormontabile?
Mi è stato suggerito di provare a gestirli con un mega (cosa che proverò a fare appena me ne procuro uno), però mi sembra uno spreco di risorse utilizzare un mega solo per 3 display.
Anche considerando che i dati da visualizzare sono alquanto statici (si tratta di frequenze radio, canali radio e coordinate geografiche), cioè vengono impostati e al limite variati saltuariamente e solo se necessario.
Mi domando inoltre, visto che è possibile concatenare fino a 8 MAX, che cosa servirebbe per gestirli???

Andrea

I 7219 hanno i latch e il multiplexer interni, perciò devono comunicare solo quando ci sono variazioni. Sono statici, rispetto alla logica di controllo. Non sono impegnativi per il microcontrollore.

Ma allora se non pesano sul micro, perchè si verifica quel comportamento?
Potrebbe essere un problema di sketch che forse (anzi, senza il forse) è un pò articolato, in quanto valuto volta per volta il valore che viene passato?
Nel caso del doppio MAX, vengono passate 2 stringhe (1 per ogni MAX), e ad ogni display 7-segmenti assegno la posizione del carattere (che è un numero) nella stringa
Nel caso del MAX singolo, la cosa è un pò più articolata, perchè vengono passati diversi valori, questa volta come integer. I 7 display 7-segmenti utilizzati sono in realtà raggruppati in questo modo:

  • un gruppo di 3, cui vengono passati 2 integer (0>65535): 1 per le unità e uno per le 100/10. Il primo problema è che il valore passato non riesco a gestirlo con una funzione map in quanto non ottengo il risultato che dovrei (adesso a memoria non ricordo); quindi ho dovuto usare istuzioni if in modo tale che a ogni determinato intervallo dell'integer (trovato "sperimentalmente") il display visualizzasse una cifra specifica da 0 a 9. A questo, si aggiunge il fatto che il secondo integer (cioè 100/10 che rappresentano un valore da 1 a 35) non cambia in maniera...lineare, ma per valori da 0 a 32767 incrementa la seconda metà (cioè 18-35) , da 32768 a 65535 da 0 a 17, e quindi anche qui ho dovuto trovare "sperimentalmente" gli intervalli e assegnargli di conseguenza il valore.
  • un gruppo di 2 display 7-segmenti, in cui i 2 integer passano unità e decine, ed anche qui ho avuto lo stesso problema con la funzione map, quindi ho dovuto risolvere come sopra
  • un gruppo di 2 display 7-segmenti, che riceve valori da 1 integer con valori 0>9, e che però ho risolto con poche righe di codice.
    Pur non essendo una cima nel programmare, anzi proprio terra terra, mi rendo conto che il codice ottenuto (per i primi 2 gruppi di cifre) è molto...dispersivo forse.
    Potrebbe essere questa dispersività (per non dire pesantezza) a far andare in tilt?
    Però in ogni caso non mi spiego perchè se usata da solo, il nano che gestisce i 3 display non fa una piega e fa il suo lavoro, mentre se ci sono anche gli altri nano sulla rete va in tilt (e sempre e solo il MAX singolo - che poi è quello con il codice più pesante)

0>65535 significa che 0 è maggiore di 65535! Forse intendevi da 0 a 65535...

Che cosa sono le 100/10?...

Bisognerebbe vedere uno schema elettrico dell'insieme e tutto il programma, compresa la comunicazione su RS485...

Se ogni hardware testato singolarmente funziona deve anche funzionare quando li assembli, però la memoria ram potrebbe non bastare. Parli di FastLed, parli di RS485 (quindi libreria), parli di MAX e quindi libreria. Queste librerie allocano spazio in ram che per la nano vale 2048 celle di memoria grande ognuna 1 byte.

Posta per ogni arduino parte principale del programma fino al setup() incluso, almeno ci si può fare una idea di massima.

Ciao.

Si intendevo quello (da....a.....), non il significato matematico

decine e centinaia (perchè il numero da visualizzare è composto da 3 cifre. In realtà suppongo che quella dicitura (che ho riportato dalla documentazione del software - se vogliamo chiamarlo così - di interfacciamento) si riferisca al fatto che il primo integer gestisce la parte unitaria di quella cifra, mentre il secondo gestisce la parte a 2 cifre iniziali (quindi decine e centinaia)

Comunque, ieri ho provato a caricare lo sketch su un arduino mega. Inizialmente non ho avuto alcun miglioramento, poi ho iniziato a "sperimentare" un pò di variazioni hardware (uso un interfaccia RS485 fatta in casa (non farina del mio sacco - non sono in grado - ma ricavata da vari forum e con una modifica che mi sono azzardato a fare); siccome facevo prove usando la stessa interfaccia collegando volta per volta il mega o il nano, ho deciso di lasciare il nano montato sull'interfaccia e il mega collegato "al volo" con cavi dupont. E ha funzionato a dovere.
Adesso mentre scrivo (e quindi pensando a come descrivere la cosa) mi è venuto un dubbio, quindi prima di continuare, me lo vorrei togliere (appena torno a casa dal lavoro), poi vi aggiorno (e se è come penso, vi chiederò lumi - almeno rimedio a un altro granello della mia ignoranza)

Per quanto riguarda il codice, non ho problemi a postarlo, ma è molto lungo, magari se ci fosse il modo allegherei direttamente i file .ino

Allora, ho risolto o almeno credo, visto che funziona senza problemi (e su un nano), anche se su bus RS485 rimane il problema di visualizzaione del terzo MAX, ma se lo connetto via USB funziona a perfezione (nessun freeze, nessun comportamento strano, veloce e reattivo come mi aspettavo). Deve essere un problema della programmazione del sistema base per quanto riguarda la comunicazione RS485. Ma va bene anche così..
In pratica ho rivisto la parte software che gestisce i dati dei display relativi al terzo MAX in cascata (quello singolo).
Tralascio il codice "originale": dopo aver preso la decisione di rivederlo, l'ho rivisto bene - stavolta accendendo il cervello - ed era vergognoso; ho vergogna a postarlo. Ma in pratica ogni volta che giravo il selettore ed il pc inviava il valore di integer nuovo, faceva una valanga di controlli....e quindi andava in palla. Forse neanche la CPU di un PC stava dietro all'oscenità che avevo scritto.
Basta dire che lo sketch adesso da 700 e oltre righe è passato a circa 350.
Sono soddisfatto della soluzione che ho trovato, ma avrei una curiosità circa un problema (che ho risolto in verità a tentoni).
RIguarda il modo in cui sto gestendo l'integer di cui al primo punto del post #3, cioè quello che mi manda il valore per calcolare le 2 cifre di decine e centinaia.
La prima cosa che ho notato (accendendo il cervello) è che questo valore rimane fisso per il 99% della decina/centinaia visualizzato. Ad esempio, per un valore 12 l'integer rimane fermo a 54612, per poi cambiare rapidamente pochi attimi prima che scatti il 13 e fermarsi a 56432, e così via.
Questo mi ha dato modo di calcolare con una certa precisione il valore decina/centinaia per un dato integer e quindi ricavare il numero che devo visualizzare. Poichè, come detto nel post #3, c'è uno sfalsamento nel reale valore da visualizzare, ho risolto sommando o sottraendo 18, a seconda dei casi.
La mia curiosità riguarda il caso in cui devo visualizzare proprio la cifra 18, in quanto in questo intervallo l'integer assume valore (fisso) 65535 ( cioè il massimo che può assumere), ma poi quando sta per scattare il 19, varia rapidamente da 0 a 1820 (cioè il valore fisso che corrisponde al 19).
Questo è il codice che mi gestisce il calcolo:

int Decine1 (unsigned int x){
  if (x>=32767 && x<65535){
    return (x/1820)-18;
  }
/*
  if (x=65535){
    return 18;
  }

  if (x>=0 && x<1820){
    return 18;
  }
*/

  if (x==65535 || (x/1820)==0) {
    return 18;
  }

  if (x>=1820 && x<32767){   
    return (x/1820)+18;
   }
}

Inizialmente avevo utilizzato le righe che ho commentato (quelle con l'AND): così facendo però, il valore visualizzato (dal 18 al 35, e stessa cosa andando al contrario, da 35 a 18) mi rimaneva costante pari a 18 (e non quello del valore corrente dell'integer passato, ovvero 19-20-21.....)
Cambiando la condizione in quella attiva (con l'OR e considerando il risultato di quella divisione), tutto funziona perfettamente.
Perchè succedeva?

Non ho capito tutto il ragionamento, ma guardando il codice commentato vedo questa riga.
Con un solo uguale è una assegnazione e non un confronto.
Magari il problema era qui.

Tra l'altro, essendo unsigned puoi tralasciare il controllo >= zero... Non potrà mai essere minore di zero...

Ancora non riesco a capire che cosa c'entrino quei valori mostruosi con le cifre che vuoi visualizzare... Con gli spezzoni di programma non si capisce nulla!

In realtà non capisco la perplessità. Comunque il codice in questione è questo:

void onZms3MagvarCnt10010Change(unsigned int newValue) {
  lc1.setDigit(2,3, ScompDecine1(Decine1(newValue)), false);
  lc1.setDigit(2,4, ScompDecine2(Decine1(newValue)), false);
}
DcsBios::IntegerBuffer zms3MagvarCnt10010Buffer(0x1940, 0xffff, 0, onZms3MagvarCnt10010Change);

int Decine1 (unsigned int x){
  if (x>=32767 && x<65535){
    return (x/1820)-18;
  }
/*
  if (x=65535){
    return 18;
  }

  if (x>=0 && x<1820){
    return 18;
  }
*/

  if (x==65535 || (x/1820)==0) {
    return 18;
  }
  if (x>=1820 && x<32767){   
    return (x/1820)+18;
   }
}

Mancano la definizione delle funzioni ScompDecine1 e ScompDecine2: fanno semplicemente (rispettivamente) una divisione per 10, e una moltiplicazione per 10 e una sottrazione. Spero che la loro mancanza non crei ulteriori perplessità.
Non capisco quali informazioni fondamentali si possano reperire da quelle 4 righe aggiunte: viene letto un valore fornito dal software (valore che è quello che ho esplicato io nei post precedenti). A meno che non sia fondamentale inserire anche il setup dove configuro il display per funzionare con la libreria LedDisplay....

Il problema è relativo a questa (e solo questa) parte di codice; il rimanente codice (che non mi da problemi) è esattamente la stessa cosa, cambia solo l'origine (cioè XYZ-Change e XYZ-Buffer) del valore passato dal software commerciale (anche il nome della variabile rimane sempre newValue).
O è necessario inserire tutte le ripetizioni?
Riguardo il valore "mostruoso": mi spiace, non ho deciso io cosa passare, ma la software house. E hanno deciso di passare un unsigned int da 0 a 65535 per indicare un valore da 0 a 9 e da 00 a 35.
Ma, al di là di incomprensioni e perplessità varie....Sicuramente è colpa mia, ma provo a spiegarmi nuovamente (e spero meglio) cosa dovrebbero rappresentare i valori mostruosi.
Lavorando un pò di fantasia (purtroppo non è possibile allegare immagini): contatore a 3 cifre (tipo quelli che si trovavano nei vecchi contatori del gas) composto da 2 anelli: anello delle unità (1 cifra: da 0 a 9), e anello delle decine / centinaia (2 cifre: da 00 a 35). Valore minimo: 000 Valore massimo : 359.
La software house ha deciso che siccome è troppo facile passare un numero a 3 cifre, ti passa 2 valori mostruosi:

  • per l'anello dell'unità, ti passa un unsigned int da 0 (0) a 65535 (9)
  • per l'anello delle decine/centinaia, ti passa un unsigned int, ma: per valori da 00 a 18, l'unsigned int parte da 32767 (00) fino a 65535 (18); per valori da 19 a 35 parte da 1820 (19) fino a 32766 (35) (sarebbe stato troppo facile farlo come per le unità)

Quello che mi serve è ricavare dal valore mostruoso il valore a 1 cifra in un caso e a 2 cifre nell'altro. E fortunatamente basta una semplice divisione nel caso delle unità, nel secondo caso oltre alla divisione devo sommare o sottrarre 18 (e poi scomporre il numero).
E se non sbaglio è la situazione che descrivo fin dall'inizio.

Hai ragione, non me ne ero accorto, sicuramente sarà quello che crea il problema. Appena riesco provo a correggere e vedere se il problema si risolve.

Ho fatto quella prova, ed effettivamente il problema era in quell'errore.
Il codice attualmente, funzionante, è:

int Decine1 (unsigned int x){
  if (x>=32767 && x<65535){
    return (x/1820)-18;
  }

  if (x==65535 || x<1820) {
    return 18;
  }

  if (x>=1820 && x<32767){   
    return (x/1820)+18;
   }
}

Grazie a tutti per il supporto

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.