fpga学习之数码管显示

1、设计需求:
设计一个数码管驱动电路,是数码管能够显示任意六位数。

2、数码管原理分析:
现在的数码管基本都是八段式的,也就是说由八个发光二极管组成的。如图一所示,这是单个数码管的原理图
fpga学习之数码管显示_第1张图片
我们需要二极管显示数字,只需要控制二极管的亮灭就行。以共阳极数码管为例(给二极管低电平为点亮二极管),如图二所示显示数字与段选关系
fpga学习之数码管显示_第2张图片
数码管位选如图三所示,Y0~Y7表示8位数码管。1为数码管有效
fpga学习之数码管显示_第3张图片

代码功能实现部分:

module seg_6(
		Clk,
		Rst_n,
		En,
		disp_data,
		sel,
		seg
	);

	input Clk;	//50M
	input Rst_n;
	input En;	//数码管显示使能,1使能,0关闭
	
	input [23:0]disp_data;
	
	output [5:0] sel;//数码管位选(选择当前要显示的数码管)
	output reg [6:0] seg;//数码管段选(当前要显示的内容)
	
	reg [14:0]divider_cnt;//25000-1
	
	reg clk_1K;
	reg [5:0]sel_r;
	
	reg [3:0]data_tmp;//数据缓存

//	分频计数器计数模块
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		divider_cnt <= 15'd0;
	else if(!En)
		divider_cnt <= 15'd0;
	else if(divider_cnt == 24999)
		divider_cnt <= 15'd0;
	else
		divider_cnt <= divider_cnt + 1'b1;

//1K扫描时钟生成模块		
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		clk_1K <= 1'b0;
	else if(divider_cnt == 24999)
		clk_1K <= ~clk_1K;
	else
		clk_1K <= clk_1K;
		
//6位循环移位寄存器,实现数码管的位选
	always@(posedge clk_1K or negedge Rst_n)
	if(!Rst_n)
		sel_r <= 6'b00_0001;
	else if(sel_r == 6'b10_0000)
		sel_r <= 6'b00_0001;
	else
		sel_r <=  sel_r << 1;
		
	always@(*)
		case(sel_r)
			6'b00_0001:data_tmp = disp_data[3:0];
			6'b00_0010:data_tmp = disp_data[7:4];
			6'b00_0100:data_tmp = disp_data[11:8];
			6'b00_1000:data_tmp = disp_data[15:12];
			6'b01_0000:data_tmp = disp_data[19:16];
			6'b10_0000:data_tmp = disp_data[23:20];
			default:data_tmp = 4'b0000;
		endcase
		
	always@(*)
		case(data_tmp)
			4'h0:seg = 7'b1000000;
			4'h1:seg = 7'b1111001;
			4'h2:seg = 7'b0100100;
			4'h3:seg = 7'b0110000;
			4'h4:seg = 7'b0011001;
			4'h5:seg = 7'b0010010;
			4'h6:seg = 7'b0000010;
			4'h7:seg = 7'b1111000;
			4'h8:seg = 7'b0000000;
			4'h9:seg = 7'b0010000;
			4'ha:seg = 7'b0001000;
			4'hb:seg = 7'b0000011;
			4'hc:seg = 7'b1000110;
			4'hd:seg = 7'b0100001;
			4'he:seg = 7'b0000110;
			4'hf:seg = 7'b0001110;
		endcase
		
	assign sel = (En)?sel_r:6'b00_0000;

endmodule

代码仿真部分

`timescale 1ns/1ns

`define clk_period 20

module seg_6_tb;

	reg Clk;	//50M
	reg Rst_n;
	reg En;	//数码管显示使能,1使能,0关闭
	
	reg [23:0]disp_data;
	
	wire [5:0] sel;//数码管位选(选择当前要显示的数码管)
	wire [6:0] seg;//数码管段选(当前要显示的内容)
	
	seg_6 seg_6(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.En(En),
		.disp_data(disp_data),
		.sel(sel),
		.seg(seg)
	);
	
	initial Clk = 1;
	always#(`clk_period/2) Clk = ~Clk;
	
	initial begin
		Rst_n = 1'b0;
		En = 1;
		disp_data = 24'h123456;
		#(`clk_period*20);
		Rst_n = 1;
		#(`clk_period*20);
		#10000000;
		disp_data = 24'h876543;
		#10000000;
		disp_data = 24'h89abcd;
		#10000000;
		$stop;
	end

endmodule

仿真波形
fpga学习之数码管显示_第4张图片
大家在位选部分也可以使用状态机来实现,欢迎大家来学习讨论。

你可能感兴趣的:(fpga)