CID aplicatii 10 : Aplicatii cu numaratoare
Teorie
Numaratoarele au extrem de multe aplicatii in lumea reala, cateva dintre acestea fiind descrise mai jos.
Exemplu: Numaratul apasarilor unui buton
Un prim sistem simplu cu numarator poate fi cel care contorizeaza de cate ori a fost apasat un buton, sau echivalent, cate persoane/masini au trecut printr-un senzor, de cate ori a fost deschisa o usa etc. Acest sistem se poate apoi dezvolta cu usurinta pentru a numara si oamenii care trec invers prin respectivul set de senzori prin adaugarea functionalitatii de up/down la numarator.
Un astfel de sistem simplu (varianta doar cu numarat intrari) ar arata in felul urmator:
Circuitul de debounce are rolul de a "curata" semnalul de intrare, astfel incat chiar si in prezenta zgomotului sau a unei activari indelungate a senzorului/butonului, sa se contorizeze un singur eveniment. O explicatie mai detaliata puteti gasi aici.
Numaratorul numara evenimentele.
Transcodorul pentru display cu 7 segmente este apoi folosit pentru o mai usoara vizualizare a numarului curent.
Observatie: transcodorul pt 7seg din exemplul de mai jos este in logica negativa. Daca circuitul fizic este in logica pozitiva trebuie adaugat un inversor la iesirea din acesta.
Descrierea debouncer-ului (fisierul debounce.v):
module debounce
#(
parameter limit = 20'd650000
) (
input wire clock,
input wire in,
output wire out
);
reg [19:0] counter; // observatie: si circuitul de debounce foloseste un numarator
reg hit;
assign out = (counter == limit);
always@(posedge clock)
begin
if(in == 0)
begin
counter <= 0;
hit <= 0;
end
else
begin
if(counter == limit)
begin
hit <= 1;
counter <= counter + 1;
end
else
begin
if(in == 1 & hit == 0)
begin
counter <= counter + 1;
end
end
end
end
endmodule
Descrierea numaratorului pe 4b(fisierul counter_4b.v):
module counter_4b
(
input wire clock,
input wire reset,
input wire en,
output reg [3:0] out
);
always@(posedge clock)
begin
if(reset == 1)
begin
out <=0;
end
else
begin
if(en == 1)
begin
out <= out + 1;
end
else
begin
out <= out;
end
end
end
endmodule
Descrierea transcodorului pentru afisaj cu 7seg(fisierul transcodor_7seg.v):
module transcodor_7seg // logica negativa
(
input [3:0] in,
output reg [6:0] out
);
always@(*)
begin
case(in)
4'd0: out = 7'b1000000;// h....a
4'd1: out = 7'b1111001;
4'd2: out = 7'b0100100;
4'd3: out = 7'b0110000;
4'd4: out = 7'b0011001;
4'd5: out = 7'b0010010;
4'd6: out = 7'b0000010;
4'd7: out = 7'b1111000;
4'd8: out = 7'b0000000;
4'd9: out = 7'b0010000;
4'd10: out = 7'b0001000;
4'd11: out = 7'b0000011;
4'd12: out = 7'b1000110;
4'd13: out = 7'b0100001;
4'd14: out = 7'b0000110;
4'd15: out = 7'b0001110;
default: out = 7'b1111111;//tot stins
endcase
end
endmodule
Descrierea sistemului, modulul de top (fisierul top.v):
module top
(
input wire clock,
input wire reset,
input wire button,
output wire [6:0] out // logica negativa
);
wire debounce_0_X_out;
wire [3:0] counter_4b_0_X_out;
debounce
#(
.limit(20'd50_000)
) debounce_0 (
.clock(clock),
.in(button),
.out(debounce_0_X_out)
);
counter_4b counter_4b_0
(
.clock(clock),
.reset(reset),
.en(debounce_0_X_out),
.out(counter_4b_0_X_out)
);
transcodor_7seg transcodor_7seg_0 // logica negativa
(
.in(counter_4b_0_X_out),
.out(out)
);
endmodule
Descrierea test bench-ului(fisierul tb.v):
`timescale 1ns / 1ps
module tb();
reg clock_tb;
reg reset_tb;
reg button_tb;
wire [6:0] out_tb;
top dut
(
.clock(clock_tb),
.reset(reset_tb),
.button(button_tb),
.out(out_tb) // logica negativa
);
initial
begin
clock_tb = 0;
forever
begin
#5 clock_tb = ~clock_tb;
end
end
initial
begin
reset_tb = 0;
button_tb = 0;
#50;
reset_tb = 1;
#50;
reset_tb = 0;
#100;
repeat(5) // vreau 5 apasari de buton
begin
button_tb = 1;
repeat(70_000)
begin
@(posedge clock_tb);
end
button_tb = 0;
repeat(70_000)
begin
@(posedge clock_tb);
end
end
#1000 $stop();
end
endmodule
Exercitii
Exercitiul 1: Divizor de frecventa cu puteri ale lui 2
Divizorul de frecventa are rolul de a genera un semnal de ceas mai lent din semnalul de ceas principal. El este alcatuit doar dintr-un numarator, iar fiecare bit al acestuia va fi practic un semnal de ceas cu frecventa din ce in ce mai mica astfel (la jumate):
bit[0] - frecventa de 2 ori mai mica decat semnalul de ceas bit[1] - frecventa de 2 ori mai mica decat bit[0], deci de 4 ori mai mica decat semnalul de ceas bit[2] - frecventa de 2 ori mai mica decat bit[1], deci de 8 ori mai mica decat semnalul de ceas
Acest lucru se poate observa si in poza ce urmeaza:
Implementati acest circuit si folosind ledurile prezente pe placa, incercati sa conectati bitul corespunzator la leduri astfel incat cel mai din dreapta led sa clipeasca cu o frecventa cat mai apropiata de 1s.
Observatie: Printr-un astfel de divizor de frecventa minimal, un numar f mic de frecvente poate fi generat. Daca se doreste generarea unui semnal periodic cu o perioada exacta, diferita de cele posibile prin acest mecanism, se poate construi urmatorul circuit:
Exercitiul 2: Divizor de frecventa ce poate genera orice perioada
Un astfel de divizor de frecventa este construit ca in figura de mai jos:
Prin adaugarea constantei "limit", perioada semnalului de iesire poate sa fie orice multiplu a perioadei semnalului de ceas.
Bistabilul de tip t, se modifica atunci cand limita este atinsa si practic iesirea lui este semnalul periodic.
Sa se calculeze valoarea necesara pentru "limit" astfel incat pe led-uri sa se genereze semnal cu perioada exact 1s.
Exercitiul 3: PWM (Pulse Width Modulation)
PWM este un concept folosit foarte des in multiple ramuri ale ingineriei, de la transmisiunea informatiei pana la controlul motoarelor sau al intensitatii ledurilor din instalatii de Craciun. El se refera la a avea un semnal periodic cu factor de umplere variabil, asa cum este aratat in poza de mai jos :
Generarea unui astfel de semnal periodic se face printr-un numarator si un comparator, ca in figura de mai jos:
Raportul dintre limita pusa si valoarea la care numaratorul se reseteaza este practic factorul de umplere selectat.
Pentru testare pe placa, cei 6b ai limitei provin de la switch-uri si butoane. Afisarea se face pe led[0].
Exercitiul 4: PWM cu limita variabila
Un exemplu foarte uzual de folosire a PWM este aprinderea ledurilor cu diverse pattern-uri. Factorul de umplere determina intensitatea cu care ledul este aprins. Un PWM cu o limita variabila automata va face ledul sa para din ce in ce mai stins sau din ce in ce mai luminos (exemplu: instalatii de Craciun). Combinand asta cu leduri RGB se obtin efecte de schimbare a culorii ledului aparent la intamplare.
Un astfel de circuit se realizeaza punand inca un numarator in locul limitei, ca in poza de mai jos:
Pentru o functionalitate suplimentara, a pastra un anumit factor de umplere mai multe perioade, am adaugat inca un numarator.
Pentru claritatea desenului, nu am mai tras efectiv firul de ceas catre intrarile unde acesta se duce.
Rezultatul este:
Bonus: Incercati sa adaugati si parametri pentru LIMIT_DUTY_CYCLE_LOW si LIMIT_DUTY_CYCLE_HIGH, care sa permita factorului de umplere sa varieze doar intre ele. (Numaratorul va avea nevoie si de intrari pentru comanda de load si data load, ca sa poata incepe de la orice valoare)
Exercitiul 5: Ceas
Un ceas poate fi construit cifra cu cifra, folosind numaratoare si comparatoare (si transcodoare pentru display cu 7seg ca sa se vada totul mai bine pe placa)
Incercati sa implementati un ceas cu milisecunde, secunde si minute in varianta comportamentala.
Observatie: Va fi nevoie fie separat, fie in modul de un numarator cu frecventa rezolutiei dorite (aici 1 ms). Observatie: Codul va contine multe "if" de tipul "daca cifra unitatilor secundelor a ajuns la 10, se face 0 si cresc cifra zecilor", repetate pentru fiecare cifra.
Incercati si o implementare structurala a ceasului, mergand pe aceasi idee. Fiecare cifra va contine numaratorul ei. Cand numaratorul unei cifre ajunge ajunge la limita sa, va da enable pentru numaratorul cifrei urmatoare. Daca este nevoie se pot folosi si porti aditionale (ex: ca sa creasca minutul cifra zecilor secundelor trebuie sa fie 5 si cifra unitatilor secundelor trebuie sa fie 9).
Observatie: Va fi nevoie de un numarator cu frecventa rezolutiei dorite (aici 1 ms sau 1s). Observatie: Pentru a scrie mai putin puteti face un numarator doar cu secunde si minute. Principiul de baza este acelasi si daca aveati ms. Observatie: Simularea a cateva milisecunde sau chiar secunde este un proces indelungat (dureaza minute-ore fizice). Astfel strict pentru simulari se recomanda ceasul sa functioneze cu microsecunde sau milisecunde maxim.