基于FPGA的IO复用扫描模块

一、静态数码管显示(共阳极)

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的时序分析:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值