数码管静态显示
数码管
数码管是一种半导体发光器件,其基本单元是发光二极管。
数码管静态显示0-F
共阴极数码管:八根数码管的阴极全部连接在一起,阳极独立。
共阳极数码管:八根数码管的阳极全部连接在一起,阴极独立。
只有在每个对应的端口输入低电平了,才可以点亮对应的二极管
六位八段数码管
当使用多位数码管时,为了减少数码管占用的IO口,我们将断选,就是数码管的abc等引脚连接在一起,位选信号独立控制,可以通过位选信号控制哪几个数码管点亮,就是通过位选信号控制选中哪一位数码管,而在同一时刻,位选选通的数码管,显示的数字始终都是一样的,因为它们的断选都是连接在一起的,送入所有的数码管的断选信号都是相同的,这种显示方式称为静态显示。
六位位选就是选择这六个数码管的哪一位进行显示。
八位段选就是选择那几段数码管进行点亮。
这个就是选择六个位选信号,第一个位选信号的显示0(段选信号abcdef点亮),第二个位选信号显示1(段选信号bc点亮),第三个位选信号显示2(段选信号abged点亮),第四个位选信号显示3(段选信号abgcd点亮),第五个位选信号显示4(段选信号fgbc点亮),第六个位选信号显示6(段选信号aafgcd点亮)。
知道位选和段选的关系之后,现在要实现六位数码管从0-F的显示。就需要将六位位选信号显示,并且根据要显示的数据,改变段选信号的值,改变数据显示的值,就设定为每0.5s变换一次。
本次实验使用的是共阴极数码管,所以共阴极的数码管0-F的段码为
{0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef,0xf7,0xfc,0xb9,0xde,0xf9,0xf1}
根据理论的解析,就可以进行代码的编写了。
数码管的控制模块代码
module seg_ctrl (
input clk,
input rst_n,
output[5:0] sel, // 位选信号
output[7:0] seg // 段选信号
);
// 定义一个时间500ms,设置数码管每500ms变化一次
parameter TIME_500ms = 25'd25_000_000;
// 定义一个500ms计数器
reg[24:0] cnt_500ms;
wire add_cnt_500ms;
wire end_cnt_500ms;
// 定义一个用来显示0-f的数据
reg[3:0] data;
// 定义6为位选,8位段选
reg[5:0] sel_r;
reg[7:0] seg_r;
// 500ms计数器
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_500ms <= 0;
end
else if(add_cnt_500ms)begin
if(end_cnt_500ms)begin
cnt_500ms <= 0;
end
else begin
cnt_500ms <= cnt_500ms + 1;
end
end
end
assign add_cnt_500ms = 1'b1;// 开始计数条件一直为1
assign end_cnt_500ms = add_cnt_500ms && cnt_500ms == TIME_500ms - 1;// 当计数到500ms结束计数
// 定义要显示的数据,从0开始显示,一直显示到F
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
data <= 0;
end
else if(end_cnt_500ms && data == 15)begin // 当计数到最大值15,也就是F时,显示的数值重新归0
data <= 0;
end
else if(end_cnt_500ms)begin // 每500ms显示的数值加1
data <= data + 1;
end
end
// 定义位选信号,复位信号有效时,不显示,复位信号无效时,6个位选信号都显示。
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
sel_r <= 6'b111111;
end
else begin
sel_r <= 6'b000000;
end
end
assign sel = sel_r;
// 定义段选信号,当复位信号有效时,不显示,当复位信号无效时,8个段选信号显示当前数据的值。
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
seg_r <= 8'b0000_0000;
end
else begin
case (data) // 当要显示的数据位0-F的任意一值时,数码管显示对应的段落
4'd0: seg_r <= 8'hc0;
4'd1: seg_r <= 8'hf9;
4'd2: seg_r <= 8'ha4;
4'd3: seg_r <= 8'hb0;
4'd4: seg_r <= 8'h99;
4'd5: seg_r <= 8'h92;
4'd6: seg_r <= 8'h82;
4'd7: seg_r <= 8'hf8;
4'd8: seg_r <= 8'h80;
4'd9: seg_r <= 8'h90;
4'd10: seg_r <= 8'h88;
4'd11: seg_r <= 8'h83;
4'd12: seg_r <= 8'hc6;
4'd13: seg_r <= 8'ha1;
4'd14: seg_r <= 8'h86;
4'd15: seg_r <= 8'h8e;
default: seg_r <= 8'hc0;
endcase
end
end
assign seg = seg_r;
endmodule
接下来就是仿真模块的代码
`timescale 1ns/1ns
module seg_ctrl_tb (
);
reg clk;
reg rst_n;
wire[5:0] sel;
wire[7:0] seg;
// 模块例化
seg_ctrl u_seg_ctrl(
/* input */ .clk (clk ),
/* input */ .rst_n(rst_n),
/* output[5:0] */ .sel (sel ),
/* output[7:0] */ .seg (seg )
);
// 将控制模块的参数500ms重定义,位100周期
defparam u_seg_ctrl.TIME_500ms = 10'd100;
// 定义一个参数为20ns
parameter CLK_PERO = 20;
// 定义复位信号,开始为低电平,五个时钟周期之后一直为高电平
initial begin
rst_n = 1'b0;
#(CLK_PERO*5);
rst_n = 1'b1;
end
// 定义时钟信号,开始为高电平,每10ns翻转一次
initial clk = 1'b1;
always #(CLK_PERO/2) clk =~clk;
initial begin
// 执行1700个时钟周期之后,停止运行。
#(CLK_PERO*1700);
$stop;
end
endmodule
然后使用ModelSim工具进行仿真
段选信号的变化和共阴极数码管需要的段选信号变化一致{0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef,0xf7,0xfc,0xb9,0xde,0xf9,0xf1}说明代码仿真正确。
接下来就是上板验证
显示0
显示3
显示9
显示A
显示F
这里选择了几个数据提供参考,结果显示和想要的结果一致,说明本次实验成功完成。