在实验中,时常需要在数码管上显示数字。
此时,需要使用译码器将输入的信号进行转换,使得数码管能显示对应数字。
一、数码管七段译码器
数码管上每一位都可以显示一位数字,数字可以通过如图的(A、B、C、D、E、F、G)七段显示出来。
如要显示数字1,则使B、C段亮即可。
由于输入的信号是一位数字,所以需要将其译码为数码管需要的二进制段选信号。
七段译码器:将输入的四位二进制信号Data(0~9),译成数码管的七位段选信号codeout。
codeout[6]=a,codeout[5]=b......,codeout[0]=g。
module Test(codeout,Data);
input[3:0] Data; //4位输入信号
output[6:0] codeout;//7位输出信号
reg[6:0] codeout; //输出变量数据类型为寄存器型
always @(Data) //用always块语句描述逻辑
begin
case(Data)//case多分支条件语句,按输入显示对应输出
4'd0 : codeout = 7'b1111110;
4'd1 : codeout = 7'b0110000;
4'd2 : codeout = 7'b1101101;
4'd3 : codeout = 7'b1111001;
4'd4 : codeout = 7'b0110011;
4'd5 : codeout = 7'b1011011;
4'd6 : codeout = 7'b1011111;
4'd7 : codeout = 7'b1110000;
4'd8 : codeout = 7'b1111111;
4'd9 : codeout = 7'b1111011;
default : codeout = 7'bx;//其他输入情况
endcase
end
endmodule
通过改变Data的值,可以改变数码管显示的值。
二、数码管动态扫描
一、设计思路
有时候需要数码管在不同位显示不同的数字。
选择只在指定位置显示对应数字,一次显示一位数字,通过循环显示对应的几位数字,利用人眼的视觉暂留效应达到显示出多位不同数字。
此处举显示三位数字的例子。
当计数器值为0时,只在数码管第一位显示第一位数字;
当计数器值为1时,只在数码管第二位显示第二位数字;
当计数器值为2时,只在数码管第三位显示第三位数字;
计数器的值不断循环重复,数码管显示出三位数字。
需要增加位选信号[7:0]SEG,控制数码管亮的位置;模三计数器,循环计数k。
代码使用层次化设计,同时增加了前置分频器,将50MHz的时钟信号分成1000Hz的信号。
二、代码实现
顶层文件
module Test(en,clk,CLK,SEG,codeout,Data,k);
input clk; //50MHz时钟信号
input en; //使能信号
output CLK; //分频后信号
output [7:0]SEG; //位选信号
output [6:0]codeout; //数码管信号
output [3:0]Data; //显示数字
output [1:0]k; //计数器
Test_1 t1(clk,CLK); //分频器50MHz->1000Hz(clk->CLK)
Test_2 t2(CLK,k,en); //模三计数器(由CLK控制k的值)
Test_3 t3(k,Data); //数据选择器(由k控制Data的值)
Test_4 t4(k,SEG); //位选译码器(由k控制SEG的值)
Test_5 t5(codeout,Data); //接入七段译码器(将Data译码)
endmodule
模块1:分频器(也可以不要分频器,删除模块1和clk,直接将输入信号接入到CLK上也可)
module Test_1(clk,CLK); //分频器
input clk; //50MHz输入
output reg CLK = 1'd0; //分频后CLK信号
integer tmp = 0; //计数
always@(negedge clk) //clk信号下降沿触发
begin
tmp <= tmp + 1;
if(tmp >= 24999) //每25000次取反一次
begin
CLK <= ~CLK; //输出取反
tmp <= 0;
end
end
endmodule
模块2:模三计数器
module Test_2(CLK,k,en); //模3计数器
input CLK,en; //1000Hz,使能信号
output reg [1:0]k = 2'b00; //计数器值k
always@(posedge CLK)
begin
if(en==1) //en为1时才能正常显示
begin //k取值为0,1,2
if(k <= 2'd1)
k <= k + 2'd1; //小于2加一
else
k <= 2'd0; //等于2取0
end
end
endmodule
模块三:数据选择器
module Test_3(k,Data); //数据选择器
input [1:0]k; //计数器值k
output reg[3:0]Data = 4'b0000; //显示数字Data
always@(k)
begin
case(k) //显示123
2'd0:Data<=4'd1;
2'd1:Data<=4'd2;
2'd2:Data<=4'd3;
default:Data<=4'bx;
endcase
end
endmodule
模块四:位选译码器
module Test_4(k,SEG); //位选译码器
input [1:0]k; //计数器值k
output reg[7:0]SEG = 8'b00000000; //位选信号
always@(k)
begin
case(k)
2'd0:SEG<=8'b10000000; //第一位亮
2'd1:SEG<=8'b01000000; //第二位亮
2'd2:SEG<=8'b00100000; //第三位亮
default:SEG<=8'bx;
endcase
end
endmodule
模块五:七段译码器
module Test_5(codeout,Data); //七段译码器
input[3:0] Data;//4位输入信号
output reg[6:0]codeout = 7'b1111110; //7位输出信号
always @(Data)//用always块语句描述逻辑
begin
case(Data)//case多分支条件语句,按输入显示对应输出
4'd0 : codeout = 7'b1111110;
4'd1 : codeout = 7'b0110000;
4'd2 : codeout = 7'b1101101;
4'd3 : codeout = 7'b1111001;
4'd4 : codeout = 7'b0110011;
4'd5 : codeout = 7'b1011011;
4'd6 : codeout = 7'b1011111;
4'd7 : codeout = 7'b1110000;
4'd8 : codeout = 7'b1111111;
4'd9 : codeout = 7'b1111011;
default : codeout = 7'bx;//其他输入情况
endcase
end
endmodule
三、ModelSim仿真
使用ModelSim进行仿真。
注意:在程序文件中,对于reg型变量需要赋予初值,否则在波形图中可能会出现红色波(值未定)。
Test Bench文件
`timescale 1 ns/ 1 ns
module Test_vlg_tst();
reg clk;
reg en;
wire CLK;
wire [3:0] Data;
wire [7:0] SEG;
wire [6:0] codeout;
wire [1:0] k;
Test i1 (
.CLK(CLK),
.Data(Data),
.SEG(SEG),
.clk(clk),
.codeout(codeout),
.en(en),
.k(k)
);
initial
begin
clk = 0;
en = 1;
#4000000 //延迟4ms关闭使能信号en 1ms,而后en=1
en = 0;
#1000000
en = 1;
$display("Running testbench");
end
always#10 clk = ~clk; //每10个时间单位翻转一次(即周期为20ns,频率50MHz)
endmodule
波形图
在CLK信号下:
k值在00,01,10中循环;
对应Data值为0001,0010,0011;
位选信号SEG分别表示第一位亮,第二位亮,第三位亮。
当en为1时,数码管正常显示三位数字;当en为0时,数码管只显示一位数字。