Altera EP4CE10 征途Pro开发板数码管显示原理(以实现模60计数器为例)

征途Pro开发板上使用的数码管型号为FJ3661BH,以及使用了两片74HC595芯片。

一. 硬件原理图

数码管为共阳极数码管,即段选为低电平点亮。

如图 所示开发板上搭载了两片74HC595芯片用于输出数码管驱动信号,其中我们接到了VCC防止数据清零,所以这两片74HC595芯片我们只用四个IO口控制即可。我们将两片74HC595进行级联,一片的Q7S输出端接到另一片的数据输入端DS,这样我们输入的14位串行输入数码管信号的前六位就会在 第二片就行输出。(注意:因为是移位寄存器,如果一次共输入14位数据,那么第一位输入的串行数据会在第二片74HC595芯片的Q5输出)。

74HC595芯片的使用:

  1. 首先把要传输的数据通过引脚DS输入到74HC595中。

  2. 产生SHCP时钟,将DS上的数据串行移入移位寄存器。

  3. 产生STCP时钟,将移位寄存器里的数据送入存储寄存器。

  4. 将引脚置为低电平,存储寄存器的数据会在Q0—Q7并行输出,同时并行输出的数据会被锁存起来。

二. Verilog代码设计实现595控制模块

1. 模块框图设计

输入段选信号,位选信号,系统时钟以及复位信号,输出ds,oe,stcp和shcp。

2. Verilog代码实现

module  hc595_ctrl
(
    input   wire            sys_clk     ,   
    input   wire            sys_rst_n   ,   
    input   wire    [5:0]   sel         ,   
    input   wire    [7:0]   seg         ,   
    
    output  reg             stcp        ,   
    output  reg             shcp        ,   
    output  reg             ds          ,   
    output  wire            oe              
);

reg     [1:0]   cnt_4   ; 
reg     [3:0]   cnt_bit ; 

wire    [13:0]  data    ; 

assign  data = {seg[0],seg[1],seg[2],seg[3],seg[4],seg[5],seg[6],seg[7],sel};

assign oe = ~sys_rst_n;

always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_4 <=  2'd0;
    else    if(cnt_4 == 2'd3)
        cnt_4 <=  2'd0;
    else
        cnt_4 <=  cnt_4 +   1'b1;
		
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_bit   <=  4'd0;
    else    if(cnt_4 == 2'd3 && cnt_bit == 4'd13)
        cnt_bit   <=  4'd0;
    else    if(cnt_4  ==  2'd3)
        cnt_bit   <=  cnt_bit   +   1'b1;
    else
        cnt_bit   <=  cnt_bit;
		
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        stcp    <=  1'b0;
    else    if(cnt_bit == 4'd13 && cnt_4 == 2'd3)
        stcp    <=  1'b1;
    else
        stcp    <=  1'b0;
		
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        shcp    <=  1'b0;
    else    if(cnt_4 >= 4'd2)
        shcp    <=  1'b1;
    else
        shcp    <=  1'b0;

always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        ds  <=  1'b0;
    else    if(cnt_4 == 2'd0)
        ds  <=  data[cnt_bit];
    else
        ds  <=  ds;
		
		
endmodule

三. 数码管显示实例

( 以实现模60计数器为例,计数时间间隔为1s)

1. 总体模块设计

        模60计数器的实现包括计数模块timer,数据显示模块display,595控制模块hc595_ctrl以及顶层模块counter60。模块display_595包含595控制模块以及数据显示模块。

整体RTL视图如下:

display_595模块如下:

 2.  计时模块timer:

实现数据从00-59的循环计数,时间间隔为1s。Verilog代码描述如下:

module timer
(
		input 	wire 			sys_clk 	,
		input 	wire			sys_rst_n	,
		
		output  reg     [7:0]   timer       ,  
        output  wire    [5:0]   point       ,  
        output  reg             seg_en      ,  
        output  wire            sign           
);


parameter CNT_MAX = 26'd24_999_999;


reg  [25:0] cnt_1s ;
reg 		clk1   ;

assign  point   =   6'b000_000;
assign  sign    =   1'b0	  ;

always@( posedge sys_clk or negedge sys_rst_n )
	if( sys_rst_n == 1'b0 )
		cnt_1s <= 26'd0 ;
	else if( cnt_1s ==	CNT_MAX )
		cnt_1s <= 26'd0 ;
	else 
		cnt_1s <= cnt_1s + 1'b1 ;

always@( posedge sys_clk or negedge sys_rst_n )
	if( sys_rst_n == 1'b0 )
		clk1 <= 1'b0 ;
	else if( cnt_1s == CNT_MAX )
		clk1 <= ~ clk1 ;
	else
		clk1 <= clk1 ;
		
always@( posedge clk1 or negedge sys_rst_n )
	if( sys_rst_n == 1'b0 )
		timer <= 8'b0000_0000;
	else if( timer[7:4] == 4'd5 && timer[3:0] == 4'd9 )
		timer <= 8'd0000_0000;
	else if( timer[3:0] == 4'd9 )
		begin
			timer[7:4] <= timer[7:4] + 1'b1 ;
			timer[3:0] <= 4'd0 ;
		end
	else 
		timer[3:0] <= timer[3:0] + 1'b1 ;
		
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        seg_en  <=  1'b0;
    else
        seg_en  <=  1'b1;
		
endmodule

3. 数据显示模块display

  六位八段数码管扫描显示。由于数码管的余辉效应以及人眼的视觉残留,动态扫描的方式能实现数码管的动态显示。Verilog代码如下:

module display
(

	input   wire            sys_clk     , 
	input   wire            sys_rst_n   , 
	input   wire    [7:0]   timer       ,
	input   wire    [5:0]   point       , 
	input   wire            seg_en      , 
	input   wire            sign        , 
	
	output  reg     [5:0]   sel         , 
    output  reg     [7:0]   seg           
	
);

parameter 	CNT_MAX = 16'd49_999;

reg 	[15:0]	cnt_1ms		;
reg 			flag_1ms	;
reg 	[2:0]	cnt_sel 	;
reg 	[3:0]	data  		;


always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1ms <=  16'd0;
    else    if(cnt_1ms == CNT_MAX)
        cnt_1ms <=  16'd0;
    else
        cnt_1ms <=  cnt_1ms + 1'b1;
		
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        flag_1ms    <=  1'b0;
    else    if(cnt_1ms == CNT_MAX )
        flag_1ms    <=  1'b1;
    else
        flag_1ms    <=  1'b0;
		
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_sel <=  3'd0;
    else    if((cnt_sel == 3'd5) && (flag_1ms == 1'b1))
        cnt_sel <=  3'd0;
    else    if(flag_1ms == 1'b1)
        cnt_sel <=  cnt_sel + 1'b1;
    else
        cnt_sel <=  cnt_sel;

always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        sel <=  6'b000_000;
    else    if((cnt_sel == 3'd0) && (flag_1ms == 1'b1))
        sel <=  6'b000_001;
    else    if(flag_1ms == 1'b1)
        sel <=  sel << 1;
    else
        sel <=  sel;
		
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)	
		data <= 4'b0 ;
	else if( seg_en == 1'b1 && flag_1ms == 1'b1 )
		case( cnt_sel )
			3'd0:	data 	<= timer[3:0] 	;
			3'd1:	data 	<= timer[7:4] 	;
			3'd2:   data	<= 4'd11	   	;
            3'd3:   data	<= 4'd11		;
	        3'd4:   data	<= 4'd11		;
            3'd5:   data	<= 4'd11		;
			default:data	<= 4'b0			;
		endcase
	else
		data <= data ;
		
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
		seg <= 8'b1111_1111 ;
	else
		case(data)
			4'd0   : seg <= 8'b1100_0000 ;
			4'd1   : seg <= 8'b1111_1001 ;
			4'd2   : seg <= 8'b1010_0100 ;
			4'd3   : seg <= 8'b1011_0000 ;
			4'd4   : seg <= 8'b1001_1001 ;
			4'd5   : seg <= 8'b1001_0010 ;
			4'd6   : seg <= 8'b1000_0010 ;
		    4'd7   : seg <= 8'b1111_1000 ;
		    4'd8   : seg <= 8'b1000_0000 ;
		    4'd9   : seg <= 8'b1001_0000 ;
			4'd10  : seg <= 8'b1111_1111 ;
			4'd11  : seg <= 8'b1111_1111 ;
			default:seg <= 8'b1100_0000  ;
		endcase
		
	
endmodule

4. display_595模块

  该模块中实现对display模块以及hc595_ctrl模块的例化。

module display_595
(
	input   wire            sys_clk     ,
	input   wire            sys_rst_n   ,
	input   wire    [7:0]   timer       ,
	input   wire    [5:0]   point       ,
	input   wire            seg_en      ,
	input   wire            sign        ,
	
	output  wire            stcp        ,
    output  wire            shcp        ,
    output  wire            ds          ,
	output  wire            oe           

); 

wire	[7:0] seg	;
wire	[5:0] sel	;

display display_inst
(
	
	.sys_clk     	(sys_clk     	), 
	.sys_rst_n   	(sys_rst_n   	), 
	.timer       	(timer       	),
	.point       	(point       	), 
	.seg_en      	(seg_en      	), 
	.sign        	(sign        	), 
						
	.sel         	(sel         	), 
    .seg         	(seg         	)  
	
);

hc595_ctrl hc595_ctrl_inst
(
    .sys_clk     	(sys_clk     	),   
    .sys_rst_n   	(sys_rst_n   	),   
    .sel         	(sel         	),   
    .seg         	(seg         	),   
					
    .stcp        	(stcp        	),   
    .shcp        	(shcp        	),   
    .ds          	(ds          	),   
    .oe          	(oe          	)    
);

endmodule

5. 顶层模块counter60

  该模块中实现对所有底层模块的例化。

module counter60
(
	
		input   wire            sys_clk     ,
		input   wire            sys_rst_n   ,		
		
		output  wire            stcp        ,
        output  wire            shcp        ,
        output  wire            ds          ,
		output  wire            oe           
);    

wire 	[7:0] timer		;
wire	[5:0] point		;
wire	      seg_en	;
wire		  sign		;

timer timer_inst
(

		.sys_clk 		(sys_clk 		),
		.sys_rst_n		(sys_rst_n		),
			
		.timer      	(timer      	),  
        .point      	(point      	),  
        .seg_en     	(seg_en     	),  
        .sign       	(sign       	)    

);

display_595 display_595_inst
(
	.sys_clk     		(sys_clk     	),
	.sys_rst_n   		(sys_rst_n   	),
	.timer       		(timer       	),
	.point       		(point       	),
	.seg_en      		(seg_en      	),
	.sign        		(sign        	),
					
	.stcp        		(stcp        	),
    .shcp        		(shcp        	),
    .ds          		(ds          	),
	.oe          		(oe          	) 

);

endmodule

6. counter60模块对应的开发板引脚配置

7. 程序烧录结果

开发板六位数码管最后两位显示数据00-59的循环计数,时间间隔为1s。

  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是既白呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值