数码管段码显示
一个数码管有八个引脚,控制八段二极管的亮灭,用以显示需要的数字。
当有N个数码管时,一个一个控制的话需要N x 8 个引脚,消耗资源较多。用动态显示的方法可降低成本
数码管动态显示
将每个数码管相应的LED阴极连在一起,并加入选通信号sel。sel为高电平(位选),阴极为低电平(段选)
eg:当sel0为高电平,sel1、sel2为低电平,a为低电平,b-h为高电平时,数码管0的LED0点亮
动态显示的方案通过人眼的视觉暂留特性达到静态显示的效果(动态显示周期<20ms),只需8+n个引脚。节省了大量资源。
逻辑电路:
任务要求clk1频率为50MHz,即周期20ns,分频后clk2频率为1kHz,即周期1ms(500us翻转一次)
查找表:
不同段码输入后相应的显示内容:
verilog设计文件:
①
`timescale 1ns / 1ps
module hex8(
Clk,
Reset_n,
Disp_Data,
sel,
seg
);
input Clk;
input Reset_n;
input[31:0]Disp_Data;
output reg [7:0]sel;
output reg[7:0]seg;//seg[0]对应a...seg[7]对应h
reg clk_1k; //周期1ms(500us翻转一次)
reg [14:0]div_cnt; //5000000/20=25000 15位二进制
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
div_cnt <= 0;
else if(div_cnt == 24999)
div_cnt <= 0;
else
div_cnt <= div_cnt + 1'b1;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
clk_1k <= 0;
else if(div_cnt >= 24999)
clk_1k <= ~clk_1k;
//这种时钟在绝大多数场合不允许使用
reg [2:0]num_cnt;
always@(posedge clk_1k or negedge Reset_n)
if(!Reset_n)
num_cnt <= 0;
else
num_cnt <= num_cnt + 1'b1;
//三八译码器
always@(*)
case(num_cnt)
0:sel = 8'b00000001;
1:sel = 8'b00000010;
2:sel = 8'b00000100;
3:sel = 8'b00001000;
4:sel = 8'b00010000;
5:sel = 8'b00100000;
6:sel = 8'b01000000;
7:sel = 8'b10000000;
endcase
//数码管输出-查表
reg[3:0]disp_tmp;
always@(*)
case(num_cnt)
0:disp_tmp = Disp_Data[31:28];
1:disp_tmp = Disp_Data[27:24];
2:disp_tmp = Disp_Data[23:20];
3:disp_tmp = Disp_Data[19:16];
4:disp_tmp = Disp_Data[15:12];
5:disp_tmp = Disp_Data[11:8];
6:disp_tmp = Disp_Data[7:4];
7:disp_tmp = Disp_Data[3:0];
endcase
always@(*)
case(disp_tmp)
4'h0:seg = 8'hc0; //注意,是用十六进制表示,这里的0也是十六进制的0
4'h1:seg = 8'hf9;
4'h2:seg = 8'ha4;
4'h3:seg = 8'hb0;
4'h4:seg = 8'h99;
4'h5:seg = 8'h92;
4'h6:seg = 8'h82;
4'h7:seg = 8'hf8;
4'h8:seg = 8'h80;
4'h9:seg = 8'h90;
4'ha:seg = 8'h88;
4'hb:seg = 8'h83;
4'hc:seg = 8'hc6;
4'hd:seg = 8'ha1;
4'he:seg = 8'h86;
4'hf:seg = 8'h8e;
endcase
endmodule
②改进:
`timescale 1ns / 1ps
module hex8(
Clk,
Reset_n,
Disp_Data,
sel,
seg
);
input Clk;
input Reset_n;
input[31:0]Disp_Data;
output reg [7:0]sel;
output reg[7:0]seg;//seg[0]对应a...seg[7]对应h
reg clk_1k;
reg [15:0]div_cnt;
//改进:使能时钟,每1ms给一个持续20ns的高电平,其他时候均为低电平
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
div_cnt <= 0;
else if(div_cnt == 49999)
div_cnt <= 0;
else
div_cnt <= div_cnt + 1'b1;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
clk_1k <= 0;
else if(div_cnt == 49999)
clk_1k <= 1'b1;
else
clk_1k <= 0;
reg [2:0]num_cnt;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
num_cnt <= 0;
else if(clk_1k)
num_cnt <= num_cnt + 1'b1;
//尽量都改为时序逻辑
//三八译码器-sel位选
always@(posedge Clk)
case(num_cnt)
0:sel = 8'b00000001;
1:sel = 8'b00000010;
2:sel = 8'b00000100;
3:sel = 8'b00001000;
4:sel = 8'b00010000;
5:sel = 8'b00100000;
6:sel = 8'b01000000;
7:sel = 8'b10000000;
endcase
//提取该位数码管需要输出的内容-查表
reg[3:0]disp_tmp;
always@(posedge Clk)
case(num_cnt)
7:disp_tmp = Disp_Data[31:28];
6:disp_tmp = Disp_Data[27:24];
5:disp_tmp = Disp_Data[23:20];
4:disp_tmp = Disp_Data[19:16];
3:disp_tmp = Disp_Data[15:12];
2:disp_tmp = Disp_Data[11:8];
1:disp_tmp = Disp_Data[7:4];
0:disp_tmp = Disp_Data[3:0];
endcase
//seg段选
always@(posedge Clk)
case(disp_tmp)
4'h0:seg = 8'hc0; //注意,是用十六进制表示,这里的0也是十六进制的0
4'h1:seg = 8'hf9;
4'h2:seg = 8'ha4;
4'h3:seg = 8'hb0;
4'h4:seg = 8'h99;
4'h5:seg = 8'h92;
4'h6:seg = 8'h82;
4'h7:seg = 8'hf8;
4'h8:seg = 8'h80;
4'h9:seg = 8'h90;
4'ha:seg = 8'h88;
4'hb:seg = 8'h83;
4'hc:seg = 8'hc6;
4'hd:seg = 8'ha1;
4'he:seg = 8'h86;
4'hf:seg = 8'h8e;
endcase
endmodule
仿真文件:
`timescale 1ns / 1ps
module hex8_tb();
reg Clk;
reg Reset_n;
reg [31:0]Disp_Data;
wire[7:0]sel;
wire[7:0]seg;
hex8 hex8(
Clk,
Reset_n,
Disp_Data,
sel,
seg
);
initial Clk = 1;
always #10 Clk = ~Clk;
initial begin
Reset_n = 0;
Disp_Data = 32'h00000000;
#201;
Reset_n = 1;
#2000;
Disp_Data = 32'h12345678;
#10000000;
Disp_Data = 32'h9abcdef0;
#10000000;
$stop;
end
endmodule