Verilog: wyświetlacz 7seg multipleksowany

Gdy chcemy zastosować większą ilość wyświetlaczy 7-segmentowych, pojawia się problem dużej liczby połączeń. W przypadku tradycyjnego sterowania, każdy z tych wyświetlaczy ma 8 wejść. Gdy mamy ich na przykład cztery, to daje nam to aż 32 połączenia. Jest to marnotrawstwo nóżek układy scalonego, który tymi wyświetlaczami ma sterować.

Istnieje bardzo prosty sposób, by zminimalizować liczbę potrzebnych połączeń - multipleksacja. Polega to na tym, ze łączymy ze sobą wszystkie identyczne segmenty wyświetlaczy, tzn. wszystkie a łączymy razem, wszystkie b razem i tak dalej. Jak sprawić, by na każdym wyświetlaczu pojawiała się inna cyfra? W danej chwili może świecić się tylko jeden wyświetlacz. Do tego celu wykorzystamy elektrody wspólne wyświetlaczy, mianowicie wspólną katodę lub wspólną anodę. Włączamy pierwszy wyświetlacz i pokazujemy pierwszą cyfrę. Potem go wyłączamy, włączamy drugi i pokazujemy drugą cyfrę, i tak dalej. Przełączenia muszą się odbywać z odpowiednio dużą częstotliwością, by nie było widać mrugania.

Wszystko wyjaśnia animacja z wkrętak.pl

Multipleksacja wyświetlacza

Prezentowany przykład dostosowany jest do mojej płytki testowej, którą opisałem w artykule Płytki testowe do mikrokontrolerów

Wyświetlacz multipleksowany schemat

Sterownik wyświetlacza wymaga dostarczenia sygnału zegarowego o częstotliwości minimum 250Hz. Przy mniejszej widać mruganie wyświetlaczy. Można dać większą częstotliwość, ale nie poprawi to efektu, a jedynie zwiększy prądożerność układu.

Obsługiwany jest wyświetlacz czterocyfrowy, w którym poszczególne cyfry ponumerowane są od prawej, zaczynając od zera. Wyjścia display3, display2, display1, display0 łączymy z anodami tych wyświetlaczy, pamiętając o tranzystorach, by nie uszkodzić układu FPGA przez nadmierny prąd płynący przez jego nóżki. Wyjścia sa, sb, sc... to oczywiście linie sterujące segmentami. Dane do sterownika dostarczane są przez cztery magistrale czterobitowe digit3, digit2, digit1, digit0, po jednej na każdy wyświetlacz.

Kod dzieli się na trzy części:

  • licznik sterujący
  • multiplekser
  • dekoder

W pierwszej z nich widzimy prosty licznik 2-bitowy, czyli taki który liczy od 0 do 3. Jest on dyrygentem, wyznaczającym który wyświetlacz ma się świecić w danej chwili. Multiplekser to elektroniczny przełącznik. W tym przypadku potrzebna nam jest "zwrotnica" wybierająca jeden 4-bitowy sygnał digit spośród czterech 4-bitowych danych wejściowych digitX (X = 3, 2, 1, 0). Oprócz tego jest tu zawarty również prosty dekoder z kody binarnego na kod "1 z 4", co posłuży do uaktywniania tylko jednego wyświetlacza i wygaszenia pozostałych. Trzecia część kodu to dekoder znany z poprzedniego artykułu, przetwarzający liczbę zapisaną binarnie na kombinację zapalonych i zgaszonych segmentów.

 
module seg7_multiplex(
    input clk_250Hz,
    input [3:0] digit3, digit2, digit1, digit0,        // wejscia danych
    output reg sa, sb, sc, sd, se, sf, sg,             // 0 zapalony, 1 zgaszony
    output reg display3, display2, display1, display0  // 0 zapalony, 1 zgaszony
);
    
    // licznik sterujący
    reg [1:0] selektor;
    always @(posedge clk_250Hz)
        selektor <= selektor + 1;
    
    // wybór aktywnego wyświetlacza i cyfry do wyświetlenia
    reg [3:0] digit;
    always @(selektor, digit0, digit1, digit2, digit3)
        case(selektor)
            0:
                begin
                display3 <= 1;
                display2 <= 1;
                display1 <= 1;
                display0 <= 0;
                digit <= digit0;
                end
            1:
                begin
                display3 <= 1;
                display2 <= 1;
                display1 <= 0;
                display0 <= 1;
                digit <= digit1;
                end
            2:
                begin
                display3 <= 1;
                display2 <= 0;
                display1 <= 1;
                display0 <= 1;
                digit <= digit2;
                end
            3:
                begin
                display3 <= 0;
                display2 <= 1;
                display1 <= 1;
                display0 <= 1;
                digit <= digit3;
                end
            default:
                begin
                display3 <= 1;
                display2 <= 1;
                display1 <= 1;
                display0 <= 1;
                digit <= digit0;
                end
        endcase
    
    // dekoder BIN -> 7seg
    always @(digit)
        case(digit)                             //abcdefg
            4'b0000: {sa,sb,sc,sd,se,sf,sg} <= 7'b0000001;  // 0
            4'b0001: {sa,sb,sc,sd,se,sf,sg} <= 7'b1001111;  // 1
            4'b0010: {sa,sb,sc,sd,se,sf,sg} <= 7'b0010010;  // 2
            4'b0011: {sa,sb,sc,sd,se,sf,sg} <= 7'b0000110;  // 3
            4'b0100: {sa,sb,sc,sd,se,sf,sg} <= 7'b1001100;  // 4
            4'b0101: {sa,sb,sc,sd,se,sf,sg} <= 7'b0100100;  // 5
            4'b0110: {sa,sb,sc,sd,se,sf,sg} <= 7'b0100000;  // 6
            4'b0111: {sa,sb,sc,sd,se,sf,sg} <= 7'b0001111;  // 7
            4'b1000: {sa,sb,sc,sd,se,sf,sg} <= 7'b0000000;  // 8
            4'b1001: {sa,sb,sc,sd,se,sf,sg} <= 7'b0000100;  // 9
            4'b1010: {sa,sb,sc,sd,se,sf,sg} <= 7'b0001000;  // a
            4'b1011: {sa,sb,sc,sd,se,sf,sg} <= 7'b1100000;  // b
            4'b1100: {sa,sb,sc,sd,se,sf,sg} <= 7'b0110001;  // c
            4'b1101: {sa,sb,sc,sd,se,sf,sg} <= 7'b1000010;  // d
            4'b1110: {sa,sb,sc,sd,se,sf,sg} <= 7'b0110000;  // e
            4'b1111: {sa,sb,sc,sd,se,sf,sg} <= 7'b0111000;  // f
            default: {sa,sb,sc,sd,se,sf,sg} <= 7'b1111111;  // -
        endcase

endmodule