FPGA中八位數碼管驅動的設計和驗證

1.驅動原理

其中8段數碼管的動態顯示驅動如圖1所示,動態顯示的特點是將所有位數碼管的段選線 並聯在一起,由位選線控制是哪一位數碼管有效。選亮數碼管採用動態掃描顯示。所謂動態掃描顯示即輪流向各位數碼管送出字形碼和相應的位選,利用發光管的餘輝和人眼視覺暫留作用,使人的感覺好像各位數碼管同時都在顯示。

而在實際的使用中,由於FPGA出來的引腳資源寶貴,因此在FPGA外部用了兩個74HC595的芯片進行控制。其主要的作用就是將FPGA輸出的串行信號轉化爲數碼管需要的sel信號以及段信號(seg)。74HC595的芯片示意圖如下。

可以看出該芯片需要3個信號,分別爲DIO(串行數據),RCLK(移位寄存時鐘),SCLK(存儲時鐘),以下分別稱爲DS,SH_CP,ST_CP。

數碼管的驅動如下所示。即,在FPGA內部產生動態的掃描seg和sel。其中的En沒有在設計中使用,所以在代碼中去掉。

然後將產生的sel和seg如何送入到74HC595芯片?通過設計出其需要的端口及串行信號以及另外的兩個時鐘信號即可。模塊原理圖如下。

因此總共包括兩個部分:1,掃描信號驅動,2,模塊接口驅動。

 

2.RTL部分

(1).產生計數信號用於sel的翻轉

module divider(clk, rst_n,divider_cnt,clk_1k);
	input clk;
	input rst_n;

	output reg [31:0] divider_cnt;
	output reg clk_1k;
	
	parameter CNT_MAX = 28'd49_999;
	
	//對divider_cnt進行計數,計數到24999就歸零
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			divider_cnt <= 0;
		else if(divider_cnt == CNT_MAX )
			divider_cnt <= 0;
		else
				divider_cnt <= divider_cnt + 1'b1;
	//產生clk_1k的信號
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			clk_1k <= 0;
		else if(divider_cnt == CNT_MAX)
			clk_1k = ~clk_1k;
		else
			clk_1k <= clk_1k;
			
endmodule 

(2)sel信號的產生

module move_choice(clk,rst_n,divider_cnt,sel);
	input clk;
	input rst_n;
	input wire [31:0] divider_cnt;
	output reg [7:0] sel;
	parameter CNT_MAX = 32'd49_999;
	

	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			sel <= 8'b0000_0001;
		else if(divider_cnt == CNT_MAX)
		begin
			if(sel == 8'b1000_0000)
				sel <= 8'b0000_0001;
			else
				sel <= sel << 1;
		end
			else
				sel <= sel;
	
endmodule 

(3)根據sel信號分段讀取data信號

module pass_choice(clk,rst_n,sel,disp_data,data_tmp);
	input clk;
	input rst_n;
	input wire [7:0] sel;
	input wire [31:0] disp_data;
	
	output reg [4:0] data_tmp;

	always@(*)
			begin
			case(sel)
			8'b0000_0001: begin data_tmp <= disp_data[31:28]; end
			8'b0000_0010: begin data_tmp <= disp_data[27:24]; end
			8'b0000_0100: begin data_tmp <= disp_data[23:20]; end
			8'b0000_1000: begin data_tmp <= disp_data[19:16]; end
			8'b0001_0000: begin data_tmp <= disp_data[15:12]; end
			8'b0010_0000: begin data_tmp <= disp_data[11:8]; end
			8'b0100_0000: begin data_tmp <= disp_data[7:4]; end
			8'b1000_0000: begin data_tmp <= disp_data[3:0]; end
			default: begin data_tmp = 4'b0000;end
			endcase
			end			
endmodule 

(4)譯碼器

module translate(clk,rst_n,data_tmp,seg);
	input clk;
	input rst_n;
	input wire [4:0] data_tmp;
	output reg [7:0] seg;

	always@(*)
		begin
		case(data_tmp)
			4'b0000:seg[7:0] =8'b11000000;
			4'b0001:seg[7:0] =8'b11111001;
			4'b0010:seg[7:0] =8'b10100100;
			4'b0011:seg[7:0] =8'b10110000;
			4'b0100:seg[7:0] =8'b10011001;
			4'b0101:seg[7:0] =8'b10010010;
			4'b0110:seg[7:0] =8'b10000010;
			4'b0111:seg[7:0] =8'b11111000;
			4'b1000:seg[7:0] =8'b10000000;
			4'b1001:seg[7:0] =8'b10010000;
			default:seg[7:0] = 8'b01000_0000;
		endcase
		end
endmodule 

2.模塊驅動信號

(1)HC595

module HC595(
		clk,
		rst_n,
		sel,
		seg,
		ds,
		stcp,
		shcp,
		cnt,
		sclk,
		sclk_cnt
		);
	input clk;
	input rst_n;
	input [7:0] seg;
	input [7:0] sel;
	
	output reg ds;
	output reg stcp;
	output reg shcp;
	
	output reg [3:0]cnt;
	output wire sclk;
	output reg [6:0]sclk_cnt;
	
	parameter CNT_MAX2 = 2'd3;
	
	//對時鐘進行分頻
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			cnt <= 0;
		else if(1'b1)
			begin
				if(cnt >= CNT_MAX2)
					cnt <= 0;
				else
					cnt <= cnt + 1'b1;
			end
			else
				cnt <= 0;
				
	//形成了sclk這個分頻後的時鐘			
	assign sclk = (cnt == CNT_MAX2);
	
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			sclk_cnt <= 0;
		else if(sclk)
			begin
				if(sclk_cnt >= 15'd34)
					sclk_cnt <= 0;
				else
					sclk_cnt <= sclk_cnt + 1'b1;
			end
			else
				sclk_cnt <= sclk_cnt;
	//設置輸出的激勵順序以及製造時鐘
	
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			begin
				ds <= 0;
				shcp <= 0;
				stcp <= 0;
			end
		else
			begin
				case(sclk_cnt)
					15'd0:  begin  shcp <= 0; end
					15'd1:  begin  shcp <= 1; stcp <= 0; end
					15'd2:  begin  shcp <= 0; ds <= seg[7];end
					15'd3:  begin  shcp <= 1; end
					15'd4:  begin  shcp <= 0; ds <= seg[6];end
					15'd5:  begin  shcp <= 1; end
					15'd6:  begin  shcp <= 0; ds <= seg[5];end
					15'd7:  begin  shcp <= 1; end
					15'd8:  begin  shcp <= 0; ds <= seg[4];end
					15'd9:  begin  shcp <= 1; end
					15'd10: begin  shcp <= 0; ds <= seg[3];end
					15'd11: begin  shcp <= 1; end
					15'd12: begin shcp <= 0; ds <=  seg[2];end
					15'd13: begin shcp <= 1; end
					15'd14: begin shcp <= 0; ds <=  seg[1];end
					15'd15: begin shcp <= 1; end
					15'd16: begin shcp <= 0; ds <=  seg[0];end
					15'd17: begin shcp <= 1; end
					15'd18: begin shcp <= 0; ds <=  sel[7];end
					15'd19: begin shcp <= 1; end      
					15'd20: begin shcp <= 0; ds <=  sel[6];end
					15'd21: begin shcp <= 1; end      
					15'd22: begin shcp <= 0; ds <=  sel[5];end
					15'd23: begin shcp <= 1; end      
					15'd24: begin shcp <= 0; ds <=  sel[4];end
					15'd25: begin shcp <= 1; end      
					15'd26: begin shcp <= 0; ds <=  sel[3];end
					15'd27: begin shcp <= 1; end      
					15'd28: begin shcp <= 0; ds <=  sel[2];end
					15'd29: begin shcp <= 1; end      
					15'd30: begin shcp <= 0; ds <=  sel[1];end
					15'd31: begin shcp <= 1; end      
					15'd32: begin shcp <= 0; ds <=  sel[0];end
					15'd33: begin shcp <= 1; end
					15'd34: begin stcp <= 1; end
					default:;
				endcase
			end
endmodule 

3.頂層1

module dis_top(clk,rst_n,disp_data,ds,shcp,stcp);
	input clk;
	input rst_n;
	input wire [31:0] disp_data;
	wire [7:0] seg;
	wire [31:0] divider_cnt;
	wire [7:0] sel;
	wire clk_1k;
	wire [4:0] data_tmp;
	
	output wire ds;
	output wire shcp;
	output wire stcp;
	wire sclk;
	wire [6:0]sclk_cnt;
	wire [3:0] cnt;
	
	divider divider(
					.clk(clk),
					.rst_n(rst_n),
					.divider_cnt(divider_cnt),
					.clk_1k(clk_1k)
					);
	move_choice move_choice(
							.clk(clk),
							.rst_n(rst_n),
							.sel(sel),
							.divider_cnt(divider_cnt)
							);
	pass_choice pass_choice(
							.clk(clk),
							.rst_n(rst_n),
							.sel(sel),
							.disp_data(disp_data),
							.data_tmp(data_tmp)
							);	
	translate translate(
							.clk(clk),
							.rst_n(rst_n),
							.seg(seg),
							.data_tmp(data_tmp)
							);
		HC595 HC595_1(
				 .clk(clk),
				 .rst_n(rst_n),
				 .seg(seg),
				 .sel(sel),
				 .ds(ds),
				 .shcp(shcp),
				 .stcp(stcp),
				 .cnt(cnt),
				 .sclk(sclk),
				 .sclk_cnt(sclk_cnt)
				  );
							
endmodule 

4.通過讀取輸入信號得到硬件顯示的值

module hex_top(clk,rst_n,ds,shcp,stcp);
	input clk;
	input rst_n;

	
	output wire ds;
	output wire shcp;
	output wire stcp;
	wire [31:0] disp_data;
	
	dis_top dis_top(
					.clk(clk),
					.rst_n(rst_n),
					.ds(ds),
					.shcp(shcp),
					.stcp(stcp),
					.disp_data(disp_data)
					);
					
	hex_data	hex_data_inst (
		.probe (),
		.source (disp_data)
		);


endmodule 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章