当前位置:   article > 正文

FPGA基本实验之数码管的静态显示_fpga手册的数码管

fpga手册的数码管

此实验基于FPGA征途pro开发板实现,

数码管的基本知识

数码管简介

数码管是一种半导体发光器件,其基本单元是发光二极管。数码管按段数一般分为七 段数码管和八段数码管,八段数码管比七段数码管多一个发光二极管(多一个小数点显 示)。当然也还有一些其他类型的数码管如“N”形管、“米”字管以及工业科研领域用 的 16 段管、24 段管等,本次实验我们采用8段数码管。

八段数码管知识

        由上图可以看出,八段数码管是一个八字型数码管,分为八段:a、b、c、d、e、 f、g、dp,其中 dp 为小数点,每一段即为一个发光二极管,这样的八段我们称之为段选信 号。数码管常用的有 10 根管脚,每一段有一根管脚,另外两根管脚为一个数码管的公共 端,两根互相连接。

        数码管分为共阳极数码管和共阴极数码管。共阳极数码管就是把发光二极管的正极连 接在一起作为一个引脚,负极分开。相反的,共阴极数码管就是把发光二极管的阴极连接 在一起作为一个引脚,正极分开。这两者的区别在于,公共端是连接到地还是高电平,对 于共阳极数码管需要给对应段低电平才会使其点亮,而对于共阴极数码管则需要给其高电 平才会点亮。本次实验使用的是共阳极数码管,也就是说给对应段低电平才会被点亮。给 不同的段点亮可显示 0~f 的值,

下图是提供的数码管编码译码表:

 二进制段码右边为高位左边为低位。我们只要点亮相应的段码,就 能显示我们需要显示的内容。

        段式数码管工作方式有两种:静态显示和动态显示。静态显示的特点是每个数码管的 段选必须接一个 8 位数据线来显示字形,显示字形可一直保持,直到送入新字形码为止。 那么如果点亮 6 个码管是不是需要 48 位数据线去分别控制每一个码管的段选?当然这种方 法也可以,但是其占用的 I/O 口较多,因此硬件电路比较复杂,成本较高,很少使用。

        为节省资源我们采用如图所示的数码管的连接方式:

 由上图可以看到,我们将六个数码管的段选信号连接在一起,而位选(sel)独立控 制,这样六个数码管接在一起就少了 8×5 个 I/O 口。这里对位选信号特别说明一下:由上 图可以看到每一个数码管都有一个位选信号,而这个位选信号就控制着数码管的亮灭。这 样我们就可以通过位选信号去控制数码管亮,而在同一时刻,位选选通的数码管上显示的 字形是一样的,因为我们将 6 个数码管相对应的段选连在了一起,数码管的显示自然就相 同了,数码管的这种显示方式即为静态显示。

为了进一步减少板载I/O口资源我们采用74HC595芯片

74HC595芯片介绍

        74HC595 是一个 8 位串行输入、并行输出的位移缓存器。其内部具有 8 位移位寄存器 和一个存储器,具有三态输出功能。

通过查找数据手册我们得到74HC595芯片的功能表:

总结一下74HC595芯片的用法

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

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

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

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

 接下来正式开始实验的设计验证和实现:

我们可以设计一个这样的 6 位数码管静态显示:控制六位 数码管让其以 000000、111111、222222 一直到 FFFFFF 循环显示。每个字符显示 0.5s 后变 化。

程序设计

根据实验要求绘制系统框架:

根据绘制的系统框架可以将这个程序初步设计为三部分:

第一部分:实现seg_static功能,

第二部分:实现芯片hc595_ctrl控制功能;

第三部分:实现顶层设计模块的综合。

第一部分:seg_static数码管显示模块

 

首先介绍一下程序中的几个变量所代表的含义:

cnt:根据实验要求需要等待 0.5s 后显示的字符才发生变化。所以我们需要一个 0.5s 的循环计数器。我们输入的时钟频率是 50MHz,一个时钟周期的时间就是 (1/50MHz)s , 也 就 是 20ns 。 所 以 我 们 计 数 器 从 0 计 到 24_999_999 即 为 0.5s (25000000*20ns)的时间。计到 0.5s 后让其归 0 开始下一个 0.5s 的计数。

cnt_flag:当计数器计到 0.5s 时,我们拉高一个标志信号,让这个标志信号去控制数 码管字符的跳转。 num:每个数码管显示的字符,初始显示为 0,六个就是 000000。当检测到跳转的标 志信号为高时,让各个数码管显示的字符加 1。当加到 4’hF 时让其归 0 重新相加以此循 环。

sel:数码管的位选信号。我们是显示六个数码管,直接给其全点亮即可。根据原理图 可知我们需要给其位选信号高电平数码管才会被点亮,所以给对应的位数高电平对应的数 码管就会点亮,一位表示一个数码管。这里我们全部点亮即可。

seg:数码管的段选信号,给其相应段码点亮显示 num 里的值即可。

  1. module seg_static
  2. #(
  3. parameter CNT_MAX = 25'd24_999_999
  4. )
  5. (
  6. input wire sys_clk,
  7. input wire sys_rst_n,
  8. output reg [5:0] sel ,
  9. output reg [7:0] seg
  10. );
  11. reg [24:0] cnt;
  12. reg [3:0] data;
  13. reg cnt_flag;
  14. always@(posedge sys_clk or negedge sys_rst_n)
  15. if(sys_rst_n == 1'b0)
  16. cnt <= 25'd0;
  17. else if(cnt == CNT_MAX)
  18. cnt <= 25'd0;
  19. else
  20. cnt <= cnt + 1'b1;
  21. always@(posedge sys_clk or negedge sys_rst_n)
  22. if(sys_rst_n == 1'b0)
  23. cnt_flag <= 1'b0;
  24. else if(cnt == CNT_MAX-1)
  25. cnt_flag <= 1'b1;
  26. else
  27. cnt_flag <= 1'b0;
  28. always@(posedge sys_clk or negedge sys_rst_n)
  29. if(sys_rst_n == 1'b0)
  30. data <= 4'd0;
  31. else if(cnt_flag == 1'b1)
  32. data <= data + 1'b1;
  33. else
  34. data <= data;
  35. always@(posedge sys_clk or negedge sys_rst_n)
  36. if(sys_rst_n == 1'b0)
  37. sel <= 6'b000_000;
  38. else
  39. sel <= 6'b111_111;
  40. always@(posedge sys_clk or negedge sys_rst_n)
  41. if(sys_rst_n == 1'b0)
  42. seg <= 8'hff;
  43. else case(data)
  44. 4'd0 : seg <= 8'hc0;
  45. 4'd1 : seg <= 8'hf9;
  46. 4'd2 : seg <= 8'ha4;
  47. 4'd3 : seg <= 8'hb0;
  48. 4'd4 : seg <= 8'h99;
  49. 4'd5 : seg <= 8'h92;
  50. 4'd6 : seg <= 8'h82;
  51. 4'd7 : seg <= 8'hf8;
  52. 4'd8 : seg <= 8'h80;
  53. 4'd9 : seg <= 8'h90;
  54. 4'd10 : seg <= 8'h88;
  55. 4'd11 : seg <= 8'h83;
  56. 4'd12 : seg <= 8'hc6;
  57. 4'd13 : seg <= 8'ha1;
  58. 4'd14 : seg <= 8'h86;
  59. 4'd15 : seg <= 8'h8e;
  60. default seg <= 8'hff;
  61. endcase
  62. endmodule

 第二部分74HC595 控制模块

程序中的一些变量所表示的含义: 

cnt:分频计数器。这里我们让计数器在 0 和 3 之间循环计数,这样一个循环生成一个 时钟即为四分频时钟。

cnt_bit:传输位数计数器。我们知道我们需要传输 14bit 的数据,故我们需要一个数据 器对传输的位数进行计数,这样我们对传输完成 14 位数据就可以用这个计数器进行判别了。当 cnt 等于 3 时让 cnt_bit 计数器加 1,让其从 0 到 13 循环计数,每个数值 代表传输一位数据。

data:我们将需要传输的数码管信号寄存在 data 中,方便赋值。存储顺序是根据我们 传输的位数顺序由低到高位进行存储的,至于数码管各信号的传输顺序我们在硬件部分已 有所讲解。

ds:串行数据输出(对我们 FPGA 芯片来说其是输出,对 74HC595 来说其是输入, stcp 和 shcp 信号也是如此)。第二片的 Q5 引脚连到 了数码管的 DIG6,也就是最右侧的数码管,而我们最右侧数码管对应的是我们位选信号的 最低位,即 sel[0]。所以我们第一位应传输的数据为 sel[0],当一次数据传完之后再次回到状态 0 开始新一轮 的数码管信号传输。

shcp:移位寄存器时钟,上升沿时将数据写入移位寄存器中。我们在 ds 数据的中间状 态拉高产生上升沿,这样可以使 shcp 采得的 ds 数据更加稳定。

stcp:存储寄存器时钟。当我们 14 位数码管控制信号传输完之后我们需要拉高一个 stcp 时钟来将信号存入存储寄存器之中。最后一个数据是在 cnt_bit=13 且 cnt=2 时传输的, 所以我们就在下一个时钟(cnt_bit=13 且 cnt=3 时)将 stcp 拉高一个时钟产生上升沿即可。

oe:存储寄存器数据输出使能信号,低电平有效,这里我们将复位信号取反的值赋给 该信号即可。

  1. module hc595_crtl
  2. (
  3. input wire sys_clk ,
  4. input wire sys_rst_n ,
  5. input wire [5:0] sel ,
  6. input wire [7:0] seg ,
  7. output reg stcp ,
  8. output reg shcp ,
  9. output reg ds ,
  10. output wire oe
  11. );
  12. reg [1:0] cnt_4;
  13. reg [3:0] cnt_bit;
  14. wire [13:0] data;
  15. assign data = {seg[0],seg[1],seg[2],seg[3],seg[4],seg[5],seg[6],seg[7],sel};
  16. assign oe = 1'b0;
  17. always@(posedge sys_clk or negedge sys_rst_n)
  18. if(sys_rst_n == 1'b0)
  19. cnt_4 <= 2'd0;
  20. else if(cnt_4 == 2'd3)
  21. cnt_4 <= 2'd0;
  22. else
  23. cnt_4 <= cnt_4 + 1'b1;
  24. always@(posedge sys_clk or negedge sys_rst_n)
  25. if(sys_rst_n == 1'b0)
  26. cnt_bit <= 4'd0;
  27. else if(cnt_4 == 2'd3 && cnt_bit == 4'd13)
  28. cnt_bit <= 4'd0;
  29. else if(cnt_4 == 2'd3)
  30. cnt_bit <= cnt_bit + 1'b1;
  31. else
  32. cnt_bit <= cnt_bit;
  33. always@(posedge sys_clk or negedge sys_rst_n)
  34. if(sys_rst_n == 1'b0)
  35. stcp <= 1'b0;
  36. else if(cnt_4 == 2'd3 && cnt_bit == 4'd13)
  37. stcp <= 1'b1;
  38. else
  39. stcp <= 1'b0;
  40. always@(posedge sys_clk or negedge sys_rst_n)
  41. if(sys_rst_n == 1'b0)
  42. shcp <= 1'b0;
  43. else if (cnt_4 >= 4'd2)
  44. shcp <= 1'b1;
  45. else
  46. shcp <= 1'b0;
  47. always@(posedge sys_clk or negedge sys_rst_n)
  48. if(sys_rst_n == 1'b0)
  49. ds <= 1'b0;
  50. else if (cnt_4 == 2'd0)
  51. ds <= data[cnt_bit];
  52. else
  53. ds <= ds;
  54. endmodule

第三部分顶层模块综合:

  1. module seg_595_static
  2. (
  3. input wire sys_clk,
  4. input wire sys_rst_n,
  5. output wire ds,
  6. output wire shcp,
  7. output wire stcp,
  8. output wire oe
  9. );
  10. wire [5:0] sel;
  11. wire [7:0] seg;
  12. seg_static seg_static_inst
  13. (
  14. .sys_clk (sys_clk),
  15. .sys_rst_n (sys_rst_n),
  16. .sel (sel ),
  17. .seg (seg )
  18. );
  19. hc595_crtl hc595_crtl_inst
  20. (
  21. .sys_clk (sys_clk),
  22. .sys_rst_n (sys_rst_n),
  23. .sel (sel),
  24. .seg (seg),
  25. .stcp (stcp),
  26. .shcp (shcp),
  27. .ds (ds),
  28. .oe (oe )
  29. );
  30. endmodule

编写仿真代码进行仿真验证

  1. `timescale 1ns/1ns
  2. module tb_seg_595_static();
  3. reg sys_clk;
  4. reg sys_rst_n;
  5. wire stcp;
  6. wire shcp;
  7. wire ds;
  8. wire oe;
  9. initial begin
  10. sys_clk = 1'b1;
  11. sys_rst_n <= 1'b0;
  12. #20
  13. sys_rst_n <= 1'b1;
  14. end
  15. always #10 sys_clk <= ~sys_clk;
  16. defparam seg_595_static_inst.seg_static_inst.CNT_MAX =100;
  17. seg_595_static seg_595_static_inst
  18. (
  19. .sys_clk (sys_clk),
  20. .sys_rst_n (sys_rst_n),
  21. .stcp (stcp),
  22. .shcp (shcp),
  23. .ds (ds),
  24. .oe (oe )
  25. );
  26. endmodule

     综合方正结果:

与我们所想的基本一致

上板验证:

开发板上电,绑定FPGA管脚,下载成功后,开发板数码管六位会依次从111111到FFFFFF循环。

总结:

经过对这个实验的流程,系统层次化设计有一个深刻的感悟 !

 

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

闽ICP备14008679号