FPGA学习笔记(五)------动态数码管

时钟分频
激励文件

顶层模块

module top_seg_led(
    //global clock
    input            sys_clk  ,       // 全局时钟信号
    input            sys_rst_n,       // 复位信号(低有效)

    //seg_led interface
    output    [5:0]  seg_sel  ,       // 数码管位选信号
    output    [7:0]  seg_led          // 数码管段选信号
);

//wire define
wire    [19:0]  data;                 // 数码管显示的数值
wire    [ 5:0]  point;                // 数码管小数点的位置
wire            en;                   // 数码管显示使能信号
wire            sign;                 // 数码管显示数据的符号位

//*****************************************************
//**                    main code
//*****************************************************

//计数器模块,产生数码管需要显示的数据
count u_count(
    .clk           (sys_clk  ),       // 时钟信号
    .rst_n         (sys_rst_n),       // 复位信号

    .data          (data     ),       // 6位数码管要显示的数值
    .point         (point    ),       // 小数点具体显示的位置,高电平有效
    .en            (en       ),       // 数码管使能信号
    .sign          (sign     )        // 符号位
);

//数码管动态显示模块
seg_led u_seg_led(
    .clk           (sys_clk  ),       // 时钟信号
    .rst_n         (sys_rst_n),       // 复位信号

    .data          (data     ),       // 显示的数值
    .point         (point    ),       // 小数点具体显示的位置,高电平有效
    .en            (en       ),       // 数码管使能信号
    .sign          (sign     ),       // 符号位,高电平显示负号(-)
    
    .seg_sel       (seg_sel  ),       // 位选
    .seg_led       (seg_led  )        // 段选
);

endmodule

动态显示模块

module seg_led(
	//input
	input clk,
	input rst_n,
	
	input  [19:0]	data,		//数码管显示数据99_9999 20位二进制表示
	input  [5:0]	point,	//6个小数点
	input  			en,		//数码管使能信号
	input 			sign, 	//符号位
	
	//output
	output reg [5:0] seg_sel,  //数码管片选信号
	output reg [7:0] seg_led	//段选
);

//parameter define	模块内声明局部参数常数
localparam CLK_DIVIDE = 4'd10;		//时钟分频系数10
localparam MAX_NUM	 = 13'd5000;	//5MHz晶振5000*200ns=1ms

//reg define
reg  [3:0]  	 clk_cnt ; 		// 时钟分频计数器
reg  			    dri_clk ; 		// 数码管的驱动时钟,5MHz
reg  [23:0]     num ; 			// 24位bcd码寄存器
reg  [12:0]     counter ; 		// 数码管驱动时钟计数器
reg 		  	    flag ; 			// 标志信号(标志着counter计数达1ms)
reg  [2:0]      cnt_sel ; 		// 数码管位选计数器
reg  [3:0]      num_disp ; 	// 当前数码管显示的数据
reg 				 dot_disp ;		// 当前数码管显示的小数点

//wire define
wire [3:0] data0 ; // 个位数
wire [3:0] data1 ; // 十位数
wire [3:0] data2 ; // 百位数
wire [3:0] data3 ; // 千位数
wire [3:0] data4 ; // 万位数
wire [3:0] data5 ; // 十万位数

//**************************************
//**				 main code
//**************************************

//提取显示数值所对应的十进制数的各个位
//assign 连续赋值语句(总是处于激活状态)
assign data0 = data % 4'd10; 				   // 个位数
assign data1 = data / 4'd10 % 4'd10 ;	   // 十位数
assign data2 = data / 7'd100 % 4'd10 ;    // 百位数
assign data3 = data / 10'd1000 % 4'd10 ;  // 千位数
assign data4 = data / 14'd10_000 % 4'd10; // 万位数
assign data5 = data / 17'd100_000; 		   // 十万位数

//对系统时钟10分频,得到的频率为5MHz的数码管驱动时钟dri_clk
always @(posedge clk or negedge rst_n) begin
   if(!rst_n) begin
       clk_cnt <= 4'd0;
       dri_clk <= 1'b1;
   end
   else if(clk_cnt == CLK_DIVIDE/2 - 1'd1) begin
       clk_cnt <= 4'd0;
       dri_clk <= ~dri_clk;
   end
   else begin
       clk_cnt <= clk_cnt + 1'b1;
       dri_clk <= dri_clk;
   end
end

//将20位2进制转化为8421码
//dri_clk 数码管的驱动时钟
//cnt_sel数码管位选计数器
always @ (posedge dri_clk or negedge rst_n)begin
	if(!rst_n)
		num <= 24'b0;
	else if(data5 || point[5])begin	//显示6位数据
			num[23:20] <= data5;
			num[19:16] <= data4;
			num[15:12] <= data3;
			num[11:8]  <= data2;
			num[7:4]   <= data1;
			num[3:0]   <= data0;
		 //num[23:0] <= {data5,data4,data3,data2,data1,data0};
	end
	else if(data4 || point[4])begin	//显示5位数据
		num[19:0] <= {data4,data3,data2,data1,data0};
		if(sign)
			num[23:20] <= 4'd11;   //6位显示‘-’号
		else
			num[23:20] <= 4'd10;   //6位不显示
	end
	else if(data3 || point[3])begin	//显示4位数据
		num[15:0] <= {data3,data2,data1,data0};
		num[23:20] <= 4'd10;   //6位不显示
		if(sign)
			num[19:16] <= 4'd11;   //5位显示‘-’号
		else
			num[19:16] <= 4'd10;   //5位不显示
	end
	else if(data2 || point[2])begin	//显示3位数据
		num[11:0] <= {data2,data1,data0};
		num[23:20] <= 4'd10;   //6位不显示
		num[19:16] <= 4'd10;   //5位不显示
		if(sign)
			num[15:12] <= 4'd11;   //4位显示‘-’号
		else
			num[15:12] <= 4'd10;   //4位不显示
	end
	else if(data1 || point[1])begin	//显示2位数据
		num[7:0] <= {data1,data0};
		num[23:20] <= 4'd10;   //6位不显示
		num[19:16] <= 4'd10;   //5位不显示
		num[15:12] <= 4'd10;   //4位不显示
		if(sign)
			num[11:8] <= 4'd11;   //3位显示‘-’号
		else
			num[11:8] <= 4'd10;   //3位不显示
	end
	else if(data0 || point[0])begin	//显示1位数据
		num[3:0] <= data0;
		num[23:20] <= 4'd10;   //6位不显示
		num[19:16] <= 4'd10;   //5位不显示
		num[15:12] <= 4'd10;   //4位不显示
		num[11:8]  <= 4'd10;   //3位不显示
		if(sign)
			num[7:4] <= 4'd11;   //2位显示‘-’号
		else
			num[7:4] <= 4'd10;   //2位不显示
	end	
end


//5MHz计时1ms,切换片选
always @ (posedge dri_clk or negedge rst_n)begin
	if(!rst_n)begin
		counter <= 13'b0;
		flag	  <= 1'b0;
 	end
	else if(counter < MAX_NUM - 1'b1)begin
		counter <= counter + 1'b1;
		flag	  <= 1'b0;
	end
	else begin
		counter <= 13'b0;
		flag	  <= 1'b1;
	end
end

//cnt_sel [2:0] 数码管位选计数器 高有效
//计数0-5 1ms 选择当前显示的数码管
always @ (posedge dri_clk or negedge rst_n)begin 
	if(!rst_n)begin 
		cnt_sel = 3'b0;  //复位全灭
	end
	else if(flag)begin
		if(cnt_sel < 3'd5)
			cnt_sel = cnt_sel + 1'b1;
		else
			cnt_sel = 3'b0;
	end
	else
		cnt_sel = cnt_sel; 
end

//控制数码管位选信号 低电平有效
always @ (posedge dri_clk or negedge rst_n)begin 
	if(!rst_n)begin 
		seg_sel <= 6'b111_111;		//6'd63
	end
	else begin
		if(en)begin   //en=1
			case(cnt_sel)
				3'd0: begin
					seg_sel  <= 6'b111_110;//显示数码管第1位
					num_disp <= num[3:0];
					dot_disp <= ~point[0];
				end
				3'd1: begin
					seg_sel  <= 6'b111_101;//显示数码管第2位
					num_disp <= num[7:4];
					dot_disp <= ~point[1];
				end				
				3'd2: begin
					seg_sel  <= 6'b111_011;//显示数码管第3位
					num_disp <= num[11:8];
					dot_disp <= ~point[2];
				end				
				3'd3: begin
					seg_sel  <= 6'b110_111;//显示数码管第4位
					num_disp <= num[15:12];
					dot_disp <= ~point[3];
				end				
				3'd4: begin
					seg_sel  <= 6'b101_111;//显示数码管第5位
					num_disp <= num[19:16];
					dot_disp <= ~point[4];
				end				
				3'd5: begin
					seg_sel  <= 6'b011_111;//显示数码管第6位
					num_disp <= num[23:20];
					dot_disp <= ~point[5];
				end	
				default: begin
					seg_sel  <= 6'b111_111;
				end				
			endcase
		end	
		else begin		//en=0
			seg_sel <= 6'b111111; 
			num_disp <= 4'b0;
			dot_disp <= 1'b1;		
		end
	end
end

//控制数码管段选信号
always @ (posedge dri_clk or negedge rst_n) begin
	if (!rst_n)
		seg_led <= 8'hc0;
	else begin
		case (num_disp)
			4'd0 : seg_led <= {dot_disp,7'b1000000}; //显示数字 0
			4'd1 : seg_led <= {dot_disp,7'b1111001}; //显示数字 1
			4'd2 : seg_led <= {dot_disp,7'b0100100}; //显示数字 2
			4'd3 : seg_led <= {dot_disp,7'b0110000}; //显示数字 3
			4'd4 : seg_led <= {dot_disp,7'b0011001}; //显示数字 4
			4'd5 : seg_led <= {dot_disp,7'b0010010}; //显示数字 5
			4'd6 : seg_led <= {dot_disp,7'b0000010}; //显示数字 6
			4'd7 : seg_led <= {dot_disp,7'b1111000}; //显示数字 7
			4'd8 : seg_led <= {dot_disp,7'b0000000}; //显示数字 8
			4'd9 : seg_led <= {dot_disp,7'b0010000}; //显示数字 9
			4'd10: seg_led <= 8'b11111111; //不显示任何字符
			4'd11: seg_led <= 8'b10111111; //显示负号(-)
			default:
				seg_led <= {dot_disp,7'b1000000};
		endcase
	end
end
endmodule

计时模块

module count(
	//input
	input	clk,
	input	rst_n,
	
	//output
	//reg 寄存器数据类型,声明能保存数值的变量
	output reg [19:0]	data,		//数码管显示数据99_9999 20位二进制表示
	output reg [5:0]	point,	//6个小数点
	output reg 				en,	//数码管使能信号
	output reg				sign  //符号位
);

//parameter define	模块内声明常数
//5000_000*20ns=100ms
parameter	MAX_NUM=23'd5000_000;    //计数器最大值

//reg	define	寄存器数据类型声明
reg	[22:0]	counter;				//计数器 23位 100ms
reg		time_flag;					//定时标志信号

//**************************************
//**				 main code
//**************************************
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin		//如果复位,执行
		counter	<= 23'b0;	//计数器清零
		time_flag <= 1'b0;	//定时标志清零
	end
	else if(counter < MAX_NUM-1'b1)begin		//定时未到,且counter(max)=MAX_NUM-1
		counter <= counter + 1'b1;      //counter++
		time_flag <= 1'b0;
	end
	else	begin    						 //counter < MAX_NUM-1'b1
		time_flag <= 1'b1;				//定时标志清零
		counter	<= 23'b0;				//计数器清零
	end
end

//数码管显示的数据,0-999_999
always @ (posedge clk or negedge rst_n)begin
	if(!rst_n)begin   			//复位初始化
		data  <= 20'b0;
		point <= 6'b0;
		sign  <= 1'b0;
		en		<= 1'b0;
	end
	else begin
		point <= 6'b0;				//不显示小数点
		sign  <= 1'b0;				//不显示符号
		en		<= 1'b1;				//打开片选
		if(time_flag)begin		//100ms 累加一次
			if(data < 20'd999_999)
				data <= data + 1'b1;  //data++
			else
			data <= 20'b0;	
		end
	end
end
endmodule
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值