一、静态数码管显示(共阳极)
RTL代码:
module seg_led_static(
input sys_clk,
input sys_rst,
output [5:0] sel,
output reg [7:0]seg_led
);
reg [24:0] cnt; //25M分频计数器 -> 0.5s
reg [3:0] num; // 显示控制
reg flag; // 增减标志位 1增
assign sel = 6'd0;
// 计时模块
always @(posedge sys_clk or negedge sys_rst) begin
if (!sys_rst)
cnt <= 25'd0;
else if (cnt == 25'd5)
cnt <= 25'd0;
else
cnt <= cnt + 1'd1;
end
// 显示控制模块
always @(posedge sys_clk or negedge sys_rst) begin
if (!sys_rst) begin
num <= 4'd0;
flag <= 1'd1;
end
else begin
if (flag == 1'd1) begin
if (num >= 4'hf)
flag <= 1'd0;
else begin
if (cnt == 25'd5)
num <= num + 1'h1;
else
num <= num;
end
end
else begin
if (num <= 4'h0)
flag <= 1'd1;
else begin
if (cnt == 25'd5)
num <= num - 1'h1;
else
num <= num;
end
end
end
end
// 显示模块
always @(posedge sys_clk or negedge sys_rst) begin
if (!sys_rst)
seg_led <= 8'b11111111;
else
case (num)
4'h0: seg_led <= 8'b1100_0000;
4'h1: seg_led <= 8'b1111_1001;
4'h2: seg_led <= 8'b1010_0100;
4'h3: seg_led <= 8'b1011_0000;
4'h4: seg_led <= 8'b1001_1001;
4'h5: seg_led <= 8'b1001_0010;
4'h6: seg_led <= 8'b1000_0010;
4'h7: seg_led <= 8'b1111_1000;
4'h8: seg_led <= 8'b1000_0000;
4'h9: seg_led <= 8'b1001_0000;
4'hA: seg_led <= 8'b1000_1000;
4'hB: seg_led <= 8'b1000_0011;
4'hC: seg_led <= 8'b1100_0110;
4'hD: seg_led <= 8'b1010_0001;
4'hE: seg_led <= 8'b1000_0110;
4'hF: seg_led <= 8'b1000_1110;
endcase
end
endmodule
Testbench:
`timescale 1ns/1ns
module seg_led_static_tb();
reg sys_clk;
reg sys_rst;
wire [5:0] sel;
wire [7:0] seg_led;
always #10 sys_clk = ~ sys_clk;
initial begin
sys_clk <= 1'd0;
sys_rst <= 1'd0;
# 40 sys_rst <= 1'd1;
end
seg_led_static u1(
sys_clk,
sys_rst,
sel,
seg_led
);
endmodule
过程中有这么一个顾虑的问题:
当flag = 1,num = 4'hf 时,当前时钟下flag<=0,num锁存。在下个时钟上升沿到来时,flag取得0值,num取得锁存值4'hf,cnt取得新计数值,如果cnt达到上限值时,num<=num-1,即在接下来一个时钟上升沿时,num = 4'he. 不存在因为flag变化时导致num持续保持的问题。
基于modelsim的时序分析:
二、动态数码管显示(共阳极)
设计思路:
RTL代码:
1、Top module
module seg_led_danymic_top(
input sys_clk,
input sys_rst,
output [5:0] sel,
output [7:0] seg_led
);
wire bcd_clk;
wire sel_flag;
wire [23:0] data;
wire [3:0] data0;
wire [3:0] data1;
wire [3:0] data2;
wire [3:0] data3;
wire [3:0] data4;
wire [3:0] data5;
wire en0;
wire en1;
wire en2;
wire en3;
wire en4;
wire en5;
assign data = {data5,data4,data3,data2,data1,data0};
assign en0 = 1'd1;
assign en1 = (data0 == 4'd9) ? 1'd1 : 1'd0;
assign en2 = ({data1, data0} == 8'h99) ? 1'd1 : 1'd0;
assign en3 = ({data2, data1, data0} == 12'h999) ? 1'd1 : 1'd0;
assign en4 = ({data3, data2, data1, data0} == 16'h9999) ? 1'd1 : 1'd0;
assign en5 = ({data4,data3,data2,data1,data0}==20'h99999) ? 1'd1 : 1'd0;
// 时钟模块
count cnt1(sys_clk, sys_rst, bcd_clk, sel_flag);
// 扫描显示模块
scan_display scan1(
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.sel_flag(sel_flag),
.data(data),
.sel(sel),
.seg_led(seg_led)
);
// 例化6个BCD计数器作为各个数码段的显示值
bcd_cnt u1(bcd_clk, sys_rst, en0, data0);
bcd_cnt u2(bcd_clk, sys_rst, en1, data1);
bcd_cnt u3(bcd_clk, sys_rst, en2, data2);
bcd_cnt u4(bcd_clk, sys_rst, en3, data3);
bcd_cnt u5(bcd_clk, sys_rst, en4, data4);
bcd_cnt u6(bcd_clk, sys_rst, en5, data5);
endmodule
2、计时模块
module count(
input sys_clk,
input sys_rst,
output reg bcd_clk,
output reg sel_flag
);
reg [22:0] cnt_seg;
reg [18:0] cnt_sel;
reg sel_clk;
// 5M分频计数器 -> 10Hz(0.1s)用于bcd计数器的时钟信号
always @(posedge sys_clk or negedge sys_rst) begin
if (!sys_rst) begin
cnt_seg <= 23'd0;
bcd_clk <= 1'd0;
end
else if (cnt_seg == 23'd2_499_999) begin
cnt_seg <= 23'd0;
bcd_clk <= ~ bcd_clk;
end
else begin
cnt_seg <= cnt_seg + 1'd1;
bcd_clk <= bcd_clk;
end
end
// 计时模块 6ms -> 用于位选
always @(posedge sys_clk or negedge sys_rst) begin
if (!sys_rst) begin
cnt_sel <= 19'd0;
sel_flag <= 1'd0;
end
else if (cnt_sel == 19'd29_999) begin
cnt_sel <= 19'd0;
sel_flag <= 1'd1;
end
else begin
cnt_sel <= cnt_sel + 1'd1;
sel_flag <= 1'd0;
end
end
endmodule
3、BCD计数器模块
module bcd_cnt(
input clk,
input rst,
input en,
output reg [3:0] data
);
always @(posedge clk or negedge rst) begin
if (!rst)
data <= 4'd0;
else if (en == 1'd1) begin
if (data == 4'd9)
data <= 4'd0;
else
data <= data + 1'd1;
end
else
data <= data;
end
endmodule
4、扫描显示模块
module scan_display(
input sys_clk,
input sys_rst,
input sel_flag,
input [23:0]data,
output reg [5:0] sel,
output reg [7:0] seg_led
);
reg [2:0] cnt_sel_flag;
reg [3:0] seg_reg; // 用于存放每位数码管的待翻译的数据
// 位选状态控制计数器
always @(posedge sys_clk or negedge sys_rst) begin
if (!sys_rst)
cnt_sel_flag <= 3'd0;
else if (sel_flag == 1'd1) begin
if (cnt_sel_flag == 3'd5)
cnt_sel_flag <= 3'd0;
else
cnt_sel_flag <= cnt_sel_flag + 1'd1;
end
else
cnt_sel_flag <= cnt_sel_flag;
end
// 位选控制器
always @(posedge sys_clk or negedge sys_rst) begin
if (!sys_rst)
sel <= 6'b111111;
else begin
case (cnt_sel_flag)
3'd0: begin
sel <= 6'b111110;
seg_reg <= data[3:0];
end
3'd1: begin
sel <= 6'b111101;
seg_reg <= data[7:4];
end
3'd2: begin
sel <= 6'b111011;
seg_reg <= data[11:8];
end
3'd3: begin
sel <= 6'b110111;
seg_reg <= data[15:12];
end
3'd4: begin
sel <= 6'b101111;
seg_reg <= data[19:16];
end
3'd5: begin
sel <= 6'b011111;
seg_reg <= data[23:20];
end
endcase
end
end
// 段显控制器
always @(posedge sys_clk or negedge sys_rst) begin
if (!sys_rst)
seg_led <= 8'b11111111;
else begin
case (seg_reg)
4'h0: seg_led <= 8'b1100_0000;
4'h1: seg_led <= 8'b1111_1001;
4'h2: seg_led <= 8'b1010_0100;
4'h3: seg_led <= 8'b1011_0000;
4'h4: seg_led <= 8'b1001_1001;
4'h5: seg_led <= 8'b1001_0010;
4'h6: seg_led <= 8'b1000_0010;
4'h7: seg_led <= 8'b1111_1000;
4'h8: seg_led <= 8'b1000_0000;
4'h9: seg_led <= 8'b1001_0000;
endcase
end
end
endmodule
Testbench:
`timescale 1ns/1ns
module seg_led_dynamic_tb();
reg sys_clk;
reg sys_rst;
wire [5:0] sel;
wire [7:0] seg_led;
always #10 sys_clk = ~ sys_clk;
initial begin
sys_clk <= 1'd0;
sys_rst <= 1'd0;
# 40 sys_rst <= 1'd1;
end
seg_led_danymic_top a1(
sys_clk,
sys_rst,
sel,
seg_led
);
endmodule
基于Modelsim的时序分析: