
In questo articolo parleremo del pilotaggio dei display a led a 7 segmenti, molto diffusi, di un certo fascino e abbastanza semplici da pilotare. Realizzeremo un contatore up/down con due pulsanti in modalità multiplex e utilizzante l’interrupt per l’aggiornamento delle cifre! Quindi il funzionamento del programma sarà non certo semplice da intuire al primo colpo ma vi assicuro che, realizzato in questo modo, ci permette davvero di sfruttare appieno il concetto di sistema operativo in real-time.
I più bravi possono sfruttare circuito e schema presentati in questa lezione anche per realizzare un timer eliminando i pulsanti oppure un elimina-code, o ancora un contapezzi in cui al posto dei pulsanti ci saranno dei sensori ecc. Il limite è dato solo dalla vostra fantasia!
Incominciamo prima con una breve introduzione ai display a 7 segmenti (dei quali qualcosa abbiamo già letto in un nostro precedente articolo dal titolo: La codifica BCD e i display a 7 segmenti).
I display a led più semplici e diffusi sono costituiti da 8 led: 7 che compongono la cifra e uno per il punto (generalmente usato come separatore decimale e posizionato in basso a destra), tutti i led hanno gli anodi (display ad anodo comune, es: TDSR5150, HDSP5501) oppure i catodi (display a catodo comune, es: TDSR5160, FND500, HDSP5503 ) collegati insieme.
Esistono display doppi (es.: il MAN6440, HDSP5523 -catodo comune- o MAN6410, HDSP5521 -anodo comune-), tripli (es.: BDD3301xxx) e quadrupli (es.:BDD2481xxx) che presentano più di una cifra in un unico corpo, display con doppio punto decimale (in basso a destra e in basso a sinistra), e display a 14 segmenti (che possono formare anche lettere oltre che i numeri), oppure ancora display esadecimali (come il TIL302 o il TIL311) che possono mostrare le lettere A-B-C-D-E-F oltre alle 10 cifre e ancora display che possono mostrare solo il numero uno con il simbolo + o – davanti (HDSPH5507 -anodo comune-, HDSP5508 -catodo comune-).
Nei display esadecimali o a 14 segmenti non fuoriescono i pin relativi ai tutti i singoli segmenti perchè sarebbero davvero troppi e molti hanno una logica integrata (ad esempio il TIL311) per ridurre il numero di pin necessari al controllo.
Pilotare un singolo display è piuttosto semplice, basta difatti far accendere i segmenti giusti per ottenere il numero che vogliamo. L’immagine seguente mostra come vengono comunemente indicati i segmenti di un display a led:

DP sta per Decimal Point. Supponendo di disporre di un display a catodo comune, collegheremo il catodo a massa e per comporre, ad esempio il numero 1, faremo arrivare la tensione positiva (tramite resistenze) agli anodi dei segmenti B e C: si tratta soltanto di accendere dei led, fin qui nulla di complicato.
La cosa in realtà si complica quando dobbiamo pilotare più di un display per comporre cifre di una certa grandezza. Quando dobbiamo pilotare un singolo display con un microcontrollore, supponendo di voler tralasciare il punto, abbiamo bisogno di 7 linee di comunicazione: una per ogni segmento, le linee di comunicazione si riducono a 4 se utilizziamo la codifica BCD ed un apposito circuito integrato.
Ma… Se dobbiamo pilotare 2 display? Avremmo bisogno in teoria di almeno 14 linee di comunicazione: 7 per ogni display (consideriamo sempre il caso di non voler usare il punto), oppure 8 se usiamo la codifica BCD. La cosa diventa sempre più complicata quando aumenta il numero di display.
Nella pratica, in realtà, non si agisce in questo modo ma si utilizza una tecnica chiamata Multiplexing. Tale tecnica è concettualmente molto semplice e si basa sul fenomeno della persistenza della visione: si accende un unico display per volta, ad intervalli di tempo talmente brevi da non poter essere percepiti dall’occhio umano: accendiamo prima un display, lo lasciamo acceso per pochi millisecondi, lo speghiamo e accendiamo il successivo e così via. Ma come si realizza tutto questo?
E’ molto semplice: oltre alle normali 7 linee di comunicazione (8 se vogliamo usare anche il puntino, tralasciamo in questa sede il pilotaggio con un BCD converter), avremo bisogno di una linea aggiuntiva per ogni display per pilotare il comune (l’anodo o il catodo a seconda del tipo di display che abbiamo scelto).
Ve lo spiego con un esempio: supponiamo di avere 3 display a catodo comune, di non voler usare il punto e di non voler usare un ulteriore integrato per effettuare la codifica BCD. Ci sarà bisogno quindi di 7 linee per i segmenti e ulteriori 3 linee per il pilotaggio dei catodi dei 3 display: 10 linee di output in totale. Mantenendo i catodi separati, collegheremo insieme tutti gli anodi degli stessi segmenti: collegheremo insieme i 3 pin dei 3 display che pilotano il segmento A, e così per tutti gli altri pin. Supponiamo quindi di voler mandare sui display il numero 123: nella prima fase, volendo iniziare da sinistra (possiamo pure iniziare da destra, è indifferente), dovremo prima accendere il numero 1 sul primo display: manderemo tensione ai segmenti B e C: la tensione arriverà su tutti e 3 i display perchè i segmenti uguali sono tutti collegati tra loro, ma attiveremo soltanto il catodo del primo display! In questo modo il numero 1 verrà visualizzato solo sul primo display, lo lasceremo acceso per un po’, dopodichè toglieremo la massa dal catodo del primo display (per fare questo si utilizza un transistor), predisporremo le linee per comporre il numero 2 e quindi manderemo la massa al catodo del secondo display e così via. I display si accenderanno e spegneranno così velocemente che l’occhio non sarà in grado di accorgersene e i numeri ci appariranno fissi.
Nota:
I display aventi più cifre in un unico corpo, come i BDD3301 e i BDD2481 (giusto per fare un esempio) hanno spesso già i segmenti uguali collegati insieme sia per facilitare il cablaggio, sia per rendere il packaging del componente meno “affollato”. I display BDD2481, poi, sono ottimi per realizzare, ad esempio, un orologio avendo 4 cifre separate dai due punti centrali.
In questa lezione utilizzeremo due display a catodo comune per realizzare un semplice contatore up/down: avremo un tasto che permette di incrementare il numero visualizzato e un tasto per decrementarlo.
Nella lezione successiva sfrutteremo lo stesso circuito con ulteriori due pulsanti aggiuntivi per memorizzare il numero nell’eeprom interna e quindi richiamarlo.
Utilizzando dei display a catodo comune, i segmenti si accenderanno con una tensione positiva mentre al comune viene mandata la massa utilizzando un transistor di tipo NPN. Di display a catodo comune ne esistono un’infinità, io, come potete vedere nella foto introduttiva, ho utilizzato un display doppio del tipo MAN6440, del quale riporto qui la piedinatura:
Con K1 e K2 sono indicati i catodi rispettivamente della prima e della seconda cifra, ogni segmento è seguito dal numero 1 o 2 per indicare che appartiene alla prima o alla seconda cifra. Il MAN6440, così come moltri altri tipi di display viene venduto in varie colorazioni, quello in mio possesso ha i segmenti di colore verde. Altri display che potete usare per questa lezione sono, ad esempio, i “vecchi” FND500 oppure i TDSR5160, entrambi hanno la seguente piedinatura (che è standard per numerosi modelli di display, verificate sempre e comunque il datasheet):
Di questi 3 display (e di altri) potete scaricarne il datasheet in fondo all’articolo. Comunque un display vale l’altro, ce ne sono tanti, in questa lezione, comunque, lo ripeto, l’esempio verrà fatto con display a catodo comune.
Nella foto seguente, da sinistra verso destra, sono illustrati un MAN6440, un TDSR5160 e un FND500:

Diamo quindi uno sguardo al circuito che andremo a realizzare:
Come vedete nulla di complicato, abbiamo i due pulsanti btn_up e btn_down, collegati nella solita configurazione e che avranno la funzione di incrementare e decrementare il valore del contatore. I segmenti uguali dei display sono stati collegati insieme (il segmento A del primo display è collegato con il segmento A del secondo display e così via). I catodi vengono pilotati con due transistor BJT di tipo NPN: quando alla base giunge il segnale logico alto dal picmicro, il transistor va in saturazione e porta il catodo a massa, facendo accendere i segmenti a cui abbiamo dato tensione: si utilizza un transistor perchè nel catodo comune fluisce la corrente di tutti i segmenti accesi, quindi già da 2 segmenti in poi non è possibile utilizzare il pin del picmicro in maniera diretta altrimenti si friggerebbe. Al posto del BC547 indicato nello schema potete utilizzare un NPN di bassa potenza qualsiasi.
Nella sezione Risorse di questo sito, potete scaricare gratuitamente il documento “Pinout ed equivalenze transistor bjt di bassa potenza” in maniera tale da poter sostituire i due transistor con altri che magari avete a portata di mano.
Da notare che ho omesso la parte relativa al connettore di programmazione e alla circuiteria di reset.
Bene, adesso passiamo al codice, come sempre il codice sarà formato dal modulo principale (main.c), da un file header contenente le configurazioni (settings.h) più altri file ausiliari (delay.c e delay.h utilizzati per la generazione dei ritardi). Scaricate i file della lezione in fondo all’articolo e diamo dapprima uno sguardo al file settings.h. Tralasciando le cose che ormai ci dovrebbero essere ben chiare, andiamo ad analizzare le parti essenziali per capire come funziona il programma. E’ innanzitutto da notare la riga:
18 | #define dispReg PORTB // Banco al quale sono collegati i display |
Questo l’ho fatto in maniera tale che potete modificare semplicemente “PORTB” con il banco che voi preferite se avete già realizzato uno schema simile, senza andare a cambiare tutti i “PORTB” all’interno del codice: questo è un buon modo di rendere “portabile” un codice: in futuro lo potremo modificare per adattarlo ad un altro pic o ad un’altra situazione, senza fare troppa fatica.
Proseguendo, incontriamo la definizione del valore dei segmenti:
48 49 50 51 52 53 54 | #define SA 64 #define SB 32 #define SC 16 #define SD 8 #define SE 4 #define SF 2 #define SG 1 |
In pratica cosa ho fatto: avendo collegato il segmento A dei display alla porta RB6, il segmento B alla porta RB5 ecc, ho definito dei “simboli” che mi identificano il valore numerico del bit della porta al quale il segmento è collegato (RB6 è il bit 6 della porta B, il bit 6 in decimale ha valore 64 ecc)
Poi ancora:
56 57 58 59 60 61 62 63 64 65 66 | // Segmenti da accendere in base al numero (Nn) da comporre #define N0 SA+SB+SC+SD+SE+SF #define N1 SB+SC #define N2 SA+SB+SG+SE+SD #define N3 SA+SB+SG+SC+SD #define N4 SF+SG+SB+SC #define N5 SA+SF+SG+SC+SD #define N6 SA+SF+SG+SE+SC+SD #define N7 SA+SB+SC #define N8 SA+SB+SF+SG+SC+SD+SE #define N9 SA+SB+SF+SG+SC+SD |
Non ho fatto altro che dire: per formare il numero 0 (identificato con N0), devo accendere i segmenti A, B, C, D, E, F. Così facendo è più semplice anche per voi capire cosa stiamo facendo e definirvi, perchè no, anche delle lettere (questi display possono anche visualizzare una A maiuscola, una E, una F o una b minuscola ecc ;) )
In seguito mi sono definito un’array in cui sono contenuti proprio questi numeri:
79 | const unsigned char dispnum[]={N0,N1,N2,N3,N4,N5,N6,N7,N8,N9}; |
Qui c’è da fare una precisazione sull’attributo “const”: mettendo questa parola chiave davanti alla definizione di una variabile, faccio in modo innanzitutto che questa variabile non sia allocata nella memoria RAM del mio microcontrollore ma nella memoria programma, ovvero quella destinata ad accogliere materialmente il nostro programma, appunto. E’ buono usare questa definizione quando si dichiarano valori costanti, ovvero il cui valore numerico non deve mai cambiare durante l’esecuzione del programma, questo, oltretutto, ci fa risparmiare memoria RAM, in questo caso non ne avevamo la reale necessità (di risparmiare ram), ma trattandosi di valori costanti ho preferito dichiararli come “const”. Lo scopo di questo array così dichiarato è presto detto: quando vorrò visualizzare sul mio display, ad esempio, il numero 7, mi basterà fare una cosa del tipo:
PORTB=dispnum[7];
Ovvero assocerò alla porta alla quale i display sono collegati, il valore numerico contenuto dall’elemento dell’array avente lo stesso indice numerico della cifra che voglio visualizzare.
Per il resto nulla di complicato: ci sono i prototipi delle funzioni, la dichiarazione di alcune variabili utilizzate nel programma e l’impostazione dell’interrupt ogni millisecondo come abbiamo già visto nelle precedenti lezioni.
Passiamo ora al programma principale. Il main non fa niente di eccezionale: si limita a leggere lo stato dei due pulsanti e ad incrementare o decrementare il valore del contatore, memorizzato nella variabile “counter” che è poi quella che viene visualizzata sui display. Da notare che quando ci troviamo al valore 99 e premiamo ancora il tasto di incremento, il valore viene portato a zero, al contrario se ci troviamo al valore 0 premiamo il tasto di decremento, il valore viene portato a 99, ci sono inoltre le routine antirimbalzo già viste nelle lezioni precedenti:
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | // pulsante "su" premuto if (btnUp==Pressed) { DelayMs(100); if (btnUp==Pressed) // antibounce { counter++; // incremento il contatore // se il contatore supera 99, lo azzero if (counter>99) { counter=0; } } } // pulsante "giu" premuto if (btnDn==Pressed) { DelayMs(100); if (btnDn==Pressed) // antibounce { if (counter==0) { counter=99; } else { counter--; // decremento il contatore } } } |
La parte interessante è invece svolta dalla interrupt service routine. Ogni millisecondo, la funzione ISR viene richiamata dall’interrupt causato dall’overflow del Timer0. In questa funzione abbiamo il contatore “muxcount” il quale viene incrementato ad ogni interrupt. Ogni volta che tale contatore raggiunge il valore di 5, viene invertito il flag “actdisplay” che stabilisce se deve rimanere acceso il display delle unità o quello delle decine, ogni display rimane quindi acceso per 5 millisecondi, dopodichè si spegne e viene acceso l’altro: stiamo realizzando il multiplexing.
Ci calcoliamo quindi il numero da visualizzare con delle semplici divisioni:
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | if (actdisplay==0) // devo mostrare solo le unità { displayU=ON; // accendo il display delle unità // mi calcolo quindi la sola unità da mostrare result=counter/10; // ottengo la decina (esempio: 28/10 = 2) // nota: in C la divisione tra interi restituisce un intero, quindi privo di decimali result=counter-(result*10); // ottengo la sola unità // se, ad esempio, il contatore era 28, result ora //qui vale 2, quindi dal contatore sottraggo (2*10) e ottengo 8 } else // devo mostrare solo le decine { result=counter/10; // ottengo la sola decina // accendo la decina solo se il risultato è maggiore di zero if (result) { displayD=ON; } } |
Nel caso che deve rimare acceso il display delle decine, dobbiamo visualizzare soltanto la decina: se abbiamo quindi che il valore del contatore è 28, dovremo visualizzare il solo 2, questo si ottiene semplicemente dividendo il valore del counter per 10: il risultato è un numero intero, privo dei decimali. La decina, inoltre, sarà visualizzata soltanto se il suo valore è diverso da zero. Per l’unità è la stessa cosa: faremo soltanto un’operazione in più: sottraiamo il valore della decina dal contatore per ottenere la sola unità, il concetto è molto semplice; basta tener conto che in C la divisione tra interi restituisce un intero, quindi privo dei decimali.
In seguito associo al registro, sul quale sono collegati i display, il valore numerico da visualizzare, che è stato memorizzato nella variabile “result”:
130 | dispReg=dispnum[result]; |
Quindi eseguo delle altre operazioni:
134 135 136 137 138 139 140 141 142 | if (muxcount==5) { muxcount=0; // azzero il contatore actdisplay=actdisplay^1; // cambio il display per il prossimo ciclo dispReg=0; // azzero il display attualmente visualizzato //per prevenire l'effetto "ghosting" displayU=OFF; // spengo display unità displayD=OFF; // spengo display decine } |
In pratica: azzero il contatore del multiplexer se ha raggiunto il valore di 5, in maniera da cambiare il display da accendere. E’ interessante la riga:
138 | dispReg=0; |
Questo in pratica viene fatto per eliminare l’effeto di “ghosting“, ovvero la scia rimasta dalla cifra precedente: provate a vedere cosa succede eliminando questa riga, in realtà l’effetto potrebbe non notarsi a determinate frequenze e con determinati display.
Infine resetto il flag di interrupt sul timer0, altrimenti non lo posso più intercettare:
144 | T0IF=0;// Reset flag interrupt su timer 0 |
Nel file seguente è contenuto il codice sorgente completo:
File di supporto alla ottava lezione del corso di programmazione picmicro in C (188)
Se volete realizzare questo esempio con display ad anodo comune anzichè a catodo comune dovete tenere conto che:
- Al posto di transistor NPN dovrete utilizzare PNP e i display non verranno più attivati con livello logico alto ma con livello logico basso.
- I singoli segmenti dei display non si attiveranno più mettendo ad 1 il relativo bit ma mettendolo a zero. Quindi per definire i segmenti da accendere per ogni singolo numero anzichè fare, ad esempio, SA+SB, farete: 255-(SA+SB)
Se volete realizzare questo programma utilizzando più di 2 display vi fornisco qui solo due consigli principali, il resto ormai dovreste essere bravi per intuirlo da soli:
- La variabile destinata a contenere il conteggio non potrà essere più di tipo CHAR perchè il tipo CHAR, essendo ad 8 bit, contiene al massimo un numero fino a 255.
- Il flag “actdisplay”, utilizzato in questo esempio per effettuare lo switch del display, non potrà essere più di tipo BIT ma dovrà essere di tipo CHAR e gestito come un contatore, si deciderà quindi quale display accendere tramite una struttura SWITCH…CASE
Datasheets
- MAN6440 - Display a led 7 segmenti, 2 cifre, catodo comune (107)
- TDSR5150 - Display a led 7 segmenti, catodo comune (72)
- FND500 - Display a led 7 segmenti, catodo comune (73)
- BDD3301XXX - Display a led 7 segmenti, 3 cifre (69)
- BDD2481XXX - Display a led 7 segmenti, 4 cifre con due punti di separazione (80)
- HDSPxxxx - Display a led 7 segmenti, singola e doppia cifra, anodo e catodo comune (79)
Articoli che potrebbero interessarti:




#1 da S.D.R. il 6 dicembre 2009
Ti sei meritato un buon cappuccino , se ti sei svegliato ora ;-)
Grazie , l’articolo che aspettavo , volevo fare un po’ di esperimenti con il display 7 seg , prima di tutto un maxi orologio facendo con i led 5mm i segmenti (5x segmento) .
Poi provare con le porte analogiche a leggere o la temperatura ambiente con lm35 o una tensione .
Quindi penso che ti romperò le scatole spesso .
#2 da Giovanni Bernardo il 6 dicembre 2009
Buongiorno e grazie :)
E’ una bella idea la tua, ti do dei consigli da non sottovalutare per questo tuo progetto.
Per fare un maxi orologio come dici tu non puoi più pilotare i segmenti direttamente con le uscite del pic, devi per forza mettere un transistor per ogni segmento, calcolati bene quanto assorbe ogni segmento e quindi scegli il transistor più adatto, magari può andare bene un array di transistor (tipo ULN2003 per fare un esempio) così rendi tutto più compatto.
Utilizzando il catodo comune avrai bisogno quindi di un NPN per il catodo (ma arrivati a questo punto ce ne vuole uno più grosso del bc547 o simili: tieni conto che quando tutti i segmenti saranno accesi, fluirà la corrente di 35 led!) e di 7 PNP per gli anodi.
Pilotare i display con multiplex tramite interrupt ti facilita di molto le cose: rendi il programma più veloce e indipendente dal resto. Puoi fare pure i due puntini di separazione dell’orario lampeggianti: metti una variabile che si incrementa nell’interrupt: ogni mezzo secondo inverti lo stato del pin che comanda l’accensione dei puntini, così si accenderanno ogni secondo. Poi magari, ogni dieci secondi cambi la visualizzazione per mostrarti la temperatura, come negli orologi che si vedono nelle stazioni ecc. Una volta fatto il “circuitone” su cui piazzare tutti i led, resistenze e transistor, ti conviene coprire il tutto con una lastra sottile di plexiglass scuro dello stesso colore che hai scelto per i segmenti e quindi ti devi dedicare solo al software di pilotaggio. Una mano te la do sempre volentieri, quello che mi frega è il tempo che ho a disposizione.
#3 da S.D.R. il 6 dicembre 2009
Grazie per i consigli , avevo già deciso di usare un uln2003 per pilotare i led , fortunatamente collaudo schede elettroniche in una ditta che le assembla quindi vedo i diversi sistemi che usano i clienti per le varie schede e soprattutto posso trovare tutti i componenti che mi servono .
Anche tu mi leggi nel pensiero , volevo proprio fare in modo che si alternasse l’ora con la visualizzazione della temperatura , però faccio un passo alla volta altrimenti mi complico troppo la vita .
Purtroppo neppure io ho tantissimo tempo e poi alle volte dopo avere visto schede elettroniche per 8 ore non ho molta volglia di continuare a lavorarci .
Poi in questo periodo c’è stato un risveglio generale di tutti i clienti quindi il titolare vuole entro l’anno consegnare il più possibile visto che i mesi precedenti sono stati davvero magri .
A proposito di temperatura, hai mai usato i sensori di temperatura NTC o PTC , so che non sono lineari quindi bisogna fare dei calcoli particolari tramite il micro , con LM35 sarebbe molto più semplice la cosa ma vedo che molti clienti li usano quindi volevo capire come si gestiscono via software ?!
#4 da Giovanni Bernardo il 6 dicembre 2009
Non ho mai usato NTC o PTC per temperature, ma non penso siano molto buoni per fare un termometro, sono più adatti per un semplice termostato. Fin’ora ho usato soltanto l’LM35, è semplicissimo da utilizzare: solo 3 terminali, alimentazione e segnale: il segnale in uscita è 10mv per ogni grado centigrado, con una porta analogica del pic lo leggi semplicemente e con l’ADC a 10 bit hai una risoluzione di mezzo grado (visualizzerai ad esempio 20,0 – 20,5 – 21,0 ecc ma non 20,2 o cose del genere).
http://www.national.com/mpf/LM/LM35.html#Overview
Altro sensore molto usato è il DS18S20 ma utilizza un protocollo di comunicazione, l’LM35 è molto più semplice da gestire, lo leggi come se fosse una resistenza variabile, inoltre costa 4 soldi, se lo ordini su ebay, pure dalla cina, lo paghi davvero una fesseria.
Per alternare la visualizzazione orario/temperatura non credere sià cosi difficile: basta utilizzare sempre dei contatori. Un suggerimento è quello di utilizzare una variabile globale utilizzata soltanto per pilotare il display, ogni dieci secondi, ad esempio, a questa variabile viene alternato il valore di orario o di temperatura.
Avrai in pratica 3 variabili: una di appoggio che serve solo per pilotare i display, una per l’orario (che puoi gestire come un normale contatore, da incrementare ogni minuto, ovviamente dovrai gestire i minuti e le ore a parte su altre 2 variabili per fare in modo da aumentare le centinaia quando i minuti sono diventati 60 ecc ecc), e una per la temperatura. Ogni 10 secondi assegni alla variabile da visualizzare l’orario o la temperatura.
#5 da Giovanni Bernardo il 6 dicembre 2009
Adesso non so di che dimensioni vuoi fare l’orologio, ma facendo una rapida ricerca su ebay si trovano a prezzi irrisori dei display a led anche di 7.6 centimetri di altezza (3 pollici), a un prezzo un bel pò più elevato ci sono pure display da quasi 13cm…. almeno ti risparmi il cablaggio dei led… è solo un’idea
#6 da robcar il 7 dicembre 2009
Ottimo articolo, come sempre d’altronde! Quindi meritevole di donazione per caffè :-)
Proprio ieri pomeriggio stavo sperimentando con i display e dei transistor, per realizzare praticamente lo stesso progetto presentato qui, ma in assembly. E tra l’altro con 2 display distinti, quindi con il ‘pain in the ass’ derivato dai collegamenti tra i 2…
Mi ero fermato all’implementazione della gestione del multiplexing; contavo anch’io di sfruttare l’overflow del timer0, mi mancava il passo successivo della variabile muxcount per gestire l’uno o l’altro.
Ho 1 domanda del ‘piffero’: ho visto che è sufficiente collegare 1 solo catodo comune K per display (a massa o al collettore del transistor) affinchè il display si accenda. Quale può essere la controindicazione?
Grazie e … keep up the good work! :-)
#7 da Giovanni Bernardo il 7 dicembre 2009
Ciao e grazie :)
Alla fine due display separati o due in un solo corpo cambia poco, il mio, che porta due display in un solo corpo ha comunque i segmenti separati, sono quelli da 3 cifre in poi che hanno generalmente tutti i segmenti uguali già collegati insieme. Probabilmente esisteranno pure quelli da due cifre con già i segmenti collegati ma non ho avuto modo di incontrarli :D
La tua non è una domanda del piffero perchè me lo sono chiesto anch’io. Suppongo che la presenza di due catodi sia una scelta per rispettare in qualche modo il packaging di 5+5 piedini (facci caso che questi display li puoi anche montare sugli zoccoli degli integrati, quelli più larghi), avanzava un piedino e quindi ci hanno messo un altro catodo. In alcuni progetti che ho già ho realizzato e sono egregiamente in funzione, ne ho collegato uno solo per motivi di spazio e non danno problemi. Il display doppio difatti ha un solo catodo per cifra e non due e questo mi ha portato a pensare che magari la scelta di due catodi non derivi da un maggiore assorbimento di corrente ma proprio perchè avanzava un piedino. Comunque potrei anche sbagliarmi, nel dubbio, se lo spazio ce l’hai, collegali entrambi.
#8 da Giovanni Bernardo il 7 dicembre 2009
Ah dimenticavo! Il catodo lo devi collegare per forza al collettore del transistor e non a massa, altrimenti sui display ti appare sempre 88 o comunque un numero che deriva dalla “fusione” delle due cifre che dovrebbero apparire separate.
#9 da robcar il 7 dicembre 2009
Hai ragione, non mi sono spiegato bene. E’ che il primo esperimento l’ho effettuato con un solo display e quindi, in tal caso, ho collegato il catodo a massa ed era a questo caso a cui mi riferivo (1 solo display).
#10 da S.D.R. il 7 dicembre 2009
Scusa la domanda ma se invece di scrivere :
const unsigned char dispnum[]={N0,N1,N2,N3,N4,N5,N6,N7,N8,N9};
scrivo :
const unsigned char dispnum[]={0×3F,0×06,0X5B,0×4F,0×66,0×6D,0×7D,0×07,0×7F,0×6F};
eliminando tutta la parte superiore dove definisco i segmenti è lo stesso giusto ?
#11 da Giovanni Bernardo il 7 dicembre 2009
Non ho controllato se N0 vale 3F ecc ecc ma il concetto è quello li, puoi eliminare le somme e tutto il resto e mettere nell’array direttamente i valori, certo. Ho fatto in quel modo per far capire cosa stavo facendo, essendo una spiegazione non era il caso di mettere quei numeri senza far capire da dove venivano fuori.
#12 da marco814 il 8 dicembre 2009
ciao, ho trovato tutte le lezioni molto interessanti… specialmente per chi come me partiva da zero…. per provare i programmi spiegati io utilizzo il pic18f4580… mi sai dire per quale motivo mi da questi avvertimenti??? premetto pero che i programmi funzionano:
Advisory[1233] Employing 18F4580 errata work-arounds:
Advisory[1234] * Corrupted fast interrupt shadow registers
#13 da Giovanni Bernardo il 8 dicembre 2009
per Marco:
Non ti so dire, ma se non erro i pic18 hanno due livelli di interrupt e probabilmente l’avvertimento è relativo al fatto che non li stai utilizzando come dovrebbero essere utilizzati. Difatti è solo un avvertimento e non un errore, perciò ti funziona lo stesso.
#14 da S.D.R. il 9 dicembre 2009
Ciao givanni ;
Ho modificato un po’ il programma usando lo switch invece dell’istruzione if-else , per vedere se funzionava , per poi passare a 4 display .
Funziona, te lo posto così mi dici cosa ne pensi .
if (T0IF)
{
TMR0=8;
muxcount++;
switch (actdisplay)
{
case 0:
displayU=ON;
result=counter/10;
result=counter-(result*10);
break;
case 1:
result=counter/10;
if (result)
{
displayD=ON;
}
break;
}
dispReg=dispnum[result];
#15 da S.D.R. il 9 dicembre 2009
Mamma mia ogni volta che faccio una prova devo sempre chiederti un parere :
Su case 1 che si vede nel post sopra ho provato a toglere l’istruzione if ed ho modificato come sotto e vedo che funziona allo stesso modo , lo vedo perchè ho portato il prescaler a 30ms per vedere bene il comportamento dei display .
case 1:
displayD=ON;
result=counter/10;
break;
sicuramente se hai messo :
if (result)
{
displayD=ON;
}
Vuol dire che serve , mi aiuti a capire per favore !?
#16 da Giovanni Bernardo il 9 dicembre 2009
Allora… Riguardo al primo caso è ok, è quella li la cosa che devi fare per più di due display. Fino a due display puoi usare una variabile di tipo booleano, da 3 valori in poi ci vuole almeno una variabile char e la analizzi con una struttura switch…case come hai fatto, quindi ok.
Quell’If per verificare se result è diverso da zero lo metto per evitare di visualizzare lo zero quando non ci vuole. Se vuoi visualizzare sui display 3, se ometti quell’if sui due display apparirà 03. Se ti piace far uscire lo zero non significativo, allora lo ometti. Ecco perchè quella verifica non la faccio sulla unità, perchè li lo zero deve apparire. Se invece utilizzi 3 display la cosa si complica, perchè devi fare la verifica solo se la centinaia è zero. Se la centinaia è zero non la fai apparire, ma in questo caso effettui pure la verifica della decina. Se la centinaia è diversa da zero, allora la verifica del diverso da zero sulla decina non la fai… Spero di essere stato chiaro…
#17 da Giovanni Bernardo il 9 dicembre 2009
Se non sono stato chiaro dimmelo
#18 da S.D.R. il 9 dicembre 2009
Sei stato anche troppo chiaro , grazie !
Ho fatto la prova e infatti appare lo zero sulle decine .
Mi sono reso conto che era una cosa banale , d’altronde ho cominciato da poco con l’ANSIC e non ho ancora l’elasticità mentale per comprendere subito le cose .
Ora sto provando con 3 display .
#19 da S.D.R. il 10 dicembre 2009
Credevo di esserci riuscito senza alcun intoppo invece … da 100 a 109 , 200 a 209 e così via non mi appaiono le decine .
Dove ho messo la freccia sicuramente c’è il problema :
case 1: // decine
result=counter/100;
result=counter-(result*100);
result=result/10 ;
if (result) <————–
{
displayD=ON;
}
break;
ho provato a mettere if(!displayC) e funziona finchè non scendo sotto al 10 dopo di che ho sulle decine lo zero .
Purtroppo devo chiedere ancora il tuo aiuto .
#20 da Giovanni Bernardo il 10 dicembre 2009
La decina deve apparire se anche la centinaia è diversa da zero, devi controllare prima la centinaia stesso dove controlli le decine…
Hai 2 situazioni limite:
es.: numero 3 => non hai centinaia, non hai decine e non devi mostrare 003
es.: numero 101 => hai le centinaia, lo zero delle decine però lo devi mostrare
prova con questo (non l’ho testato e dato l’orario stai attento, il concetto è comunque quello li):
case 1: // decine
char centinaia=counter/100; // memorizzo le centinaia in una variabile
result=counter-(centinaia*100); // risultato senza centinaia
result=result/10 ; // decina
if (centinaia) // le centinaia ci sono? si
{
displayD=ON; // mostro le decine in ogni caso
}
else // le centinaia non ci sono
{
if (result) // ma le decine ci sono? si
{
displayD=ON; // mostro le decine
}
}
break;
In pratica devi sempre scomporre il problema in pezzi più piccoli, in questo caso devi analizzare due casi: le centinaia ci sono e le centinaia non ci sono.
Nel caso che le centinaia ci sono, allora la decina la devi mostrare sempre in ogni caso anche se è zero.
Nel caso che le centinaia non ci sono, allora la decina la devi mostrare solo se è diversa da zero.
Con le migliaia la cosa diventa ancora più complicata. Ti fai sempre i due macrocasi: migliaia ci sono, migliaia non ci sono, ognuno dei due lo scomponi nei vari casi ecc ecc.
Fammi sapere se funziona.
#21 da S.D.R. il 10 dicembre 2009
Si funziona !!!
Ho però aggiunto le variabili unità,decine ,centinaia per capirmi meglio ed il risultato è questo :
interrupt isr(void)
{
if (T0IF)
{
TMR0=8;
muxcount++;
switch (actdisplay)
{
case 0: //unita
displayU=ON;
centinaia=counter/100;
decine=(counter-(centinaia*100))/10;
unita=(counter-(centinaia*100))-(decine*10);
result=unita;
break;
case 1: // decine
centinaia=counter/100;
decine=(counter-(centinaia*100))/10;
result=decine;
if (centinaia)//le centinaia ci sono?
{
displayD=ON;// SI –> accendi il display Decine
}
else // non ci sono le centinaia
{
if(decine) // ma le decine ci sono ?
{
displayD=ON; // SI –> accendi il display Decine
}
}
break;
case 2: // centinaia
centinaia=counter/100;
result=centinaia;
if (centinaia)
{
displayC=ON;
}
break;
}
dispReg=dispnum[result];
if (muxcount==5)
{
muxcount=0; // azzero il contatore
actdisplay=actdisplay+1; // cambio il display per il prossimo ciclo
if (actdisplay>3)
{
actdisplay=0;
}
dispReg=0; // azzero il display attualmente visualizzato
//per prevenire l’effetto “ghosting”
displayU=OFF; // spengo display unità
displayD=OFF; // spengo display decine
displayC=OFF; // spengo display centinaia
}
T0IF=0;// Reset flag interrupt su timer 0
} // End T0IF
} // End ISR
// EOF
#22 da S.D.R. il 11 dicembre 2009
A gran fatica sono riuscito a pilotare 4 display senza errori di visualizzazione .
Però si nota un leggero lampeggio da 40 a 99 , da 120 a 999 ,da 1020 a1099 da ,1120 fino oltre 2000 , non avevo voglia di arrivare fino a 9999 .
Allora ho messo muxcount==4 , ora non si nota più il lampegio però passando da 119 a 120 lo zero delle unità di 120 aumenta di luminosità .
void interrupt isr(void)
{
if (T0IF)
{
TMR0=8;
muxcount++;
switch (actdisplay)
{
case 0: //unita
displayU=ON;
migliaia=counter/1000;
centinaia=(counter-(migliaia*1000))/100;
decine=((counter-(migliaia*1000))-(centinaia*100))/10;
unita=((counter-(migliaia*1000))-(centinaia*100))-(decine*10);
result=unita;
break;
case 1: // decine
migliaia=counter/1000;
centinaia=(counter-(migliaia*1000))/100;
decine=((counter-(migliaia*1000))-(centinaia*100))/10;
result=decine;
if(decine) //decine>0
{
displayD=ON; //SI accendi decine
}
else //decine0
{
displayD=ON; //si accendi decine
}
else //centinaia0
{
displayD=ON; //Si accendi decine
}
//else //migliaia0
{
displayC=ON; //Si accendi centinaia
}
else //migliaia0
{
displayC=ON; //accenti centinaia
}
}
break;
case 3: // migliaia
migliaia=counter/1000; //1
result=migliaia;
if (migliaia) //
{
displayM=ON;
}
break;
}
dispReg=dispnum[result];
if (muxcount==4)
{
muxcount=0; // azzero il contatore
actdisplay=actdisplay+1; // cambio il display per il prossimo ciclo
if (actdisplay>4)
{
actdisplay=0;
}
dispReg=0; // azzero il display attualmente visualizzato
//per prevenire l’effetto “ghosting”
displayU=OFF; // spengo display unità
displayD=OFF; // spengo display decine
displayC=OFF; // spengo display centinaia
displayM=OFF; // spengo display migliaia
}
T0IF=0;// Reset flag interrupt su timer 0
} // End T0IF
} // End ISR
#23 da Giovanni Bernardo il 11 dicembre 2009
Ok, perfetto.
L’aumento di luminosità non me lo so spiegare, anche perchè il numero di segmenti accesi è sempre lo stesso sia con 9 che con zero… Ma comunque sia non può dipendere dal numero di segmenti accesi perchè ogni segmento è pilotato da un pin differente… Boh… non mi viene in mente nessuna spiegazione… ci devo ragionare un po’
#24 da Giovanni Bernardo il 11 dicembre 2009
Non è che per caso, riguardo alla diversa luminosità, non c’è qualche problema sul circuito? Falsi contatti, resistenze di valore diverso, saldature fredde ecc
#25 da S.D.R. il 11 dicembre 2009
Non credo , con due display non dava questo problema poi con quattro display il problema c’è solo con alcuni numeri .
#26 da S.D.R. il 11 dicembre 2009
Allora visto che ho un oscilloscopio anche se vecchiotto ho controllato il segnale sulla base tel transistor del primo display e si nona che il tON quando il numero visualizzato è 119 è di 5ms invece con 120 ho circa 9 ms , invece il tOFF rimane invariato .
#27 da S.D.R. il 11 dicembre 2009
Risolto , avevo notato il tOFF di 20ms un po’ troppo lungo ,sicuramente dovuto al fatto che avevo 4 display e non più 2 , allora ho impostato il prescaler per avere 0,25ms però mi trovo sempre tON 5ms invece tOFF 10ms , pensavo di trovarmi tON 1.25ms e tOFF 5ms .
Il tON sul primo display non varia più come prima da 119 a 120 , tu che dici !?
#28 da S.D.R. il 12 dicembre 2009
Pensavo di esserci riuscito , invece …
Allora un periodo di DispON+DispOFF=14ms circa
Display Unità DispON=5ms DispOFF=9ms ,
Display Decine DispON=4ms DispOFF=10ms ,
Display centinaia DispON=2ms DispOFF=12ms ,
Display migliaia DispON=1ms DispOFF=13ms .
Poi se il display delle migliaia è spento il periodo aumenta .
void interrupt isr(void)
{
if (T0IF)
{
TMR0=8;
muxcount++;
switch (actdisplay)
{
case 0: //unita
displayU=ON;
migliaia=counter/1000;
centinaia=(counter-(migliaia*1000))/100;
decine=((counter-(migliaia*1000))-(centinaia*100))/10;
unita=((counter-(migliaia*1000))-(centinaia*100))-(decine*10);
result=unita;
break;
case 1: // decine
migliaia=counter/1000;
centinaia=(counter-(migliaia*1000))/100;
decine=((counter-(migliaia*1000))-(centinaia*100))/10;
result=decine;
if(decine) //decine>0
{
displayD=ON; //SI accendi decine
}
else //decine0
{
displayD=ON; //si accendi decine
}
else //centinaia0
{
displayD=ON; //Si accendi decine
}
}
}
break;
case 2: // centinaia
migliaia=counter/1000; //1
centinaia=(counter-(migliaia*1000))/100; //2
result=centinaia;
if (migliaia) //migliaia>0
{
displayC=ON; //Si accendi centinaia
}
else //migliaia0
{
displayC=ON; //accenti centinaia
}
}
break;
case 3: // migliaia
migliaia=counter/1000; //1
result=migliaia;
if (migliaia) //
{
displayM=ON;
}
break;
}
dispReg=dispnum[result];
if (muxcount==5)
{
muxcount=0; // azzero il contatore
actdisplay=actdisplay+1; // cambio il display per il prossimo ciclo
if (actdisplay==4)
{
actdisplay=0;
}
dispReg=0; // azzero il display attualmente visualizzato
//per prevenire l’effetto “ghosting”
displayU=OFF; // spengo display unità
displayD=OFF; // spengo display decine
displayC=OFF; // spengo display centinaia
displayM=OFF; // spengo display migliaia
}
T0IF=0;// Reset flag interrupt su timer 0
} // End T0IF
} // End ISR
Prescaler impostato per avere 0,25ms .
#29 da Giovanni Bernardo il 17 dicembre 2009
Ho recuperato una bellissima schedina da un vecchio strumento, riportante 5 mini-display a 7 segmenti già collegati… Dal momento che per mancanza di tempo sperimento spesso su breadboard… capita proprio a fagiuolo. Spero di riuscire (incrocio le dita) a provare con tutti e 5 i display e ti faccio sapere, nel frattempo se risolvi, facci sapere.
#30 da S.D.R. il 15 dicembre 2009
Ciao Giovanni , Ma che fine hai fatto , sei andato a fare la settimana bianca !?
#31 da Giovanni Bernardo il 15 dicembre 2009
Seeee… Magari potessi permettermelo… Sono molto impegnato a casa. Hai risolto il problema dei display? Sfarfallano ancora? Penso sia un problema dovuto ai calcoli da effettuare. Prova a mettere un quarzo a frequenza più elevata.
#32 da S.D.R. il 15 dicembre 2009
Hai famiglia , perchè allora si che hai un bel da fare ?! ;-)
Il problema del display ho constatato che è dovuto ai diversi tempi di ON Off che hanno i 4 display , verificato con l’oscilloscopio i tempi li ho messi sul commento che ho scritto sopra .
Ho diminuito i tempi del prescaler , non sfarfallano più ma il display delle unità è più luminoso , e ho scoperto che ha un tempo di accensione più lungo degli altri display .
#33 da S.D.R. il 17 dicembre 2009
Grazie giovanni ;
Anche io uso la bread board però mi sono fatto una schedina con la millefori con il micro mettendo gli strip in linea ( PORTA,B,C , Vcc , Vss) il quarzo è collegato su di essa ed ho messo uno strip 90° per il programmatore così posso fare i collegamenti come voglio , la demo board non mi ispira molto proprio per il fatto che sono vincolato nei collegamenti , preferisco farmi delle schede con i millefori e tramite la bread board le collego una con l’altra e se voglio cambio i collegamenti velocemente .
Con il display non sono ancora riuscito a risolvere , ho provato a guardare in rete se trovavo qualche esempio ma non ho trovato nulla .
Poi avevo cominciato a stendere qualche riga per l’orologio ma anche li ho qualche difficoltà .
#34 da S.D.R. il 17 dicembre 2009
Quando abbiamo risolto il problema dei display pensavo di aprire una discussione per il progetto dell’orologio su FaceBook che ne dici ?
#35 da Giovanni Bernardo il 18 dicembre 2009
Per me va bene, non penso che parteciperà qualcuno perchè non vedo molte persone attive su questo argomento, comunque… per me ok… Anche se forse sarebbe meglio aprirla qui per tenere tutto insieme… Magari vedo di mettere sul sito un’area a mo’ di forum… ci penso un po’
#36 da S.D.R. il 18 dicembre 2009
Infatti manca un’area per le discussioni o un forum su questo sito , comunque vedrai che con il tempo la gente parteciperà , sei uno dei pochi a trattare la programmazione con l’ANSIC sui Pic .
Non dirmi che sono praticamente l’unico che quì ti stressa la vita !?
#37 da Giovanni Bernardo il 18 dicembre 2009
A dire il vero all’inizio mi pareva ce ne fossero molti di più. Dalle statistiche mi risultano parecchie persone che seguono, ma mi pare davvero strano che nessuno commenta o abbia da dire… Va be che in molti mi contattano via email…
Per me non è uno stress, ho concepito queste lezioni un po’ perchè mi hanno spinto degli amici e un po’ perchè per me è una specie di “blocchetto degli appunti” dove poter fissare per bene le cose e quindi svuotare tutte le cartelline che riempio con le mie scartoffie… un esempio tutti quei calcoli sul prescaler e il timer0, credi che abbia trovato spiegazioni fatte per bene in giro? Solo datasheet, esempi in assembler della microchip e carta e penna, senza carta e penna non riesco nemmeno a pensare, pure che devo disegnare solo una linea ne ho bisogno, e cosi accumulo sempre cartacce che dopo qualche anno perdono significato perchè la memoria viene occupata da altro. E’ anche un modo per continuare ad imparare condividendo il tutto con persone interessate e che interagiscono attivamente, non credere che io sia esperto, difatti a volte un po’ penso di aver sbagliato a scrivere “lezioni” ma piuttosto avrei dovuto scrivere “appunti”… Quando si interagisce costruttivamente non è mai uno stress.
#38 da S.D.R. il 18 dicembre 2009
Ciao Giovanni ;
Sono riuscito a recuperare un paio di PIC18F452 in smd , che sia traumatico passare a questo componente , e se volessi passare ad un atmel o Friscale cambia molto? Perchè ho recuperato anche un ATMEGA16L8AU, poi potrei anche recuperare dei MC68HC908 sempre in smd .
So già che dovrei usare un altro compilatore ma come comandi ANSIC pensi che cambi tanto !?
Buon VeekEnd intanto , dicono che al nord nevicherà già da questa notte , anche dove vivo io a Padova , tu dove abiti !?
#39 da Giovanni Bernardo il 18 dicembre 2009
I PIC18 possono essere programmati in C così come programmi i PIC16, oppure anche in C18. Per gli atmel, freescale ecc non ti so dare consigli perchè non li ho mai utilizzati, anche se in effetti se si utilizza un compilatore ANSI C, le istruzioni dovrebbero rimanere quelle a parte le cose relative all’hardware del controllore in oggetto. Io sto in provincia di Caserta, fa parecchio freddo ma neve ancora niente, generalmente qui comunque non la fa mai. Mio cugino a Torino invece stamattina si è svegliato con un bel manto di neve, beato lui… Natale con la neve è più magico :)
#40 da Giovanni Bernardo il 18 dicembre 2009
Se fai qualcosa in C con gli Atmel o i Freescale e ti va di buttare giù qualche appunto (pure una cosa semplice come accendere un led partendo dall’installazione del sistema di sviluppo e del programmatore), lo possiamo mettere tra gli articoli (a nome tuo ovviamente)
#41 da S.D.R. il 18 dicembre 2009
Volentieri , però è meglio che prima prendo un po’ più dimestichezza con i pic , penso che intanto mi farò una scheda con il PIC18F452 .
Questa sera la fidanzata non se la sente di uscire perchè dalle sue parti nevica già (a Rovigo) quindi mi metto sotto per vedere se riesco a risolvere il problema del display , tu a che punto sei con il display che hai recuperato ?
#42 da Giovanni Bernardo il 19 dicembre 2009
A zero… Anche perchè mi si sono pure rotti insieme saldatore e tester, penso che riprenderò dopo le feste
#43 da Giovanni Bernardo il 19 dicembre 2009
Per farti una demoboard col pic in smd ci sono anche delle millefori fatte apposta che hanno nella parte centrale i pad per gli integrati in smd, tipo questa per intenderci:
http://www.robot-italy.com/product_info.php?products_id=1246
su ebay, soprattutto dai venditori cinesi, ce ne sono a bizzeffe e a prezzi stracciati, devi solo attendere circa un mese per la spedizione.
Appena riesco ad ordinare la stazione saldante penso di tuffarmi pure io nell’smd, in alcuni casi la scelta è davvero obbligata, mi capita troppe volte di dover infilare degli automatismi in spazi troppo angusti, ogni tanto posta pure qualche foto degli esperimenti sullo spazio di facebook. Altrimenti posso provvedere a mettere qui una galleria di immagini
#44 da S.D.R. il 19 dicembre 2009
Tu lo sapevi che volento su MPLAB IDE si può selezionare un editor esterno , mettendo per esempio Notepad++ ?
Configure /settings…/External Editor , si spunta Use External Editor e poi tramite Browse… si seleziona l’editor che si vuole usare .
Ora vado molto meglio , una volta che hai creato il progetto se apri il file di testo main.C si apre direttamente Notepad++ .
Tramacciando ogni tanto scopro cose nuove , altre vabbe , faccio anche casini , ma sbagliando si impara .
Pera fare la schedina con il PIC in smd posso farmela anche da solo sono diventato abbastanza pratico nel disegnare ed incidere i circuiti stampati , come cad uso CadSoft Eagle e per fare gli stampati uso i fogli blu che si stampano con la stampante al laser e poi si stirano vengono abbastanza bene anche per i componenti in smd .
Poi l’smd me lo mangio anche a colazione ormai ,come nel video “breakfast” che hai postato su FaceBook , hehehe !
#45 da Giovanni Bernardo il 19 dicembre 2009
Si l’avevo sentito ma a dire il vero non l’ho mai usato perchè ho l’abitudine di tenere aperto notepad++ coi file interessati ed mplab insieme.
Per gli stampati devo fare una prova col metodo del ferro da stiro sui fogli fotografici o sulle copertine patinate dei giornali. Ho fatto un’adattatore ttl/rs232 con eagle e ora l’ho stampato sulla copertina di un giornale. Se mia moglie mi presta il ferro da stiro (qua in casa ognuno è geloso dei propri “attrezzi” haha), faccio sta prova, in molti mi hanno detto che va bene.
#46 da S.D.R. il 19 dicembre 2009
Prova prova che funziona veramente bene , con la carta patinata non ho mai provato , bisogna solo prendere mano perchè il toner tende un po’ a spalmarsi e le piste si allargano un po’ rischiano di fare corto circuito l’una con l’altra , trovato la temperatura giusta , tempo di stiratura e pressione adatta da esercitare con il ferro da stiro sulla scheda questo problema non si crea .
Se usi il, ferro da stiro di tua moglie è meglio che interponi tra la scheda e il ferro da stiro uno straccio (se lo rovini rischi il divorzio ), io di solito metto un foglio bianco .
#47 da S.D.R. il 19 dicembre 2009
Forse ho trovato una soluzione per i display , ho solo una domanda :
Con DelayMs() come faccio a mettere valori minori di 1 e con la vircola , devo mettere un valore di 0,5ms .
#48 da S.D.R. il 19 dicembre 2009
Che scemo che sono , la soluzione è sul file delay.h , è scritto la , devo scrivere DelayUs() e si intende microsecondi .
#49 da S.D.R. il 19 dicembre 2009
Allora il problema erano le unità dove il display veniva sempre acceso mettendo l’istruzione “displayU=ON;” all’inizio e se scrivo sul case 0 :
case 0: //unita
migliaia=counter/1000;
centinaia=(counter-(migliaia*1000))/100;
decine=((counter-(migliaia*1000))-(centinaia*100))/10;
unita=((counter-(migliaia*1000))-(centinaia*100))-(decine*10);
result=unita;
if(unita)
{
displayU=ON;
}
else
{
displayU=ON;
}
break;
Non ci sono più differenze di tempi di accensione tra il display delle unità e gli altri , si notando delle piccole fluttuazioni (solo sul display delle unità) tra 0 e 9999 ma molto lievi rispetto a prima .
Variando il prescaler ho notato che varia anche la risposta dei tasti , se lo diminuisco diventa più lesta cioè tenendo premuto uno dei tasti il valore cresce o diminuisce più lentamente .
Volevo fare un tempo di display ON=OFF=1ms ,bisognerebbe fare in modo che i tempi dei display siano indipendenti dal precaler .
Che ne dici ?
#50 da Andrea il 14 gennaio 2010
Ciao Giovanni, seguendo la lezione ho tentato di costruire un orologio che mostra minuti e ore pilotando 4 display, per quanto riguarda i minuti tutto ok, ma quando i minuti arrivano a 60 le ore non aumentano e rimangono a 0 ti posto il codice, ti prego dammi una mano perchè nn so più dove sbattere la testa.
#include
__CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS & UNPROTECT);
#define XTAL_FREQ 20MHZ
#include “delay.c”
#include “settings.h”
void main(void)
{
settings();
while(1)
{
//Un pulsantino che fa avanzare i minuti quando premuto
if(button == 0)
{
DelayMs(75);
if(button==0)
{
minuti++;
if(minuti == 60)
{
minuti = 0;
secondi = 0;
ore++;
if(ore = 24)
{
ore = 0;
minuti = 0;
secondi = 0;
}
}
}
}
}
}
void interrupt isr(void)
{
if(T0IF)
{
TMR0=98;
intCount++;
lamp++;
if(lamp == 1000)
{
lamp = 0;
if(button == 1)
secondi++;
if(secondi == 60)
{
secondi = 0;
minuti++;
ore++;
if(minuti == 60)
{
minuti = 0;
secondi = 0;
if(ore = 24)
{
ore = 0;
minuti = 0;
secondi = 0;
}
}
}
}
if(intCount == 3)
{
if(actDisplay == 4)
actDisplay = 0;
else
actDisplay++;
intCount = 0;
dispReg = 0;
catodo1 = 0;
catodo2 = 0;
catodo3 = 0;
catodo4 = 0;
}
switch (actDisplay)
{
//decine ore
case 1:
result = ore / 10;
dispReg = dispnum[result];
catodo1 = 1;
break;
//unita ore
case 2:
result = ore % 10;
dispReg = dispnum[result];
catodo2 = 1;
break;
//decine minuti
case 3:
result = minuti / 10;
dispReg = dispnum[result];
catodo3 = 1;
break;
//unita minuti
case 4:
result = minuti % 10;
dispReg = dispnum[result];
catodo4 = 1;
break;
}
T0IF = 0;
}
}
Grazie, e complimenti per il corso.
#51 da Giovanni Bernardo il 14 gennaio 2010
if(ore = 24) => la verifica di uguaglianza si fa col doppio uguale, l’uguale singolo è un operatore di assegnazione.
quell’ if(button == 1) nell’ISR non va messo (come fai a verificare la pressione di un pulsante nel tempo di un interrupt?!) e non arrivo a capire a cosa serve.
dal momento che dispReg = dispnum[result]; è uguale per tutti i casi, è buona norma metterla al di fuori per non ripetere sempre la stessa riga di codice.
poi non capisco perchè la verifica dei minuti==60 la fai sia nel main che nell’isr… tutte ste verifiche falle al di fuori dell’isr, nell’isr mettici solo il pilotaggio dei display, dato che nel main ti controlli solo la pressione del pulsante di avanzamento dei minuti è li che ti devi fare tutti i controlli del caso
#52 da Andrea il 15 gennaio 2010
Grazie!
#53 da Andrea il 23 gennaio 2010
Ciao Giovanni
ho un altro problema ma con l’orologio, ho fatto una millefori e ho cambiato il pic ho messo un 16f818 tutto funziona bene ma non mi viene rilevata la pressione del tasto per settare i minuti, cioè anche se il piedino dove è collegato il tasto è a 1 il pic lo vede come se fosse a 0 e fa avanzare i minuti, il tasto è collegato su l’uscita RA4:
while(1)
{
//Un pulsantino che fa avanzare i minuti quando premuto
if(button == 0)
{
DelayMs(75);
if(button == 0)
{
minuti++;
if(minuti == 60)
{
minuti = 0;
secondi = 0;
ore++;
if(ore == 24)
{
ore = 0;
minuti = 0;
secondi = 0;
}
}
}
}
if(secondi == 60)
{
secondi = 0;
minuti++;
if(minuti == 60)
{
minuti = 0;
secondi = 0;
ore++;
if(ore == 24)
{
ore = 0;
minuti = 0;
secondi = 0;
}
}
}
}
#54 da Giovanni Bernardo il 23 gennaio 2010
Il 16F818 sulle porte A ha anche il convertitore AD. L’hai disattivato? ADCON1=0×06. All’avvio su quel pic le porte A sono configurate tutte come analogiche
#55 da Luca il 13 marzo 2010
Buonasera,
il tutto estremamente chiaro, ma come sempre la conversione 877a->628a non gioca a mio favore. Il programma adattato funziona alla perfezione, l’unico problema, che persiste ormai dall’inizio del corso, è l’utilizzo del PORTA(TRISA), a quanto pare, l’abbondanza di periferiche sotto PORTA(TRISA) mi sta creando parecchi problemi. Infatti tutto fila liscio se decido di tralasciare il btnDn poichè volendo usare solo le porte B ho solo a disposizione 7segmenti+1tasto. Appena modifico il programma per il decremento, nell’utilizzare una qualunque delle porte a, si verifica una cosa stranissima, il contatore aggiunge e decrementa di una unità da solo (77…76…77…76…rip) , letteralmente “fregandosene” della pressione di qualsiasi dei due tasti.
Per caso hai, come sempre, qualche dritta? Magari nel cercare di far capire al pic16f628a (che uso) di settare le porte A tutte come I\O (tranne mclr ovviamente) e disattivare qualsiasi accessorio (ANx Vref OSC..etc)?
AGGIORNAMENTO:
il problema si verifica su tutte le porte tranne RA4, ovvero RA4\T0CKI\CMP2 per la quale il programma scorre senza problemi. Allego impostazione registri.
Ps.
TRISA=0b00040000; //RA4 btndn
TRISB=0b10000000; //RB7 btnup, RB6-RB0 display
OPTION=0b00000001; //INTIO=> quarzo interno @4MHz =>1ms (Presc 4, TMRO=4+2)
INTCON=0b10100000;
TMR0=6; // il timer0 deve partire da 100
Buona Serata
#56 da Giovanni Bernardo il 13 marzo 2010
Il fatto che il problema si verifica su tutte le porte A tranne la 4 ti dovrebbe indurre in un sospetto. Prendi il datasheet del 16F628A e guarda bene qual’è la differenza tra RA4 e tutte le altre porte del banco A. Osserva attentamente. Esatto! La porta RA4 è l’unica a non avere una “funzione speciale” rispetto alle altre, è solo una porta a collettore aperto che può funzionare come I/O (ed essendo a collettore aperto necessita di una resistenza di pullup che penso hai già messo).
Penso però che il problema te lo danno solo le porte da RA0 a RA3 (non penso ti diano problemi pure le RA5/6/7). Questo perchè su quelle porte ci sono gli ingressi dei comparatori e al POR (Power On Reset) vengono abilitate con funzione analogica. Basta che disattivi la funzione analogica agendo sull’apposito registro del comparatore:
CMCON=0b00000111; // pagine 63 e 64 del datasheet
Poi ancora: se utilizzi RA6 e RA7 come I/O (invece di metterci il quarzo) non puoi contemporaneamente usare pure RA5 (MCLR) come I/O, o setti RA5 come I/O e usi RA6 e RA7 per il quarzo, O usi RA5 come normale MCLR e puoi mettere RA6 e RA7 come I/O (questo è specificato a pag. 98 – configuration word register). Se provi a violare questa regola vedi come il pic si comporta in maniera assura.
#57 da Luca il 13 marzo 2010
Perfetto, appena posso proverò ad impostare quel registro! A presto, grazie.
#58 da s.yari il 18 maggio 2010
Ciao, non mi è chiaro perchè nel main.c inizializzi la variabile “counter” a 77.
Grazie
#59 da Giovanni Bernardo il 18 maggio 2010
:) perchè è il mio anno di nascita. Ovviamente lo puoi pure inizializzare a zero… è un counter
#60 da s.yari il 18 maggio 2010
allora metto 82….
ok grazie