Verilog Práctico

Capítulo 4. Display de 7 segmentos.

9 de enero de 2021

En esta entrada veremos cómo controlar un display de 7 segmentos.


En el esquema de conexión se muestra un display de ánodo común. Para un display de cátodo común hay que conectar los pines 3 y 8 a GND, los pines de los segmentos a-g se conectan igual. En caso de duda consulta el datasheet del display que vayas a utilizar.

He intercalado un 74HC244 entre la Alhambra y el display para mejorar la calidad de las señales. El 244 es un buffer o line driver no inversor que elimina el ruido y amplifica las señales. El uso de este CI es opcional, pero si experimentas problemas de funcionamiento, prueba a utilizar uno. 

1. Contador hexadecimal 


Veamos un ejemplo de funcionamiento con un contador hexadecimal accionado mediante el switch 1 de la Alhambra.


Declaramos un módulo que llamaremos display y que tiene como entrada el switch 1 y como salida un registro de 8 bits reg [7:0] segmentos este registro lo utilizaremos para iluminar los ledes del display.


module display ( input SW1, output reg [7:0] segmentos = 0);


Declaramos un registro de 4 bits que llamaremos reg [3:0] contador donde se almacena el valor del contador. Con 4 bits podemos contar de 0 a 15 que representaremos en hexadecimal como 0-F.


reg [3:0] contador = 0;


Con la declaración always @(posedge SW1) estamos diciendo que cada vez que pulsemos SW1 se incremente el contador contador <= contador + 1 y con case (contador) evaluamos el valor del contador y asignamos el registro segmentos distintos valores para iluminar los ledes del display de acuerdo al valor del contador. En caso de utilizar un display de cátodo común, cambiar los ceros por unos en la estructura case. Por ejemplo, el 0 quedaría así: 4'd0: segmentos <= 8'b00111111;


Como se declaran números en verilog:


4’d9 significa número de 4 bits, decimal de valor 9

8’b11001010 significa número de 8 bits, binario de valor 11001010

4’hF significa número de 4 bits, hexadecimal de valor F


Ponemos todo junto y el código queda así:

// decodificador HEX de 7 segmentos con contador manual

// accionado mediente SW1.


// declaramos las E/S. Los registros los inicializamos a 0

module display ( input SW1, output reg [7:0] segmentos = 0);

reg [3:0] contador = 0;

always @(posedge SW1)

  begin


// con cada pulsación de SW1 incrementamos el contador

    contador <= contador + 1;


// dependiendo del valor del contador,

// asignamos un valor al registro SEG

// para que ilumine los ledes correspondientes a cada número

    case (contador)      //pgfe_dcba segmentos

      4'd0: segmentos <= 8'b1100_0000;

      4'd1: segmentos <= 8'b1111_1001;

      4'd2: segmentos <= 8'b1010_0100;

      4'd3: segmentos <= 8'b1011_0000;

      4'd4: segmentos <= 8'b1001_1001;

      4'd5: segmentos <= 8'b1001_0010;

      4'd6: segmentos <= 8'b1000_0010;

      4'd7: segmentos <= 8'b1111_1000;

      4'd8: segmentos <= 8'b1000_0000;

      4'd9: segmentos <= 8'b1001_1000;

      4'd10: segmentos <= 8'b1000_1000;

      4'd11: segmentos <= 8'b1000_0011;

      4'd12: segmentos <= 8'b1100_0110;

      4'd13: segmentos <= 8'b1010_0001;

      4'd14: segmentos <= 8'b1000_0110;

      4'd15: segmentos <= 8'b1000_1110;

    endcase

  end

endmodule

El archivo .pfc es el siguiente:


set_io SW1 10

set_io segmentos[0] 119

set_io segmentos[1] 118

set_io segmentos[2] 117

set_io segmentos[3] 116

set_io segmentos[4] 115

set_io segmentos[5] 114

set_io segmentos[6] 113

set_io segmentos[7] 112


Lo subimos a la Alhambra y vemos que con cada pulsación de SW1 el display va mostrando los números 0-9 y las letras A-F.

2. Contador decimal


En el siguiente ejemplo veremos un contador decimal activado con el pulsador SW1. A grandes rasgos el código es similar al ejemplo anterior, pero eliminando de la estructura case aquellos dígitos que no se van a utilizar e introduciendo una sentencia if() para resetear el contador cuando llega a 10.

// decodificador decimal para display 7 segmentos con

// contador manual por flanco de SW1

// declaramos las E/S. Los registros los inicializamos a 0

module display( input SW1, output reg [7:0] segmentos = 0);

reg [3:0] contador;

always @ ( posedge SW1 ) begin

contador <= contador + 1;

// comprobamos el contador

// y si llega a 10 lo reseteamos

if (contador>=4'd9)

  contador <= 4'd0;


    case (contador)     //pgfedcba segmentos

      4'd0: segmentos <= 8'b1100_0000;

      4'd1: segmentos <= 8'b1111_1001;

      4'd2: segmentos <= 8'b1010_0100;

      4'd3: segmentos <= 8'b1011_0000;

      4'd4: segmentos <= 8'b1001_1001;

      4'd5: segmentos <= 8'b1001_0010;

      4'd6: segmentos <= 8'b1000_0010;

      4'd7: segmentos <= 8'b1111_1000;

      4'd8: segmentos <= 8'b1000_0000;

      4'd9: segmentos <= 8'b1001_1000;

      default: segmentos <= 8'b1111_1111;

    endcase

end

endmodule

El archivo .pfc es igual que en el ejemplo 1.


Lo compilamos y lo subimos a la Alhambra y vemos que con cada pulsación de SW1 el display va mostrando los números 0-9.

3. Contador decimal con prescaler


En el capítulo 3 vimos cómo dividir la frecuencia del reloj en frecuencias menores mediante el uso de un prescaler. Añadiremos uno al código anterior para hacer un contador decimal que se incrementa de manera automática.


La velocidad con la que se incrementa el contador la seleccionamos mediante:


assign clk_out = prescaler[22];


El código es el siguiente:

// decodificador decimal para display 7 segmentos con prescaler

module display(input clk, output reg [7:0] segmentos = 0);


wire clk;

wire clk_out;


//-- Registro para implementar contador de N bits

reg [23:0] prescaler = 0;


//-- El bit más significativo se saca por la salida

assign clk_out = prescaler[22];


//-- Contador: se incrementa en flanco de subida

always @(posedge(clk))

begin

  prescaler <= prescaler + 1;

end

// en este registro se almacena el valor del contador

reg [3:0] contador;

always @ ( posedge clk_out ) begin

contador <= contador + 1;

// comprobamos el contador

// y si llega a 10 lo reseteamos

if (contador>=4'd9)

  contador <= 4'd0;


// dependiendo del valor del contador,

// asignamos un valor al registro SEG

// para que ilumine los ledes correspondientes a cada número

    case (contador)       //pgfedcba segmentos

      4'd0: segmentos <= 8'b1100_0000;

      4'd1: segmentos <= 8'b1111_1001;

      4'd2: segmentos <= 8'b1010_0100;

      4'd3: segmentos <= 8'b1011_0000;

      4'd4: segmentos <= 8'b1001_1001;

      4'd5: segmentos <= 8'b1001_0010;

      4'd6: segmentos <= 8'b1000_0010;

      4'd7: segmentos <= 8'b1111_1000;

      4'd8: segmentos <= 8'b1000_0000;

      4'd9: segmentos <= 8'b1001_1000;

      default: segmentos <= 8'b1111_1111;

    endcase

  end

endmodule

El archivo pcf es el siguiente:


set_io clk 21

set_io segmentos[0] 119

set_io segmentos[1] 118

set_io segmentos[2] 117

set_io segmentos[3] 116

set_io segmentos[4] 115

set_io segmentos[5] 114

set_io segmentos[6] 113

set_io segmentos[7] 112


Lo compilamos y lo subimos a la Alhambra y vemos como el contador se incrementa de manera automática.

4. Contador hexadecimal con reset


En este último ejemplo vamos a añadir un prescaler y un reset manual al contador hexadecimal del ejemplo 1.


El reset lo implementamos con una declaración if() asociada al pulsador SW1


if (reset)

    contador <= 4'd0;

 

Si solo vamos a declarar una acción no hace falta poner begin-end, pero si queremos declarar múltiples acciones cuando se cumpla if() hay que poner begin-end.


if (reset)

  begin

     accion 1;

accion 2;

accion 3;

  end

El código queda así:


module display(input clk, input reset, output reg [7:0] segmentos = 0);


wire clk;

wire clk_out;


reg [23:0] prescaler = 0;

reg [3:0] contador;


assign clk_out = prescaler[22];


always @(posedge(clk))

begin

  prescaler <= prescaler + 1;

end


always @ ( posedge clk_out ) begin

contador <= contador + 1;

if (reset)

  begin

    contador <= 4'd0;

  end


    case (contador)       //pgfedcba segmentos

      4'd0: segmentos <= 8'b1100_0000;

      4'd1: segmentos <= 8'b1111_1001;

      4'd2: segmentos <= 8'b1010_0100;

      4'd3: segmentos <= 8'b1011_0000;

      4'd4: segmentos <= 8'b1001_1001;

      4'd5: segmentos <= 8'b1001_0010;

      4'd6: segmentos <= 8'b1000_0010;

      4'd7: segmentos <= 8'b1111_1000;

      4'd8: segmentos <= 8'b1000_0000;

      4'd9: segmentos <= 8'b1001_1000;

      4'd10: segmentos <= 8'b100_01000;

      4'd11: segmentos <= 8'b100_00011;

      4'd12: segmentos <= 8'b110_00110;

      4'd13: segmentos <= 8'b101_00001;

      4'd14: segmentos <= 8'b100_00110;

      4'd15: segmentos <= 8'b100_01110;

      default: segmentos <= 8'b1111_1111;

    endcase

  end

endmodule

El archivo pcf es el siguiente:


set_io clk 21

set_io reset 10

set_io segmentos[0] 119

set_io segmentos[1] 118

set_io segmentos[2] 117

set_io segmentos[3] 116

set_io segmentos[4] 115

set_io segmentos[5] 114

set_io segmentos[6] 113

set_io segmentos[7] 112


Lo subimos a la Alhambra y vemos un contador hexadecimal automático. Si pulsamos el switch 1 reseteamos el contador a 0.

Eso es todo.  


¡Hasta pronto!

Descargas


Descarga los ejemplos en verilog aquí.

Links


Más info sobre displays de 7 segmentos con la Alhambra aquí:


digital-electronics-with-open-FPGAs-tutorial. Vídeo 24: Display de 7 segmentos