数码管所谓的动态扫描,就是利用人眼的视觉暂留特性,在人眼能分辨 的变化速度以外,快速分时的点亮各个数码管及其对应的段。因为分别点亮 所有数码管一次所用时间小于人眼的视觉暂留,因此,在人们眼里看来,这 些数码管都是同时持续点亮的,并不会有闪烁的感觉。
因为数码管属于低速设备,其正常的扫描频率为500~10KHz,扫描频率 太快,会导致系统功耗增加,显示效果变暗。扫描频率太慢,会有明显的闪 烁感。本实验通过调试观察,选择以1KHz作为扫描频率,实际显示效果非常 好。 因此本实验首先就需要产生一个1KHz的扫描时钟,该时钟由系统时钟分 频得到。
设计结构:


代码如下:
//TOP
moduleHEX8(
					clk,
					rst_n,
					En,
					disp_data,
					dig_sel,
					dig_seg
				);
				
	inputclk,rst_n,En;
	output[7:0]dig_sel;//weixuan
	output[6:0]dig_seg;//duanxuan
	
	input[31:0]disp_data;
	
	piderpider(
						.clk(clk),
						.rst_n(rst_n),
						.En(En),
						.p_clk(p_clk)
					);
	
//	key_detectkey_detect(
//									clk,
//									rst_n,
//									key_in
//								);
//	
//	key_ctrlkey_ctrl(
//							clk,
//							rst_n,
//							key_flag,
//							key_value,
//							data
//							);
	
	dig_driverdig_driver(
						.p_clk(p_clk),
						.rst_n(rst_n),
						.disp_data(disp_data),
						.dig_sel(dig_sel),
						.dig_seg(dig_seg),
						.En(En)
						);
endmodule
modulepider(
						clk,
						rst_n,
						En,
						p_clk
					);
					
	inputclk,rst_n;
	inputEn;
	
	outputregp_clk;
	
	reg[14:0]p_cnt;//25000-1
	//	分频计数器计数模块
	always@(posedgeclkornegedgerst_n)
	if(!rst_n)
		p_cnt<=15'd0;
	elseif(!En)
		p_cnt<=15'd0;
	elseif(p_cnt==24999)
		p_cnt<=15'd0;
	else
		p_cnt<=p_cnt+1'b1;
	//1K扫描时钟生成模块		
	always@(posedgeclkornegedgerst_n)
	if(!rst_n)
		p_clk<=1'b0;
	elseif(p_cnt==24999)
		p_clk<=~p_clk;
	else
		p_clk<=p_clk;
		
endmodule
	
moduledig_driver(
						p_clk,
						rst_n,
						disp_data,
						dig_sel,
						data_tmp,
						dig_seg,
						En
						);
	inputp_clk,rst_n,En;
	input[31:0]disp_data;
	
	output[7:0]dig_sel;
	outputreg[3:0]data_tmp;//chazhaobiaohuancun
	outputreg[6:0]dig_seg;
	
	reg[7:0]sel;
	//8位循环移位寄存器
	always@(posedgep_clkornegedgerst_n)
	if(!rst_n)
		sel<=8'b0000_0001;
	elseif(sel==8'b1000_0000)
		sel<=8'b0000_0001;
	else
		sel<=sel<<1;
	
	always@(*)
		case(dig_sel)
			8'b0000_0001:data_tmp=disp_data[3:0];
			8'b0000_0010:data_tmp=disp_data[7:4];
			8'b0000_0100:data_tmp=disp_data[11:8];
			8'b0000_1000:data_tmp=disp_data[15:12];
			8'b0001_0000:data_tmp=disp_data[19:16];
			8'b0010_0000:data_tmp=disp_data[23:20];
			8'b0100_0000:data_tmp=disp_data[27:24];
			8'b1000_0000:data_tmp=disp_data[31:28];
			default:data_tmp=4'b0000;
		endcase
		
	always@(*)
		case(data_tmp)
			4'h0:dig_seg=7'b1000000;
			4'h1:dig_seg=7'b1111001;
			4'h2:dig_seg=7'b0100100;
			4'h3:dig_seg=7'b0110000;
			4'h4:dig_seg=7'b0011001;
			4'h5:dig_seg=7'b0010010;
			4'h6:dig_seg=7'b0000010;
			4'h7:dig_seg=7'b1111000;
			4'h8:dig_seg=7'b0000000;
			4'h9:dig_seg=7'b0010000;
			4'ha:dig_seg=7'b0001000;
			4'hb:dig_seg=7'b0000011;
			4'hc:dig_seg=7'b1000110;
			4'hd:dig_seg=7'b0100001;
			4'he:dig_seg=7'b0000110;
			4'hf:dig_seg=7'b0001110;
		endcase
	assigndig_sel=(En)?sel:8'b0000_0000;
endmodule
	
`timescale1ns/1ns
`defineclk_period20
moduleHEX8_tb;
	regclk;	
	regrst_n;
	regEn;	
	
	reg[31:0]disp_data;
	
	wire[7:0]sel;//数码管位选
	wire[6:0]seg;//数码管段选
	
	HEX8HEX8(
		.clk(clk),
		.rst_n(rst_n),
		.En(En),
		.disp_data(disp_data),
		.dig_sel(sel),
		.dig_seg(seg)
	);
	
	initialclk=1;
	always#(`clk_period/2)clk=~clk;
	initialbegin
		rst_n=0;
		En=1;
		disp_data=32'h12345678;
		#(`clk_period*20);
		rst_n=1;
		#(`clk_period*20);
		#20000000;
		$stop;
	end
endmodule	
仿真:
