FPGA学习系列:18. 数码管的设计

描述

设计背景:

    数码管是一种半导体发光器件,其基本单元是发光二极管。数码管在我们的许多设计中都又用到,数码管的显示原理简单和显示效果清晰在我们的工业中的到了广泛的应用。

    数码管的应用很广泛,涉及众多领域,我们就拿数显仪表这个领域来讲,数显仪表是数字式显示仪表的简称,显示器常用的有LED、LCD为显示元件。

 

设计原理:     

    本次的设计是设计一个数码管的显示模,其设计原理图如下:

    FPGA

    数码管显示分为的动态和静态显示,为了让人眼可以看清数码管的显示,我们一般驱动数码管的频率为1K - 10K 之间。

    顾名思义,七段数码管就是使用七段点亮的线段来拼成常见的数字和某些字母,这种显示方式我们在数字电路中非常容易见到。再加上右下角显示的小数点,实际上一个显示单元包括了8根信号线。根据电路设计的不同,这些信号线可能高有效也可能低有效。我们通过FPGA控制这些线段的亮灭,达到显示效果。

    对于多个数码管的显示模块,将每一个都连接到FPGA的管脚会耗用大量FPGA的管脚资源。因此我们同样引入一种类似矩阵键盘的扫描方式。任何时刻我们只使用8根信号点亮一个数码管,但是8个数码管是随着时钟步调交替点亮的,只要时钟的速度够快,我们观察到数码管就好像几个同时点亮一样。

    我们的开发板使用的动态显示来循环扫描显示。其原理图如下所示:

    FPGA

    如图所示,我们的开发板使用的是六位共阳极数码管,六个PNP型三极管分别作为六组数码管电源的输入开关,也就是我们常说的位选信号,PNP三极管为低电平导通,所以我们的位选信号低有效。在这里,为了节约FPGA的IO资源,我们把六个位选信号连接到了三八译码器74HC138D。

    从我们的板子硬件原理图上我们可以看清,我们的数码管是红阳极,就是是给一个低电平就是点亮数码管的一个段,那么8段全部给8b0000000那么数码管显示的就是8这个数字了,我们用的是循环显示,是通过sel引脚来选择哪一个数码管亮,也就是说我们的sel的三位为3b000的时候也就是选择第一个数码亮,3b001第二个数码管亮依次类推。

 

设计架构图:

    FPGA

设计代码:

顶层模块

0 module seg_x(clk,rst_n,sel,seg7); //顶层端口

1  input clk;     //输入

2  input rst_n;

3  output  [2:0] sel;  //输出

4  output [7:0] seg7;

5 

6  wire [23:0] num;

7 

8  num_in num_in(   //例化输入模块

9    .clk(clk),

10   .rst_n(rst_n),

11   .num(num)

12   );

13

14 seg seg(   //例化数码管模块

15   .clk(clk),

16   .rst_n(rst_n),

17   .sel(sel),

18   .seg7(seg7),

19   .data_in(num)

20   );

21 endmodule 

 

设计模块

0  module seg(clk,rst_n,sel,seg7,data_in); //端口定义

1  

2   input clk;

3   input rst_n;

4   input [23:0] data_in;   //输入6个灯的数据

5  

6   output reg [2:0] sel;  

7   output reg [7:0] seg7;

8  

9   parameter s0 = 3'b000;

10  parameter s1 = 3'b001;

11  parameter s2 = 3'b010;

12  parameter s3 = 3'b011;

13  parameter s4 = 3'b100;

14  parameter s5 = 3'b101;

15 

16  `define T1ms  50_000   //定义1k的计数值

17  //`define T1ms  5

18  reg [15:0] count;

19  wire flag;

20  always @ (posedge clk or negedge rst_n)

21   if(!rst_n)

22    begin

23     count <= 15'b0;

24    end

25   else

26    if(count == `T1ms - 1)  //计数到1MS

27     begin

28      count <= 15'b0;

29     end

30    else

31     begin

32      count <= count + 1'b1;

33     end

34 

35  assign flag =(count == `T1ms  - 1) ? 1'b1 : 1'b0; //标志位赋值

36 

37  reg [2:0] state; 

38  reg [3:0] num;

39  always @ (posedge clk or negedge rst_n)

40   if(!rst_n)

41    begin

42     sel <= 3'b0;

43     state <= 3'b0;

44     num <= 4'b0;

45    end

46   else

47    begin

48     case (state)

49      s0:begin

50        if(flag)

51         state <= s1;   //亮第一个灯,给24位数据的  4

52        else

53         begin

54          sel <= 3'b000;

55          num <= data_in[23:20];

56         end

57       end

58      s1:begin

59        if(flag)   ////亮第2个灯,给24位数据  4

60         state <= s2;

61        else

62         begin

63          sel <= 3'b001;

64          num <= data_in[19:16];

65         end

66       end

67      s2:begin

68        if(flag)   //亮第3个灯,给24位数据的  4

69         state <= s3;

70        else

71         begin

72          sel <= 3'b010;

73          num <= data_in[15:12];

74         end

75       end

76      s3:begin

77        if(flag) //亮第4个灯,给24位数据的4

78         state <= s4;

79        else

80         begin

81          sel <= 3'b011;

82          num <= data_in[11:8];

83         end

84       end

85      s4:begin

86        if(flag)  //亮第5个灯,给24位数据的4

87         state <= s5;

88        else

89         begin

90          sel <= 3'b100;

91          num <= data_in[7:4];

92         end

93       end

94      s5:begin

95        if(flag)  //亮第6个灯,给24位数据的4

96         state <= s0;

97        else

98         begin

99          sel <= 3'b101;

100         num <= data_in[3:0];

101        end

102      end

103     default:state <= s0;

104    endcase

105   end

106

107 always @ (*)   //数码管的译码模块

108   begin

109    case (num)

110     0:seg7 = 8'b1100_0000;

111     1:seg7 = 8'b1111_1001;

112     2:seg7 = 8'b1010_0100;

113     3:seg7 = 8'b1011_0000;

114     4:seg7 = 8'b1001_1001;

115     5:seg7 = 8'b1001_0010;

116     6:seg7 = 8'b1000_0010;

117     7:seg7 = 8'b1111_1000;

118     8:seg7 = 8'b1000_0000;

119     9:seg7 = 8'b1001_0000;

120     10:seg7 = 8'b1000_1000;

121     11:seg7 = 8'b1000_0011;

122     12:seg7 = 8'b1100_0110;

123     13:seg7 = 8'b1010_0001;

124     14:seg7 = 8'b1000_0110;

125     15:seg7 = 8'b1000_1110;

126     default:;

127    endcase

128   end

129 endmodule 

 

输入模块

0 module num_in(clk,rst_n,num);  //端口定义

1  input clk;

2  input rst_n;

3 

4 

5  output  [23:0] num;

6 

7  assign num = 24'h123456;  //给输入一个值,便于下次直接调用

8 

9 

10

11 endmodule 

 

测试模块

0 `timescale 1ns/1ps    //时间精度

1 

2 module seg_tb;

3  reg clk;   //端口定义

4  reg rst_n;

5 

6 

7  wire [2:0] sel;

8  wire [7:0] seg7;

9 

10 initial begin

11   clk = 1'b1;

12   rst_n = 1'b0;

13

14   #100.1 rst_n = 1'b1;

15

16   #200000 

17    $stop;

18

19  end

20 always #10 clk = ~clk;   //模拟时钟

21

22 seg_x seg_x_dut(  //例化顶层模块

23   .clk(clk),

24   .rst_n(rst_n),

25   .sel(sel),

26   .seg7(seg7)

27   );

28 endmodule 

 

仿真图:

    FPGA


    在仿真中我们可以看到我们的设计是正确的,第一个灯亮的是f9,也就是也就是对应数码管显示的是1,a4就是2,和我们的输入是正确的。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分