Vai al contenuto
PLC Forum


Gestione Di 3 Diplay A 7 Segmenti Tramite Interrupt


ic910

Messaggi consigliati

Salve

Sto cercando di gestire 3 diplay a 7 segmenti

I diplay che ho scelti sono ad anodo comune .I vari anodi li attivo e disattivo tramite 3 transistor pnp .

Ho pensato di gestire il multiplexing dei 3 diplay tramite routine di interrupt.

Vado alla routine di interrupt quando ho un overflow del TMR0. Ho utilizzato come oscillatore un 4Mhz (interno) ho abilitato il prescaler con fattore di divisione 1:2 .

Avendo un 4 MHz ho un impulso ogni 1uS tenendo in considerazione che il prescaler è attivo ho un overflow ogni 510 uS.

Nella routine di interrupt vado ogni 510 uS ad incrementare una variabile che arrivata al numero 10 mi fà il multiplexing dei diplay .In poche parole il multiplexing lo eseguo ogni 5mS.

Inoltre nella routine di interrupt vado ad incrementare anche un altra variabile che mi serve per fare l'incremento del numero da visualizzare sul diplay.

Questa variabile una volta arrivata a 100 mi cambia la cifra sul diplay .100 corrisponde a circa 1 secondo perche 5ms *100 = 1000 mS = 1 secondo.

Il problema che ho è dato dalla variazione del numero sul diplay che invece di avvenire ogni secondo avviene ogni 3 / 4 secondi.

Da cosa può dipendere ?

Ho pensato che il multiplexing tramite interrupt sia molto veloce da impedire l'incremento corretto nella main routine della variabile cifra diplay.

Link al commento
Condividi su altri siti


Stai lavorando con il micro stand alone o hai inserito il pickit?

nel caso del pickit inserito i tempi possono allungarsi, non quelli di interpt dei timer ma quelli generali del programma.

Link al commento
Condividi su altri siti

Allora bisognerebbe, per prima cosa, vedere il diagramma di flusso del programma.

Usi dei timer bloccanti tipo delay?

Link al commento
Condividi su altri siti

qual'è il comportamento:

la sequenza visualizzata è corretta vedi 1,2,3...ma gli incrementi avvengono con tempi sbagliati 3 4secondi

oppure

la sequenza visualizzata è sbagliata vedi 1 dopo quattro secondi il 4 dopo 3 secondi il 7 ina ltre parole vedi solo alcuni numeri della sequenza

Link al commento
Condividi su altri siti

Uso come timer il TMR0 .Il problema è stato risolto dovevo portare la routine di multiplexing diplay fuori della routine di interrupt. Nella routine di inrerrupt ho lasciato solo l'incremento di una variabile che fuori della routine di interrupt mi fà tramite if l'incremento del diplay.

In questo modo ho un incremento di numero ogni secondo.

Pongo sotto il listato spero possa essere d'aiuto

On_Interrupt GoTo aggiornamento
GoTo main

main:


If pippo > 200 Then 'pippo viene incremmentato ogni 5 mS
Inc ar[0] 'il dato viene incrementato ogni 5*200 = 1000 mS = 1 Secondo circa
pippo = 0 'riporto a 0 pippo cosi il contatore può riniziare da 0
dato = ar[0]
GoSub tabella
diplay[0] = visualizzare

End If

If ar[0] > 9 Then
ar[0] = 0
dato = ar[0]
GoSub tabella
diplay[0] = visualizzare
Inc ar[1]
dato = ar[1]
GoSub tabella
diplay[1] = visualizzare
End If


If ar[1] > 9 Then
ar[1] = 0
dato = ar[1]
GoSub tabella
diplay[1] = visualizzare
Inc ar[2]
dato = ar[2]
GoSub tabella
diplay[2] = visualizzare
End If

If ar[2] > 9 Then
ar[2] = 0
dato = ar[2]
GoSub tabella
diplay[2] = visualizzare
ar[1] = 0
dato = ar[1]
GoSub tabella
diplay[1] = visualizzare
ar[0] = 0
dato = ar[0]
GoSub tabella
diplay[0] = visualizzare
End If

-------------------------------------------------- Routine di multipleing diplay-----------------------------------------------------------------------------

Low anodo 'tramite il pnp porto il + all anodo comune


PORTB = diplay[0]
DelayMS 5
High anodo
Low anodo_1


PORTB = diplay[1]
DelayMS 5
High anodo_1
Low anodo_2


PORTB = diplay[2]
DelayMS 5
High anodo_2


GoTo main

----------------------------------------------------------Routine di Interrupt -----------------------------------------------------------------

aggiornamento:

Context Save

orsolina = orsolina + 1 'avendo impostato il prescaler a 1:2 ho un interrupt ogni 500 uS . Orsolina si và ad incrementare di un unità ogni 500 uS
If orsolina < 10 Then exit_int
If orsolina >= 10 Then 'Se Orsolina è >=10 sono passati 500uS*10 = 5 mS
orsolina = 0
pippo = pippo + 1 'Ogni 5 mS incremento pippo
End If




exit_int:

TMR0 = 6 'impostandolo a 6 il tmr0 va da 6 a 255 sono 250 impulsi di clock considerando anche lo 0 .Ho fatto questo per non avere un overflow ogni 510 uS .In questo modo ho un

'overflow ogni 500 uS cosi incremento pippo ogni 5 mS invece di 5,1mS che mi portava un errore di 0,1mS

INTCON.2 = 0 'riporto a 0 l'interrupt flag cosi potro avere un successivo interrupt.

Context Restore



'-------------------------------Routine visualizzazione------------------------------------------

tabella:


visualizzare = LookUp dato,[$C0,$F9,$A4,$B0,$99,$92,$82,$F8,$80,$98]

Return

Modificato: da ic910
Link al commento
Condividi su altri siti

Non ho voglia di analizzare nel dettaglio il sistema.

In generale tieni presente che le rountine di interrupts devono contenere il minimo indispensabile per servire l'interrupt. Spesso le scrivo addiruttura in asm.

Se vuoi fare un timer è meglio che l'overflow del timer avvenga in tempi più lunghi possibili.

Io ho standardizzato timer1 con scadenza a 10ms.

Link al commento
Condividi su altri siti

Ho dato una scorsa abbastanza veloce al listato.

A mio parere ci sono almeno 3 cose, le più evidenti, che anche se non sono causa diretta di malfunzionamenti non sono corrette.

On_Interrupt GoTo aggiornamento
GoTo main

Quste 2 righe se non sono espresamente richieste dal compilatore, ma sarebbe un pessimo compilatore, sono inutili

Apri il main e com prima riga richiama la funzione di inzializzazione che avrà come ultima riga l'amilitazione degli interrupts.

Ci penserà poi il vettore degli interrupts a richiamare la funzione di servizio del relativo interrupts.

I delay bloccanti per abilitare in sequenza gli anodi sono inutili, ancorchè dannosi. hai gia un timer ad interrupt, usa quello per abilitare la sequenza di multiplexing. Fai un interrupt timer con cadenza di 5ms. Al primo interupt abiliti il realtivo anodoe poi prepari il dato sulla porta B, al secondo interrupt ripeti l'operazione per la seconda, cifra, al terzo per la terza, poi riprendi da capo. Per circa 1µs i dati sulla porta B non saranno corretti, ma questo non è avvertibile.

Se invece di precaricare con 6 il timer 0 lo precarichi con 59 ti ritrovi direttamente 5.015 ms di clock; per 15µs non serve complicarsi la vita e complicare il programma.

Link al commento
Condividi su altri siti

Grazie a tutti delle risposte.

Giusto Livio ho spostato On_Interrupt GoTo aggiornamento alla prima riga della main e il tutto funziona come prima.

Ottima idea utilizzare l'interrupt di 5 mS per fare il mutiplexing togliendo i tre 5 mS di ritardo , ci stò lavorando su vediamo che esce fuori.

Per quanto riguarda lo start tmr0 da 59 ho 256 - 59 = 197 uS *2 (con prescaler 1:2) = 394 uS i conti non mi tornano non sò se sbaglio ?

Oppure non sò se hai preso in considerazione un altro fattore di divisione

Link al commento
Condividi su altri siti

Oppure non sò se hai preso in considerazione un altro fattore di divisione

Hai ragione è una svista mia. Avevo considerato il 6 come valore di conteggio da decrementare.

Il problema è che tu usi un contatore da 8 bits. se usassi un contatore da 16 bits avresti direttamente l'interrupt a 5 ms, risparmiandoti queste continue interruzioni di programma.

Link al commento
Condividi su altri siti

CIao Livio questa mattina avendo un pò di tempo ho tirato giù la routine togliendo i 3 ritardi da 5 mS .In questo modo effettivamente ho un aggirnamento della cifra del diplay al secondo più preciso.

Ho fatto in questo modo :

---------------------------------------------------------Routine posta nella main -------------------------------------------------------------------------

If massimo = 0 Then
High anodo_2
Low anodo 'tramite il pnp porto il + all'anodo comune
PORTB = diplay[0]

End If

If massimo = 1 Then
High anodo
Low anodo_1
PORTB = diplay[1]

End If

If massimo = 2 Then
High anodo_1
Low anodo_2
PORTB = diplay[2]

'---------------------------------------------------------------Routine di Interrupt ---------------------------------------------------------------

aggiornamento:

Context Save

orsolina = orsolina + 1 'avendo impostato il prescaler a 1:2 ho un interrupt ogni 500 uS orsolina si và ad incrementare
If orsolina < 10 Then exit_int
If orsolina >= 10 Then 'invece passati i 500*10 = 5mS incremento pippo
orsolina = 0
pippo = pippo + 1
massimo = massimo + 1
If massimo > 2 Then massimo = 0
End If

exit_int:

TMR0 = 6 'impostandolo a 6 il tmr0 va da 6 a 255 sono 250 impulsi di clock invece di 256
INTCON.2 = 0 'riporto a 0 l'interrupt flag cosi potro avere un successivo interrupt.

Context Restore

In questo modo ho un aggirnamento del singolo diplay ogni 10 mS il tutto funziona correttamente.

Ho misurato anche il tempo che impiega il pic a svolgere tutta la main sono circa 50uS dovrei recuperare facendo aggiornare pippo ogni 4950 uS invece di 5000 uS (5mS)

Link al commento
Condividi su altri siti

Per misurare il tempo della main ho fatto semplicemente cambiare lo stato logico di una porta ad ogni inizio main e poi tramite oscilloscopio ho misurato il suo periodo .Il semi periodo rappresenta il tempo di esecuzione main.

Link al commento
Condividi su altri siti

Per misurare il tempo...

Avresti dovuto far cambiare stato all'inizio ed alla fine del main, per misurarne il tempo. Come hai fatto tu misuri il tempo totale del loop di programma.

Magari nel tuo caso coincidono, però concettualmente non si fa così.

Hai anche insegnato ?( la domanda è sul serio thumb_yello.gif )

Se la domanda è rivolta a me, la rispsota è no. Io, se non sono costretto da circostanze o fatti che mi obbligano diversamente, faccio solo quello che so fare; insegnare, nell'accezione canonica del termine, è proprio una cosa che non son capace di fare. Purtroppo la maggior parte degli insegnanti che ho avuto io, dalle elementari all'università, avrebbero dovuto astenersi da questa èrofessione, invece no, non l'hanno fatto. :angry:

Link al commento
Condividi su altri siti

Crea un account o accedi per commentare

Devi essere un utente per poter lasciare un commento

Crea un account

Registrati per un nuovo account nella nostra comunità. è facile!

Registra un nuovo account

Accedi

Hai già un account? Accedi qui.

Accedi ora
×
×
  • Crea nuovo/a...