搜索
bottom↓
回复: 0

【正点原子FPGA连载】第十三章静态数码管显示实验

[复制链接]

出0入234汤圆

发表于 2021-1-26 17:20:18 | 显示全部楼层 |阅读模式
1)实验平台:正点原子超越者FPGA开发板
2)  章节摘自【正点原子】超越者之FPGA开发指南
3)购买链接:https://item.taobao.com/item.htm?&id=631660290421
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz-chaoyuezhe.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子FPGA技术交流群:905624739
QQ群头像.png

100846rel79a9p4uelap24.jpg

100846f1ce1fg14zbg0va4.png

第十三章静态数码管显示实验



数码管是一种现代常用的数码显示器件,具有发光显示清晰、响应速度快、功耗低、体积小、寿命长、易于控制等诸多优点,在数字显示仪器仪表、数字控制设备等方面得到广泛应用。本章我们将介绍八段数码管的控制原理以及如何在数码管上显示出变化的数字。
本章分为以下几个章节:
1313.1  简介
13.2  实验任务
13.3  硬件设计
13.4  程序设计
13.5  下载验证


13.1简介
数码管也称半导体数码管,它是将若干发光二极管按一定图形排列并封装在一起的一种数码显示器件。常见的数码管如图 13.1.1所示,这种数码管主要被称为八段数码管或8字形数码管,可用来显示小数点、数字0~9,和英文字母A~F。
13313.png

图 13.1.1 八段数码管

除了常用的八段数码管之外,较常见的还有“±1”数字管、“N”形管、“米”字管以及工业科研领域使用的14段管、16段管、24段管等。
13439.png

图 13.1.2 其他常用数码管

不管是什么形式的数码管,其显示原理都是点亮内部的发光二极管来发光。那么如何用数码管显示指定的数字呢?
数码管内部电路如图 13.1.3所示,从该图可以看出,一位数码管的引脚是10个,其中7个引脚对应连接到组成数码管中间“8”字型的led,Dp引脚连接到数码管的小数点显示led(dp)。最后还有两个公共端,生产商为了封装统一,单个数码管都封装成10个引脚,其中8和3两个公共端引脚(图中为com)是连接在一起的。公共端又可分为共阳极和共阴极,图 13.1.3(b)为共阴极内部原理图,图 13.1.3(c)为共阳极内部原理图。
13838.png

图 13.1.3 数码管内部原理图

对共阴极数码管来说,其8个发光二极管的阴极在数码管内部全部连接在一起,所以称“共阴”,而阳极独立。对共阳极数码管来说,其8个发光二极管的阳极在数码管内部全部连接在一起,所以称“共阳”,而阴极独立。以共阳极数码管为例,当我们想让数码管显示数字“8”,可以给a、b、c…g七个引脚送低电平,数码管就显示“8”,显示数字“1”,就给b、c引脚低电平,其余引脚(除公共端)给高电平,数码管就显示“1”。
当多位数码管应用于某一系统时,为了减少数码管占用的I/O口,将其段选(数码管的a、b、c等引脚)连接在一起,而位选(数码管的公共端)独立控制。这样我们可以通过位选信号控制哪几个数码管亮,而且在同一时刻,位选选通的所有数码管上显示的数字始终都是一样的,因为它们的段选是连接在一起的,所以送入所有数码管的段选信号都是相同的,数码管的这种显示方法叫做静态显示。
对于静态显示还有一种是数码管的每一个码段都由一个单独的I/O端口进行驱动,其优点是编程较为简单,显示亮度较高;缺点是占用I/O较多,当数码管较多时,必须增加译码驱动器进行驱动,或使用串口转并口芯片来拓展端口。因而对于多位数码管的使用,一般都采用前一种方式进行电路设计,这种电路设计更为方便的是以动态方式驱动数码管。动态显示与静态显示的区别关键在于位选的控制。由于静态显示容易实现,本章我们以6位共阳数码管的静态方式为例,带大家初步了解数码管的工作原理。
13.2实验任务
本节实验任务是使用超越者开发板上的6位数码管以静态方式依次显示000000、111111、222222至FFFFFF,结束后继续从000000开始计数,每0.5s变化一次。
13.3硬件设计
我们的超越者开发板上有6位共阳数码管,其原理图如图 13.3.1所示。在这里我们需要注意的是,为了增加FPGA输出信号的驱动能力,我们使用PNP型三极管驱动数码管的位选段,所以给三极管基极提供低电平时,位选信号为高电平。
131753.png

图 13.3.1 硬件原理图

本实验中,各端口信号的管脚分配如下表所示:
表 13.3.1 静态数码管显示实验管脚分配图
1331.png

对应的UCF约束语句如下所示:
  1. # PlanAhead Generated physical constraints
  2. NET "sys_clk" LOC = N8 | IOSTANDARD = "LVCMOS33";
  3. NET "sys_rst_n" LOC = G16 | IOSTANDARD = "LVCMOS33";
  4. NET "seg_led[0]" LOC = J12 | IOSTANDARD = "LVCMOS33";
  5. NET "seg_led[1]" LOC = H13 | IOSTANDARD = "LVCMOS33";
  6. NET "seg_led[2]" LOC = L12 | IOSTANDARD = "LVCMOS33";
  7. NET "seg_led[3]" LOC = K11 | IOSTANDARD = "LVCMOS33";
  8. NET "seg_led[4]" LOC = L13 | IOSTANDARD = "LVCMOS33";
  9. NET "seg_led[5]" LOC = L14 | IOSTANDARD = "LVCMOS33";
  10. NET "seg_led[6]" LOC = K12 | IOSTANDARD = "LVCMOS33";
  11. NET "seg_led[7]" LOC = M13 | IOSTANDARD = "LVCMOS33";
  12. NET "seg_sel[0]" LOC = M14 | IOSTANDARD = "LVCMOS33";
  13. NET "seg_sel[1]" LOC = N14 | IOSTANDARD = "LVCMOS33";
  14. NET "seg_sel[2]" LOC = J13 | IOSTANDARD = "LVCMOS33";
  15. NET "seg_sel[3]" LOC = F13 | IOSTANDARD = "LVCMOS33";
  16. NET "seg_sel[4]" LOC = H11 | IOSTANDARD = "LVCMOS33";
  17. NET "seg_sel[5]" LOC = G12 | IOSTANDARD = "LVCMOS33";
复制代码

13.4程序设计
根据实验任务,我们可以大致规划出系统的控制流程:首先我们需要一个静态数码管显示模块在数码管上显示数据,其次需要一个计时模块每当计时到0.5s时改变数码管显示的数值。由此画出系统的功能框图如下所示:
133572.png

图 13.4.1 数码管静态显示实验系统框图

程序中各模块端口及信号连接如图 13.4.2所示:
133691.png

图 13.4.2 顶层模块原理图

FPGA顶层(seg_led_static_top)例化了以下两个模块:计时模块(time_count)和数码管静态显示模块(seg_led_static),实现各模块之间数据的交互。计时模块将计时到0.5s时的标志信号flag传递给数码管静态显示模块,数码管静态显示模块接收到此信号时显示的数值增加1。
计时模块(time_count):计时模块对系统时钟进行计数,当计时到给定值(此处指0.5s)时输出标志信号。
数码管静态显示模块(seg_led_static):数码管静态显示模块在数码管上以静态方式显示数值。
顶层模块的代码如下:
  1. 1  module seg_led_static_top (
  2. 2      input               sys_clk  ,       // 系统时钟
  3. 3      input               sys_rst_n,       // 系统复位信号(低有效)
  4. 4  
  5. 5      output    [5:0]     seg_sel  ,       // 数码管位选
  6. 6      output    [7:0]     seg_led          // 数码管段选
  7. 7  
  8. 8  );
  9. 9  
  10. 10 //parameter define
  11. 11 parameter  TIME_SHOW = 25'd25000_000;    // 数码管变化的时间间隔0.5s
  12. 12
  13. 13 //wire define
  14. 14 wire       flag;                         // 数码管变化的通知信号
  15. 15
  16. 16 //*****************************************************
  17. 17 //**                    main code
  18. 18 //*****************************************************
  19. 19
  20. 20 //每隔0.5s产生一个时钟周期的脉冲信号
  21. 21 time_count #(
  22. 22     .MAX_NUM    (TIME_SHOW)
  23. 23 ) u_time_count(
  24. 24     .clk        (sys_clk  ),
  25. 25     .rst_n      (sys_rst_n),
  26. 26     
  27. 27     .flag       (flag     )
  28. 28 );
  29. 29
  30. 30 //每当脉冲信号到达时,使数码管显示的数值加1
  31. 31 seg_led_static u_seg_led_static (
  32. 32     .clk        (sys_clk  ),
  33. 33     .rst_n      (sys_rst_n),
  34. 34
  35. 35     .add_flag    (flag      ),
  36. 36     .seg_sel     (seg_sel   ),
  37. 37     .seg_led     (seg_led   )
  38. 38 );
  39. 39
  40. 40 endmodule
复制代码

顶层模块主要完成对其余模块的例化。代码第11行的参数TIME_SHOW控制数码管每隔多长时间改变显示的数值,该参数值与代码第32行的clk时钟信号频率有关。由于例化时clk为系统时钟sys_clk(50MHz),所以每隔0.5秒改变数码管显示的数值时此参数值为,此功能由计时模块(time_count)实现。
计时模块的代码如下所示:
  1. 1  module time_count(
  2. 2      input           clk     ,   // 时钟信号
  3. 3      input           rst_n   ,   // 复位信号
  4. 4  
  5. 5      output   reg    flag        // 一个时钟周期的脉冲信号
  6. 6  );
  7. 7  
  8. 8  //parameter define
  9. 9  parameter  MAX_NUM = 25000_000; // 计数器最大计数值
  10. 10
  11. 11 //reg define
  12. 12 reg [24:0] cnt;                 // 时钟分频计数器
  13. 13
  14. 14 //*****************************************************
  15. 15 //**                    main code
  16. 16 //*****************************************************
  17. 17
  18. 18 //计数器对时钟计数,每计时到0.5s,输出一个时钟周期的脉冲信号
  19. 19 always @ (posedge clk or negedge rst_n) begin
  20. 20     if (!rst_n) begin
  21. 21         flag <= 1'b0;
  22. 22         cnt  <= 24'b0;
  23. 23     end
  24. 24     else if(cnt < MAX_NUM - 1'b1) begin
  25. 25         cnt  <= cnt +1'b1;
  26. 26         flag <= 1'b0;
  27. 27     end
  28. 28     else begin
  29. 29         cnt  <= 24'b0;
  30. 30         flag <= 1'b1;
  31. 31     end
  32. 32 end
  33. 33
  34. 34 endmodule
复制代码

代码中第9行的参数MAX_NUM为计数的最大计数值,由于是对时钟计数,相当于计时,第19行的always语句块表示的是当计数器cnt计数值小于MAX_NUM - 1'b1时,标志(flag)为“0”,否则标志为“1”,并且计数器cnt清零。通过Chipscope抓到的波形图如下图所示:
136249.png

图 13.4.3 Chipscope波形图

数码管静态显示模块的代码如下:
  1. 1  module seg_led_static (
  2. 2      input               clk     ,   // 时钟信号
  3. 3      input               rst_n   ,   // 复位信号(低有效)
  4. 4     
  5. 5      input               flag,       // 数码管变化的通知信号
  6. 6      output  reg  [5:0]  seg_sel ,   // 数码管位选
  7. 7      output  reg  [7:0]  seg_led     // 数码管段选
  8. 8  );
  9. 9  
  10. 10 //reg define
  11. 11 reg [3:0] num;                      // 数码管显示的十六进制数
  12. 12
  13. 13 //*****************************************************
  14. 14 //**                    main code
  15. 15 //*****************************************************
  16. 16
  17. 17 //控制数码管位选信号(低电平有效),选中所有的数码管
  18. 18 always @ (posedge clk or negedge rst_n) begin
  19. 19     if (!rst_n)
  20. 20         seg_sel <= 6'b111111;
  21. 21     else
  22. 22         seg_sel <= 6'b000000;
  23. 23 end
  24. 24
  25. 25 //每次通知信号到达时,数码管显示的十六进制数值加1
  26. 26 always @ (posedge clk or negedge rst_n) begin
  27. 27     if (!rst_n)
  28. 28         num <= 4'h0;
  29. 29     else if(flag) begin
  30. 30         if (num < 4'hf)
  31. 31             num <= num + 1'b1;
  32. 32         else
  33. 33             num <= 4'h0;
  34. 34     end
  35. 35     else
  36. 36         num <= num;
  37. 37 end
  38. 38
  39. 39 //根据数码管显示的数值,控制段选信号
  40. 40 always @ (posedge clk or negedge rst_n) begin
  41. 41     if (!rst_n)
  42. 42         seg_led <= 8'b0;
  43. 43     else begin
  44. 44         case (num)
  45. 45             4'h0 :    seg_led <= 8'b1100_0000;
  46. 46             4'h1 :    seg_led <= 8'b1111_1001;
  47. 47             4'h2 :    seg_led <= 8'b1010_0100;
  48. 48             4'h3 :    seg_led <= 8'b1011_0000;
  49. 49             4'h4 :    seg_led <= 8'b1001_1001;
  50. 50             4'h5 :    seg_led <= 8'b1001_0010;
  51. 51             4'h6 :    seg_led <= 8'b1000_0010;
  52. 52             4'h7 :    seg_led <= 8'b1111_1000;
  53. 53             4'h8 :    seg_led <= 8'b1000_0000;
  54. 54             4'h9 :    seg_led <= 8'b1001_0000;
  55. 55             4'ha :    seg_led <= 8'b1000_1000;
  56. 56             4'hb :    seg_led <= 8'b1000_0011;
  57. 57             4'hc :    seg_led <= 8'b1100_0110;
  58. 58             4'hd :    seg_led <= 8'b1010_0001;
  59. 59             4'he :    seg_led <= 8'b1000_0110;
  60. 60             4'hf :    seg_led <= 8'b1000_1110;
  61. 61             default : seg_led <= 8'b1100_0000;
  62. 62         endcase
  63. 63     end
  64. 64 end
  65. 65
  66. 66 endmodule
复制代码

代码第11行的num信号为数码管显示的数值,由代码第30行的if语句块可知,其能显示的数值为0~f。由于开发板上的数码管为共阳数码管,所以不显示小数点时该位值为“1”,因而seg_led信号的最高位为“1”。下图为该模块运行时Chipscope抓取到的波形图:
138551.png

图 13.4.4 Chipscope波形图

由该波形图可知,当add_flag信号拉高时,数值信号num加1,输出对应的段选数据由10001000变为10000011,与代码设计的意图相符。
13.5下载验证
   编译完工程之后就可以开始下载程序了。如下图 13.5.1所示。将Xilinx下载器一端连接电脑,另一端与开发板上的JTAG下载口连接,然后连接电源线。
138800.png

图 13.5.1 超越者开发板实物图

按下电源开关,接下来我们下载程序,验证静态数码管显示实验功能。
开发板电源打开后,点击工具栏中的“Initialize chain”图标(图 13.5.2红框位置),添加工程目录下的“seg_led_static_top.bit”文件。然后双击“Program”将工程编译完成后得到的bit文件下载到开发板中,如图 13.5.3所示。

139113.png

图 13.5.2 硬件连接

139172.png

图 13.5.3 程序下载完成界面

下载完成后,就能在开发板上看到静态数码管显示实验的效果如下图所示。
139269.png

图 13.5.4 静态数码管显示效果图


回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-11 10:20

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表