Laboratorul 05 - Afisajul cu 7 segmente

Obiective
  • exersarea implementării de FSM-uri
  • interfațarea unui modul hardware simplu
  • comunicația cu utilizatorul

Afișajul cu 7 segmente

Un afișaj cu 7 segmente este un tip de display electronic folosit pentru a afișa cifre zecimale. Un astfel de afișaj este format din 7 LED-uri legate într-unul din două moduri: anod comun (plus comun) sau catod comun (minus comun).

Un LED, nu este nimic mai mult decât o diodă, alcătuită din 2 borne, numite anod si catod. Pentru funcționarea sa este necesar ca tensiunea la anod să fie mai mare decât aceea la catod (practic tensiunea scade in sensul orientarii diodei). Atunci când tensiunea la catod este mai mare sau egală cu tensiunea la anod, LED-ul este stins. în caz contrar, LED-ul este aprins.

Distribuția tensiunii intr-un 7 segment display common anode

În cazul FPGA-ului nostru, utilizăm configurația cu anod comun, ceea ce înseamnă că setarea led-urilor se va face prin setarea tensiunilor la catod pentru a fi mai mici decât cea de la anod. Cum lucrăm în logică digitală, tensiunea la anod va fi de fapt VCC, +5V sau 1 logic, şi singura tensiune pe care o putem oferi mai mică decât 1 logic este cea de 0 logic, GND, 0V.

Așadar, avem un input implicit de 1 logic la anod, iar de input-ul de la catodul fiecărui LED depinde aprinderea sa. Exemplu:

module setLed (
    output A, // fir conectat la catodul ledului A
    output AN // fir conectat la tranzistorul PNP ce controleaza anodul ledului A
    );
 
    assign AN = 0;
 
    // Pentru a aprinde ledul A:
    assign A = 0;
 
 
endmodule
module clearLed (
    output A, // fir conectat la catodul ledului A
    output AN // fir conectat la tranzistorul PNP ce controleaza anodul ledului A
    );
 
    assign AN = 0;
 
    // Pentru a stinge ledul A
    assign A = 1;
 
endmodule

Celulă de afișaj cu 7 segmente

Fiindcă o cifră este formată din 7 LED-uri și pe Digilent Nexys A7 avem 8 cifre, în mod normal am avea nevoie de 112 de semnale (128 considerând și punctul fiecărei cifre) pentru a controla starea fiecărui LED (anod + catod). Totuși este folosită o schema de multiplexare prin care un anod este comun tuturor celor 7 LED-uri dintr-o cifră (și punctului), iar catozii LED-urilor de pe aceeasi poziție sunt partajați între toate cele 8 cifre.

Afișajul cu 7 segmente pe Digilent Nexys A7

Folosind această schemă de multiplexare, doar o cifră poate fi aprinsă la un moment dat (dacă se dă drumul la mai mult de un anod aceeași cifră va fi afișată pe toate pozițiile, deoarece catozii sunt partajați). Astfel, dacă dorim să afișăm mai multe cifre diferite între ele, nu putem face acest lucru decât afișând cate una la singură la fiecare moment de timp. Din fericire, lucrând cu un clock intern de frecvență cu mult mai mare decât capacitatea de percepție a ochiului uman, ne permitem să facem un astfel de afișaj rând-pe-rând, urmând ca ochii nostrii să perceapă un display continuu al celor 8 cifre.

Task

Task-urile reprezintă o facilitate a limbajului Verilog care oferă posibilitatea de a scrie cod reutilizabil și mai ușor de înțeles. În acest sens sunt foarte similare cu funcțiile din C/C++. În Verilog există și funcții (denumite Functions) care funcționează similar, însă pentru ceea ce avem noi nevoie în rezolvarea laboratoarelor, task funcționează foarte bine. Task-urile sunt foarte utile pentru testarea funcționalitătilor codului nostru, deoarece permit folosirea de delay-uri.

Utilizăm task-uri atunci când avem de efectuat aceeași operație sau bloc de operații de mai multe ori. Pentru a evita duplicarea codului și volumul de editări de care am avea nevoie pentru a corecta potențialele erori, precum si pentru a face codul mai ușor de citit preferăm să apelăm de oricâte ori este nevoie un task descris o singură dată.

Regulile pentru folosirea de task-uri:

  • Task-urile pot avea oricât de multe input-uri și output-uri
  • Task-urile pot folosi întârzieri (posedge, # delay, etc.)
  • Task-urile pot apela alte task-uri și funcții
  • Task-urile pot modifica variabile globale, definite în exteriorul lor
  • Variabilele declarate în interiorul task-urilor sunt locale acelui task
  • Task-urile pot utiliza atât atribuiri blocante cât și non-blocante

Un exemplu:

module traffic_lights;
    reg clock, red, amber, green;
    parameter on = 1, off = 0, red_tics = 350,amber_tics = 30, green_tics = 200;
 
    // initialize colors
    initial
         red = off;
    initial
         amber = off;
    initial
         green = off;
 
    // sequence to control the lights
    always begin
         red = on;  // turn red light on
         light(red, red_tics); // and wait.
         green = on; // turn green light on
         light(green, green_tics); // and wait.
         amber = on; // turn amber light on
         light(amber, amber_tics); // and wait.
    end
 
    // task to wait for ’tics’ positive edge clocks
    // before turning ’color’ light off
 
    task light;
         output color;
         input [31:0] tics;
         begin
             repeat (tics)
                 @(posedge clock);
             color = off; // turn light off
         end
    endtask
 
 
endmodule // traffic_lights

TL;DR

  • Afișajul cu 7 segmente utilizează un circuit complex alcătuit prin multiplexarea tensiunilor legate la fiecare LED.
  • LED-urile sunt de fapt diode care se aprind atunci când au la anod o tensiune mai mare decât la catod.
  • Display-urile 7 segment există sub 2 forme: anod comun sau catod comun, de aceste elemente comune depinzând ce input (0 sau 1 logic) trebuie trimis catre fiecare LED pentru a-l aprinde.
  • NOI FOLOSIM ANOD COMUN (adică pentru a aprinde segmentul CB al cifrei din stânga să zicem, facem ceva de genul: AN3 = 0; CB = 0;)
  • Porturile pentru fiecare segment în parte sunt comune pentru fiecare cifră, astfel încat nu putem scrie cod în maniera: cifre[3].segment_CB = 0, deoarece segment_CB este unul și același atât pentru cifra 0, cât și pentru cifra 3.
  • Pentru a afișa 2 valori diferite pe 2 cifre diferite avem nevoie să le afișăm pe rând și să ciclăm foarte repede printre ele, simulând “alocarea unei cuante de timp”.
  • Realizăm acest lucru folosind un automat cu stări finite, in care fiecare cifră este o stare.
  • Task este o unealtă extraordinar de utilă care ne permite să scriem cod Verilog care să simuleze funcții.

Exerciții

Task 1 (2p). Implementați un modul care afișează cifra “0” folosind afișajul cu 7 segmente.

Task 2 (3p). Implementați un modul care afișează numărul “0123” folosind afișajul cu 7 segmente.

Daca ciclam foarte repede printre cele 4 cifre va aparea un efect de bleeding. Pentru a-l combate introduceti o intarziere de 1ms intre cifre.

Task 3 (5p). Implementați un modul contor folosind afișajul cu 7 segmente. La reset modulul va afișa “0000”, iar, la fiecare apăsare a unui buton, aceast număr va fi incrementat (e.g. “0001” → “0002” → “0003” → etc.)

La fiecare apăsare a butonului contorul trebuie incrementat o singură dată. Nu uitați de switch debouncing.

Task 4 (bonus - 2p). Realizați un timer utilizând 7 segment display. Folosiți primele 2 cifre pentru afișarea minutelor, iar ultimele 2 pentru afișarea secundelor. Va trebui să întârziați clock-ul intern al plăcuței pentru a obține frecvența aferenta 1s. După cum stiți, la 60s, display-ul aferent secundelor se va reseta la 00, iar display-ul aferent minutelor va crește cu o unitate. La apăsarea butonului reset, timer-ul vostru trebuie să revină la 00:00.

Resurse

soc/laboratoare/05.txt · Last modified: 2024/02/29 14:37 (external edit)
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0