动态数码管显示Verilog

目录

工程的基本原理:

1.动态显示

2.数码管结构

3.译码表

​ 4.结构图:

代码实现:

源代码: 

tb文件 :

仿真波形图: 


工程的基本原理:

1.动态显示

8位数码管在每(20/8)ms左右的间隔情况之下循环亮灭,同时在每个数码管单独显示每一位相对应的数字或者字母,因为循环亮灭的时间很短,这里利用人的视觉暂留效应,使得有8位数码管同时显示的错觉。更加通俗的说,类似于我们平时用的灯管,灯管两端接上50HZ交流电后,灯管以(1/50)s的周期循环亮灭,但实际上人眼所观察到的确是灯管一直在亮。

2.数码管结构

 如上图15.18所示,左边图(a)为单个数码管,其中共分为(a-h)8端,其中h段也就是图中的dp段,代表小数点。

右图(b)则分别显示共阴极(低电平有效)和共阳极的两类数码管。

     

以一位数码管显示数字‘1’为例,如果为共阳极数码管那么hgfedcba对应11111001,

若为共阴极数码管那么hgfedcba对应00000110.

3.译码表

如下图15.1,为8段的数码管显示所对应的16进制译码表

 4.结构图:

首先,利用分频器得到频率为50MHZ的方波,通过得到的方波信号来控制3位的计数器。得到的3位输出num作为三八译码器的输入从而来控制输出sel端,即代表哪一个数码管来亮。同时,输入了32位的数据disp_data,再通过上述的三位计数器控制,借助多路数据选择器来输出disp_tmp,从而选择所要显示的内容,以seg为输出。

代码实现:

源代码: 

module dongtaishumaguan(
         input clk,
		 input rst_n,
		 input [31:0] data,
		 output reg [7:0] sel,//位选
		 output reg [7:0] seg//段选
    );
	 reg [14:0] div_cnt;
	 always@(posedge clk or negedge rst_n)begin
	   if(!rst_n)
	     div_cnt<= 0;
		else if(div_cnt>=24999)
		  div_cnt<= 0;
		else
		  div_cnt<= div_cnt+1'b1;
	 end 
	 
	 reg clk_1;
	 always@(posedge clk or negedge rst_n)begin
	   if(!rst_n)
		  clk_1<= 0;
		else if(div_cnt==24999)
		  clk_1<= ~clk_1;
	end
	
	reg [2:0] cnt;
	always@(posedge clk_1 or negedge rst_n)begin
	  if(!rst_n)
	    cnt<= 0;
	  else
	    cnt<= cnt+1'b1;
	end
	
	always@(*)begin
	  case(cnt)
	   0:sel = 8'b0000_0001;
	   1:sel = 8'b0000_0010;
	   2:sel = 8'b0000_0100;
	   3:sel = 8'b0000_1000;
	   4:sel = 8'b0001_0000;
	   5:sel = 8'b0010_0000;
	   6:sel = 8'b0100_0000;
	   7:sel = 8'b1000_0000;
	  endcase
	end
	
	reg [3:0] data_1;
	always@(*)begin
	  case(cnt)
	    0:data_1 = data[31:28];
		1:data_1 = data[27:24];
		2:data_1 = data[23:20];
		3:data_1 = data[19:16];
		4:data_1 = data[15:12];
		5:data_1 = data[11:8];
		6:data_1 = data[7:4];
		7:data_1 = data[3:0];
	  endcase
	end
	
	always@(*)begin
	  case(data_1)
	     0:seg = 8'hc0;
		 1:seg = 8'hf9;
		 2:seg = 8'ha4;
		 3:seg = 8'hb0;
		 4:seg = 8'h99;
		 5:seg = 8'h92;
		 6:seg = 8'h82;
		 7:seg = 8'hf8;
		 8:seg = 8'h80;
		 9:seg = 8'h90;
	 4'ha:seg = 8'h88;
	 4'hb:seg = 8'h83;
	 4'hc:seg = 8'hc6;
	 4'hd:seg = 8'ha1;
	 4'he:seg = 8'h86;
	 4'hf:seg = 8'h8e;
	  endcase
	end
endmodule

tb文件 :

module tb_dongtaishumaguan;

	// Inputs
	reg clk;
	reg rst_n;
	reg [31:0] data;

	// Outputs
	wire [7:0] sel;
	wire [7:0] seg;

	// Instantiate the Unit Under Test (UUT)
	dongtaishumaguan uut (
		.clk(clk), 
		.rst_n(rst_n), 
		.data(data), 
		.sel(sel), 
		.seg(seg)
	);
always #10 clk=~clk;
	initial begin
		// Initialize Inputs 
		clk = 1;
		rst_n = 0;
		data = 0;//32'h0000_0000; 

		// Wait 100 ns for global reset to finish
		#201;
		rst_n = 1;
		
		#2000;
		data = 32'h87654321;
      
		#20000000;
		data = 32'habcdef12;
		// Add stimulus here

	end
      
endmodule

仿真波形图: 

这里我们可以右键输出或者输入信号,点击Radix可以去选择各种进制的显示,为了方便查错,这里对seg信号我们选择16进制显示 ,发现恰好与上面的译码表一一对应。

动态数码管显示通常是通过交替地刷新每个数码管来实现的。在Verilog中,可以使用时序模块和状态机来实现这一点。 首先,需要定义数码管的引脚和显示的数字。例如,如果使用四个共阳极数码管,则可以定义如下: ``` module display( input clk, // 时钟信号 output reg [3:0] anodes, // 数码管阳极引脚 output reg [7:0] segments // 数码管段码 ); reg [3:0] digits; // 要显示的数字 // 定义数字和段码的对应关系 parameter [9:0] digit_to_segment = { 8'h3F, // 0 8'h06, // 1 8'h5B, // 2 8'h4F, // 3 8'h66, // 4 8'h6D, // 5 8'h7D, // 6 8'h07, // 7 8'h7F, // 8 8'h6F // 9 }; // 状态机定义 parameter IDLE = 2'b00; parameter SHOW_DIGIT_1 = 2'b01; parameter SHOW_DIGIT_2 = 2'b10; reg [1:0] state = IDLE; // 时序模块 always @(posedge clk) begin case(state) IDLE: begin // 空闲状态,不显示任何数码管 anodes <= 4'b1111; segments <= 8'h00; if (digits != 4'b0000) begin // 如果有要显示的数字,进入显示状态 state <= SHOW_DIGIT_1; end end SHOW_DIGIT_1: begin // 显示第一个数码管 anodes <= 4'b1110; segments <= digit_to_segment[digits[3:0]]; state <= SHOW_DIGIT_2; end SHOW_DIGIT_2: begin // 显示第二个数码管 anodes <= 4'b1101; segments <= digit_to_segment[digits[7:4]]; state <= IDLE; end endcase end endmodule ``` 在时序模块中,状态机按顺序刷新每个数码管。每个状态下,将当前的数码管的阳极引脚设置为低电平,其他数码管的阳极引脚设置为高电平,然后根据要显示的数字设置该数码管的段码。在最后一个状态下,将状态机设置回空闲状态,等待下一次显示。 可以使用testbench模块来测试该数码管显示模块。例如,可以将要显示的数字设置为0x1234,并在时钟上升沿时调用display模块: ``` module testbench; reg clk; reg [3:0] digits; display display(clk, anodes, segments); initial begin clk = 0; digits = 4'b0000; end always #5 clk = ~clk; always @(posedge clk) begin digits <= digits + 1; end always @(posedge clk) begin display.digits <= digits; end endmodule ``` 这个测试程序将在每个时钟周期上升沿时递增要显示的数字,然后将该数字传递给display模块。显示器将交替地显示前两个数字和后两个数字。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值