当前位置:   article > 正文

FPGA实战------数码管(1)静态显示_数码管段选信号

数码管段选信号

FPGA实战数码管(1) 静态显示

led的花样点灯差不多了吧,接下来学习另一个基础的东西,数码管。



前言

数码管在FPGA开发板上占得位置不小,在工程开发中也必不可少,比如后边的温度传感器就会用数码管来显示温度。这里先不多介绍温度传感器,过一段时间就会发了。本篇文章先用数码管来做静态显示。也就是六个数码管显示一起显示一个数,一起变化。


一、数码管原理

Cyclone IV开发板中的数码管是共阳极所以数码管中需要给低电平,对应的led段才会亮
位选信号原理图如图所示,位选信号也是需要低电平有效。

数码管电路图
这张图是C4板子上数码管的电路结构,是不是看起来很麻烦,那就先来张简单的:
数码管
从这张图可以看出:数码管一共有八个小led管组成(DP就是小数点)。数码管就是通过控制每一段led的亮灭来控制显示的数字。

例如:当想让数码管显示零的时候,也就是A/B/C/D/E/F亮,G/DP灭。所以ZERO = 8'b1100_0000;
其中11就是指G/DP没有亮,其他的0都是点亮的led,就由这种亮灭情况,来显示相应的数字。

这里大家可以去想一想其他数字怎么写亮灭才能显示出来。

二、位选、段选

1.位选信号:

位选信号就是挑选六个数码管中的哪个来显示的信号。当选到这个数码管的时候,该数码管才会亮。
上边己经说过:

位选信号原理图如图所示,位选信号也是需要低电平有效。

咱这里让六个数码管一块亮一块灭,所以位选信号的六位同时变化就行。

//------------------------<位选信号>---------------------------

reg  [5:0] sel_r       ;//位选信号寄存

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        sel_r <= 6'b111_111 ;//复位时全灭
    end
    else if(end_cnt_1s)begin
        sel_r <= 6'b111_111 ;
    end
    else begin
        sel_r <= ~sel_r ;//全亮
    end
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

2.段选信号:

段选信号就是上边数码管那张图,一共八段led,怎么选择哪一段亮灭,就是段选信号该做的。

数码管中需要给低电平,对应的led段才会亮

下面的代码就是从0-F段选该怎么选择亮灭显示相应的数。

//-------------------------<段选信号参数>------------------------------
parameter       ZERO   = 8'b1100_0000 ,
                ONE    = 8'b1111_1001 ,
                TWO    = 8'b1010_0100 ,
                THREE  = 8'b1011_0000 ,
                FOUR   = 8'b1001_1001 ,
                FIVE   = 8'b1001_0010 ,
                SIX    = 8'b1000_0010 ,
                SEVEN  = 8'b1111_1000 ,
                EIGHT  = 8'b1000_0000 ,
                NINE   = 8'b1001_0000 ,
                NUM_A  = 8'b1000_1000 ,
                NUM_B  = 8'b1000_0011 ,
                NUM_C  = 8'b1100_0110 ,
                NUM_D  = 8'b1010_0001 ,
                NUM_E  = 8'b1000_0110 ,
                NUM_F  = 8'b1000_1110 ;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

下面就是用了一个case语句整理数码管显示的数字。
0-F 一共16位,所以这里用5位宽的cnt_num来控制数码管的16次数字显示。
然后用dig段选与相应的cnt_num的值对应,让数码管“知道”该在啥时候显示啥数字。

//------------------------<cnt_num>---------------------------

reg  [4:0] cnt_num     ;//数码管显示的数字

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt_num <= 0 ;
    end
    else if((cnt_num == 5'd15)&&(end_cnt_1s))begin
        cnt_num <= 0 ;//计满归零
    end
    else if(end_cnt_1s)begin
        cnt_num <= cnt_num + 1 ;//每秒加一
    end
    else begin
        cnt_num <= cnt_num ;
    end
end

//------------------------<段选信号>---------------------------

reg  [7:0] dig_r       ;//段选信号寄存

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        dig_r <= ZERO ;//复位归零
    end
    else begin
        case (cnt_num)
            5'd0  : dig_r <= ZERO   ; 
            5'd1  : dig_r <= ONE    ; 
            5'd2  : dig_r <= TWO    ; 
            5'd3  : dig_r <= THREE  ; 
            5'd4  : dig_r <= FOUR   ; 
            5'd5  : dig_r <= FIVE   ; 
            5'd6  : dig_r <= SIX    ; 
            5'd7  : dig_r <= SEVEN  ; 
            5'd8  : dig_r <= EIGHT  ; 
            5'd9  : dig_r <= NINE   ; 
            5'd10 : dig_r <= NUM_A  ; 
            5'd11 : dig_r <= NUM_B  ; 
            5'd12 : dig_r <= NUM_C  ; 
            5'd13 : dig_r <= NUM_D  ;
            5'd14 : dig_r <= NUM_E  ;
            5'd15 : dig_r <= NUM_F  ;   
            default: dig_r <= ZERO  ;
        endcase
    end
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

三、代码

1、静态显示

对了,这里sel和dig是因为在模块信号列表中给sel和dig定义为wire信号,为了用时序逻辑赋值,就分别定义了reg类型的信号。
如果嫌麻烦就在信号列表里定义为reg信号就行。这里给wire、reg类型还不太了解的同学解释一下。加油,迟早会明白的。

/**************************************功能介绍***********************************
Date	: 2023年9月30日 20:33:26
Author	: Yang.
Project : 数码管静态显示
Require : 数码管全显,从1-F轮流显示
*********************************************************************************/
module seg_dynamic (
    input         clk      ,
    input         rst_n    ,
    output [5:0]  sel      ,
    output [7:0]  dig      
);

parameter       ZERO   = 8'b1100_0000 ,
                ONE    = 8'b1111_1001 ,
                TWO    = 8'b1010_0100 ,
                THREE  = 8'b1011_0000 ,
                FOUR   = 8'b1001_1001 ,
                FIVE   = 8'b1001_0010 ,
                SIX    = 8'b1000_0010 ,
                SEVEN  = 8'b1111_1000 ,
                EIGHT  = 8'b1000_0000 ,
                NINE   = 8'b1001_0000 ,
                NUM_A  = 8'b1000_1000 ,
                NUM_B  = 8'b1000_0011 ,
                NUM_C  = 8'b1100_0110 ,
                NUM_D  = 8'b1010_0001 ,
                NUM_E  = 8'b1000_0110 ,
                NUM_F  = 8'b1000_1110 ;

//------------------------<计时器>---------------------------
parameter       MAX_1S = 26'd50_000_000 ;

reg   [25:0] cnt_1s      ;//1s计数器
wire         add_cnt_1s  ;
wire         end_cnt_1s  ;

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt_1s <= 0 ;
    end
    else if(add_cnt_1s)begin
        if(end_cnt_1s)begin
            cnt_1s <= 0 ;
        end
        else begin
            cnt_1s <= cnt_1s + 1 ;
        end
    end
end

assign add_cnt_1s = 1'b1 ;
assign end_cnt_1s = add_cnt_1s && cnt_1s == MAX_1S - 1 ;

//------------------------<位选信号>---------------------------

reg  [5:0] sel_r       ;//位选信号寄存

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        sel_r <= 6'b111_111 ;//复位时全灭
    end
    else if(end_cnt_1s)begin
        sel_r <= 6'b111_111 ;
    end
    else begin
        sel_r <= ~sel_r ;//全亮
    end
end

//------------------------<cnt_num>---------------------------

reg  [4:0] cnt_num     ;//数码管显示的数字

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt_num <= 0 ;
    end
    else if((cnt_num == 5'd15)&&(end_cnt_1s))begin
        cnt_num <= 0 ;//计满归零
    end
    else if(end_cnt_1s)begin
        cnt_num <= cnt_num + 1 ;//每秒加一
    end
    else begin
        cnt_num <= cnt_num ;
    end
end

//------------------------<段选信号>---------------------------

reg  [7:0] dig_r       ;//段选信号寄存

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        dig_r <= ZERO ;//复位归零
    end
    else begin
        case (cnt_num)
            5'd0  : dig_r <= ZERO   ; 
            5'd1  : dig_r <= ONE    ; 
            5'd2  : dig_r <= TWO    ; 
            5'd3  : dig_r <= THREE  ; 
            5'd4  : dig_r <= FOUR   ; 
            5'd5  : dig_r <= FIVE   ; 
            5'd6  : dig_r <= SIX    ; 
            5'd7  : dig_r <= SEVEN  ; 
            5'd8  : dig_r <= EIGHT  ; 
            5'd9  : dig_r <= NINE   ; 
            5'd10 : dig_r <= NUM_A  ; 
            5'd11 : dig_r <= NUM_B  ; 
            5'd12 : dig_r <= NUM_C  ; 
            5'd13 : dig_r <= NUM_D  ;
            5'd14 : dig_r <= NUM_E  ;
            5'd15 : dig_r <= NUM_F  ;   
            default: dig_r <= ZERO  ;
        endcase
    end
end

assign sel = sel_r ;
assign dig = dig_r ;



endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126

2.仿真代码

`timescale 1ns/1ns
    
module tb_seg_dynamic();

//激励信号定义 
    reg				tb_clk  	;
    reg				tb_rst_n	;

//输出信号定义	 
    wire	[5:0]		seg_sel	;
    wire	[7:0]		seg_dig ;

//时钟周期参数定义	
    parameter		CLOCK_CYCLE = 20;   

//参数重新定义
    defparam u_seg_dynamic.MAX_1S = 100;

//模块例化
    seg_dynamic  u_seg_dynamic( 
    /*input				    */.clk		(tb_clk    ),
    /*input				    */.rst_n	(tb_rst_n  ),
    /*output		[5:0]	*/.sel	    (seg_sel),//位选
    /*output		[7:0]	*/.dig	    (seg_dig) //段选
);	

//产生时钟
    initial 		tb_clk = 1'b0;
    always #(CLOCK_CYCLE/2) tb_clk = ~tb_clk;

//产生激励
    initial  begin 
        tb_rst_n = 1'b1;

        #(CLOCK_CYCLE*2);
        tb_rst_n = 1'b0;
        #(CLOCK_CYCLE*20);
        tb_rst_n = 1'b1;

        #(CLOCK_CYCLE*10000);
        $stop;

    end

endmodule 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

总结

1、仿真结果

仿真结果
从图中可以看出,数码管的位选信号同时变化且符合变化条件,段选信号也符合变化条件,合理且成功。

2、上板效果

FPGA数码管静态显示

数码管基础还是很简单的,接下来就是动态显示,然后就可以制作一个万能模版,以后有哪里用到,就直接套用模版。

代码工程都放进baidu网盘了,自行提取

链接:https://pan.baidu.com/s/1lQqqWZXfb3i6XHwkKf52zg
提取码:yang

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/518344
推荐阅读
相关标签
  

闽ICP备14008679号