Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

Multiplexing Display 7-seg

Tipologie, strumenti di sviluppo, hardware e progetti

Moderatore: Foto UtentePaolino

0
voti

[1] Multiplexing Display 7-seg

Messaggioda Foto Utentedarkweader » 26 lug 2012, 19:49

Salve a tutti, volevo realizzare il seguente programma:

Viene visualizzato il passaggio dei secondi su due display 7-segmenti, mente il punto di uno dei display rimane acceso per 1/2 secondo e spento per il successivo;
Il passaggio dei secondi è scandito dal Timer1 in Modalità CTC, quando viene raggiunto il massimo valore viene generato l'interrupt;
Si vuole inoltre che ogni 60 secondi il conteggio si azzeri (viene visualizzato fino a 59)



codice assembly:
Codice: Seleziona tutto
;*************************************
;written by:       Antonio Cittadino     
;date:                               
;version:                           
;file saved as:    Clock1                 
;for AVR:          Atmega8535         
;clock frequency   4MHz               
;*************************************

.nolist
.include "m8535def.inc"
.list

;===============
;Declaretion:

    .def temp=R16
    .def seconds=R17     
    .def tens=R18   
    .def ones=R19
    .def displayNumber=R22
    .def displayCounter=R23
    .def halfSecond=R24

;================
;Interrupt Vector

rjmp Init       
reti     
reti     
reti     
reti     
reti     
rjmp TIM1_COMPA 
reti   
reti   
reti   
reti 
reti 
reti 
reti 
reti      ;0x00E "ADC"        ADC Conversion Complete Handler
reti      ;0x00F "EE_RDY"     EEPROM Ready Handler
reti      ;0x010 "ANA_COMP"   Analog Comparator Handler
reti     ;0x011 "TWSI"       Two-wire Serial Interface Handler
reti     ;0x012 "EXT_INT2"   IRQ2 Handler
reti      ;0x013 "TIM0_COMP"  Timer0 Compare Handler
reti      ;0x014 "SPM_RDY"    Store Program Memory Ready Handler

;=================
;Start the program:

rjmp Init                             


;===============

Init:

    ldi temp,high(RAMEND) ; Main program start
    out SPH,temp ; Set Stack Pointer to top of RAM
    ldi temp,low(RAMEND)
    out SPL,temp
   
   sei ; Enable interrupts


;Output/Input
     ser temp
     out DDRB,temp ;PB0:6 output (SEG, Diasplay7-seg), rest NC

     out DDRC,temp  ;PC2,3 output (K, select Display), rest NC
                        ;PC2=Dis3 PC3=Dis4

     clr temp   
     out DDRD,temp ;PD1:3 output, rest NC
                       ;PD2=UP, PD3=DOWN

;Pull-up resitor
     ldi temp,0b00001100;PD2,3 pull-up resistor
     out PortD,temp

;Look-Up Table

          ldi temp,0b00111111
         mov R0,temp         ;number0
         ldi temp,0b00001001
    mov R1,temp         ;numerb1
    ldi temp,0b01011110
    mov R2,temp
    ldi temp,0b01011011
    mov R3,temp
         ldi temp,0b01101001
    mov R4,temp
    ldi temp,0b01110011
    mov R5,temp
    ldi temp,0b01110111
    mov R6,temp
    ldi temp,0b00011001
    mov R7,temp
    ldi temp,0b01111111
    mov R8,temp
    ldi temp,0b01111011
         mov R9,temp


;initial condition register
    clr tens                 
    clr ones

        ldi displayCounter,50
        clr displayNumber
   clr halfSecond
        clr seconds
   clr ZH

;initial condition I/O register
;starting by selecting Display3
     ldi temp,0b00000100
     out PortC,temp

rjmp Start

;===============

;Subroutines



;HalfSecond passed ISR
TIM1_COMPA:



push temp
in temp,SREG
push temp   
;____________

inc halfSecond

cpi halfSecond,2
breq passed1s
sbi PortA,6     ;turn ON DotDIS3

pop temp
out SREG,temp
pop temp
reti

passed1s:

cpi  seconds,60
brne PC+2
clr seconds

cbi PortA,6     ;turn OFF DotDIS3
clr halfSecond
inc seconds


pop temp
out SREG,temp
pop temp
reti


;__________________________________________________________________________________________
   Display:


     ;NOTE: tens,ones are "digitConvert" of "second"

      ;How made (indirecting address):
         ;"first lap" (after 50 dec), DN=0,DN-2!=0, ZL=18+0=R18(point tens), DN=0+1=1
    ;"second lap" (other 50 dec) DN=1, DN-2!=0 ,ZL=18+1=19( point ones), DN=1+1=2
    ;"third lap" (other 50 dec) DN=2, DN-2=0--> clr DN=0, ZL=18+0 (point again tens)
   
    dec displayCounter
    breq PC+2
    ret       

    ldi displayCounter,50
   
    cpi displayNumber,2
    brne PC+2  ;if DisplayNumber-2!=0 -->PC+2
    clr displayNumber

     ;indirecting address, Z will point always tens or ones

         ldi ZL,18           
    add ZL,displayNumber
   
    ld temp, Z
    clr ZL     
    add ZL,temp
    ld temp,Z 
              
         ;PortB-->Tens-->DIS4 selected(by multiplexing)      PortB-->Ones--->DIS3 selected(by multiplexing)
    out PortB,temp
         inc displayNumber

    ;Multiplexing
         ;NOTE: initial condition DIS3 selected (from initi section)

    in temp,PinC
    lsl temp
    sbrc temp,4   
    ldi temp,0b00000100

    ;"fisrt lap" lsl selecting DIS4
    ;"second lap" return to initial condition (selecting DIS3)
   
    out PortC,temp
     
    ret
;____________________________________________________________________________________________

DigitConvert:

         clr tens
    clr ones

   FindTens:
     
    subi seconds,10
    brcs FindOnes
    inc tens
    rjmp FindTens

   FindOnes:
         subi seconds,-10
    mov  ones,seconds

   ret
;===============
;Main body of program:


Start:
          ;NOTE there is a correct way to access a 16bit I/O register
     ;write: 1st-High byte 2nd-Low byte
     ;read: 1st-Low byte 2nd-High byte


          ldi temp, (1<<CS10)|(1<<CS11)|(1<<WGM12) ;CLK(I/O)/64 and CTC
     out TCCR1B,temp

         ;MaxValue 31250(f=4Hz prs=64)0x7A12 , halfsecond passed
         ldi temp,0x7A
         out OCR1AH,temp
    ldi temp,0x12
         out OCR1AL,temp

     
     ;Timer/counter1 output compare match A enable interrupt
     ;this interrupt is enabled if Iflag in SREG in set ("sei" enable global interrupt)
     ;and bit4 of TIMSK is set (OCIE1A)

          ldi temp, 1<<OCIE1A
     out TIMSK,temp

Loop:
      rcall DigitConvert
      rcall Display
      rjmp Loop


posto anche il video per far capire cosa non funziona
[url][/url]
per intenderci il DISPLAY4 è quello delle Decine (a SX) mentre il DISPLAY3 è quello delle unità a DX

Come si vede dal video non vengono incrementati le decine, penso sia un problema dovuto al multiplexing poiché ho simulato il programma su AVRstudio e funziona.

Inoltre, Il punto lampeggia, ma è veramente poco luminoso, c'è da dire che le prime volte che ho provato il programma l'intensità luminosa era la stessa dei segmenti, poi ho modificato alcune cose, salvato, ed ora è cosi, non è il display perché ho provato a scambiarli e non cambia nulla, cosa potrebbe essere?

Flowchart:

diagramma1.png
diagramma1.png (3.84 KiB) Osservato 7108 volte


diagramma2.png
diagramma2.png (15.58 KiB) Osservato 7108 volte


dagramma3.png
dagramma3.png (17.55 KiB) Osservato 7108 volte
Avatar utente
Foto Utentedarkweader
61 2 7
Frequentatore
Frequentatore
 
Messaggi: 271
Iscritto il: 8 mag 2011, 17:32

0
voti

[2] Re: Multiplexing Display 7-seg

Messaggioda Foto Utentedarkweader » 26 lug 2012, 19:52

Non sono riuscito ancora a caricare il video tramite youtube, comunque se qualcuno potrebbe darmi qualche indicazione, penso il problema sia sulla "temporizzazione" del multiplexing.
Avatar utente
Foto Utentedarkweader
61 2 7
Frequentatore
Frequentatore
 
Messaggi: 271
Iscritto il: 8 mag 2011, 17:32

0
voti

[3] Re: Multiplexing Display 7-seg

Messaggioda Foto Utentedarkweader » 26 lug 2012, 20:40



il codice dovrebbe essere esatto, ma non vengono incrementate le decine
Ultima modifica di Foto UtentePaolino il 26 lug 2012, 21:52, modificato 1 volta in totale.
Motivazione: Usati i tag youtube
Avatar utente
Foto Utentedarkweader
61 2 7
Frequentatore
Frequentatore
 
Messaggi: 271
Iscritto il: 8 mag 2011, 17:32

0
voti

[4] Re: Multiplexing Display 7-seg

Messaggioda Foto Utentedarkweader » 28 lug 2012, 17:40

ho provato a modificare il codice, richiamando la routine "display" all'interno di un ciclo che dura 0.5s

Codice: Seleziona tutto
  ;TC0 Prs=64
     ldi temp, (1<<CS00)|(1<<CS01)
     out TCCR0,temp


Loop:
      rcall DigitConvert


      ldi count250,250
     ldi mark250,250
     TimeLoop:
     rcall Display
     in temp2,TCNT0
     cp temp2,mark250
     brne TimeLoop

     subi mark250,-250

     dec count250
     brne TimeLoop

     
      rjmp Loop



adesso è cambiata un po' la situazione,mi visualizza 0,1,2,3,4,5,6,7,8,9, 10 (ora lo visualizza) però poi riparte da 0 invece di continuare...
Avatar utente
Foto Utentedarkweader
61 2 7
Frequentatore
Frequentatore
 
Messaggi: 271
Iscritto il: 8 mag 2011, 17:32

1
voti

[5] Re: Multiplexing Display 7-seg

Messaggioda Foto Utentesimo85 » 31 lug 2012, 4:06

darkweader ha scritto:Inoltre, Il punto lampeggia, ma è veramente poco luminoso, c'è da dire che le prime volte che ho provato il programma l'intensità luminosa era la stessa dei segmenti, poi ho modificato alcune cose, salvato, ed ora è cosi, non è il display perché ho provato a scambiarli e non cambia nulla

Quindi sia display che punto luminoso, hanno poca luminosità.

cosa potrebbe essere?

Il problema è dato dal mal dimensionamento delle correnti di alimentazione dei segmenti, e qui entra in gioco il duty cycle dell'output di pilotaggio sui transistori.
Tieni in mente che in un secondo stai commutando due display, quindi la luminosità si riduce circa la metà (se per esempio il duty cycle è di circa il 50%) rispetto ad un pilotaggio non multiplexato.

Mi spiego meglio. Supponendo che i LED/segmenti sono rossi e con resistenze da 270Ω avevi calcolato una luminosità proporzionale per una corrente I_\text{F} \approx 10 - 11\text{mA}, la luminosità dei LED/segmenti del display è invece proporzionale ad una corrente I_\text{F} \cdot \text{Duty Cycle}.

Vedi ad esempio questo thread.

Soluzione? O abbassi le resistenze o usi display ad alta luminosità, se ci sono.

EDIT: solo ora (06.35 qui) ho potuto vedere il video da un altro PC che non è lo stesso da cui scrivo. Il punto non lo vedo proprio.. :( Sarà perché è anche coperto dai cavetti? Comunque il problema dovrebbe essere quello descritto. Se i segmenti si illuminano bene pero il puntino no, allora potrebbe essere un problema relazionato alla struttura del firmware..
Avatar utente
Foto Utentesimo85
30,9k 7 12 13
Disattivato su sua richiesta
 
Messaggi: 9927
Iscritto il: 30 ago 2010, 4:59

0
voti

[6] Re: Multiplexing Display 7-seg

Messaggioda Foto Utentedarkweader » 31 lug 2012, 10:23

allora, quello che mi hai detto lo sapevo, il problema non è la luminosità, come dicevo, dopo che ho modificato il codice, il punto non si vedeva più, anche se io lo vedevo lampeggiare un minimo, avevo dimenticato di settare come uscita la porta (quando ho riscritto il codice)

Il problema è un altro, il programma, che ho testato su AVRstudio, dovrebbe contare i secondi da 0 a 59, solo che come si vede dal video va solo da 0 a 9, è quello il problema, anche se singolarmente, i vari "pezzi" del codice funzionano.

Ci sono i diagrammi ma se vuoi posso spiegarlo semplicemente...in ogni caso ho cambiato il codice aggiungendo, un ciclo che richiama la routine display per 0.5 secondi, e con questa modifica il display

conta fino a 10, e poi si azzera di nuovo, per questo penso sia una questione di temporizzazione, aggiorna correttamente le unità ma non le decine, anche se solo software funziona
Avatar utente
Foto Utentedarkweader
61 2 7
Frequentatore
Frequentatore
 
Messaggi: 271
Iscritto il: 8 mag 2011, 17:32

0
voti

[7] Re: Multiplexing Display 7-seg

Messaggioda Foto Utentesimo85 » 1 ago 2012, 0:38

Per ogni overflow dei secondi incrementi i minuti. Purtroppo gli AVR non li programmo in Assembly, per il momento.
Avatar utente
Foto Utentesimo85
30,9k 7 12 13
Disattivato su sua richiesta
 
Messaggi: 9927
Iscritto il: 30 ago 2010, 4:59

1
voti

[8] Re: Multiplexing Display 7-seg

Messaggioda Foto Utenterusty » 1 ago 2012, 8:57

Ho compilato il codice in AVR Studio 4 e non ho errori ne' warning, tuttavia ho notato molte cose che sono sicuramente non utili al tuo scopo (ad esempio la dichiarazione di porte come ingressi per pulsanti inutilizzate), e un non poco arzigogolato modo di comandare i display in multiplexing.
Ho apprezzato molto l'idea di indirizzare tramite il puntatore i registri con i valori BCD preimpostati, bella soluzione, ma non capisco ad esempio quell'aggiungere 10 e togliere 10, e quel valore 50 che deve essere decrementato.. perché 50? Ovviamente questi valori sono interpretati dall'assemblatore come decimali.

Purtroppo ora non ho molto tempo da spenderci, ma troverei piu' utile e didatticamente piu' divertente farne uno ex-novo piuttosto che riaddattare tagliando qua e la' il codice finché non funziona come vorremmo... anche perché potrei metterci molto piu' tempo a capire che fa questo codice e quello che fa ma che non ci serve, piuttosto che prendere l'idea iniziale e riscriverne uno completamente di sanapianta.

Saluti e buona fortuna! :)

p.s. ma scriverlo in gcc no eh? hai comunque tutta la mia stima, e mi piace di piu' cosi', anche se scriverlo in C non sara' cosi' appagante credo che sicuramente sia una via piu' diritta e con meno intoppi :ok:
Avatar utente
Foto Utenterusty
4.075 2 9 11
Utente disattivato per decisione dell'amministrazione proprietaria del sito
 
Messaggi: 1578
Iscritto il: 25 gen 2009, 13:10

0
voti

[9] Re: Multiplexing Display 7-seg

Messaggioda Foto Utentedarkweader » 1 ago 2012, 20:43

ho notato molte cose che sono sicuramente non utili al tuo scopo (ad esempio la dichiarazione di porte come ingressi per pulsanti inutilizzate)


perché inizialmente era un programma più ampio ma mi dava ulteriori problemi e mi sono limitato al conteggio dei secondi.

e un non poco arzigogolato modo di comandare i display in multiplexing.


mi sembra abbastanza semplice, è fatto in modo da poter utilizzare la routine del display per più scopi, utilizza il registro displayNumber (che chiamerò DN), e lo shift register "lsl".

Il fatto di decrementare 50 (ma il numero dipende dal codice, ma lo analizziamo dopo),è fatto per non dover usare un Timer/Counter per mantenere acceso un tot di tempo un display.

Suponiamo di avere 4 display, quattro registri decineSx (DIS4), unitaSx(DIS3), decineDx(DIS2), unitaDx(DIS1), quando DN=0
l'indirizzamento indiretto manda in uscita il contenuto di "decineSx" (lsl shifta dalla condizione iniziale, ovvero è selezionato il display delle unitaSx, il DIS3, selezionando il DIS4);
quindi abbiamo DIS4 acceso e visualizziamo decineSx,
DIS3, unitaSx
DIS2, decineDx
DIS1, unitaDx

forse l'unica cosa si potrebbe migliorare l'ordine dei registri, e non partire accendendo il 4° display,


in questo modo se prima della routine display posso: chiamare "DigitConvert" per convertire un numero decimale ("seconds") in unità e decine, altrimenti se voglio far apparire una scritta che non dipenda dallo scorrere del tempo, basta assegnare ai registri decine e unità il valore voluto.


ma non capisco ad esempio quell'aggiungere 10 e togliere 10

con assembler non sono ancora molto "sciolto", quell'aggiungere 10 e togliere 10 serve alla routine di conversione per dividere un numero decimale in due registri delle unità e delle decine, forse è un passaggio superfluo, poiché ho ridotto il codice, che ho trovato che permetteva di convertire anche le centinaia,
comunque funziona...devo controllarlo meglio


Il fatto di decrementare displayCounter50 volte, allora la routine display volevo metterla nel loop principale, e appunto non volevo chiamarla tramite un interrupt su un timer per temporizzare l'accensione dei display poiché il Timer0 potrebbe servirmi in seguito per altro e non volevo complicarmi poi la vita.

Praticamente prima di arrivare a richiamare la routine display, verranno eseguite un certo numero di righe di codice, finché però la routine non viene richiamatà per 50 volte, rimarrà acceso un display, poi viene selezionato il display seguente con il rispettivo numero da visualizzare, e fino alle 50 successive decrementazioni rimarrà acceso,

quindi: (n°istruzioni_prima_della_chiamata) X (N=50) significa che per tot istruzioni rimane acceso un display
quini in base a questo N posso determinare il tempo per cui rimane acceso un display, ovviamente questa idea era per il codice finale, dove comunque ci sono un certo numero di istruzioni.


Quindi con una frequenza di 4MHz, in un loop che chiama continuamente la routine di conversione e quella del display a quanto dovrei aumentare questo 50 per far si che ogni display rimanga acceso 5ms??
Avatar utente
Foto Utentedarkweader
61 2 7
Frequentatore
Frequentatore
 
Messaggi: 271
Iscritto il: 8 mag 2011, 17:32

0
voti

[10] Re: Multiplexing Display 7-seg

Messaggioda Foto Utentedarkweader » 1 ago 2012, 21:30

devo modificarlo, e provare ad alzarlo a 1700
Avatar utente
Foto Utentedarkweader
61 2 7
Frequentatore
Frequentatore
 
Messaggi: 271
Iscritto il: 8 mag 2011, 17:32


Torna a Realizzazioni, interfacciamento e nozioni generali.

Chi c’è in linea

Visitano il forum: Nessuno e 7 ospiti