搜索
bottom↓
回复: 0

【正点原子FPGA连载】第九章按键控制LED灯实验

[复制链接]

出0入234汤圆

发表于 2020-11-9 15:41:34 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 2021-1-25 18:37 编辑

1)实验平台:正点原子达芬奇FPGA开发板
2)购买链接:https://detail.tmall.com/item.htm?id=624335496505
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz_dafenqi.html
4) 正点原子官方B站:https://space.bilibili.com/394620890
5)对正点原子FPGA感兴趣的同学可以加群讨论:905624739  点击加入:
QQ群头像.png

100846rel79a9p4uelap24.jpg

100846f1ce1fg14zbg0va4.png

第九章按键控制LED灯实验



按键是常用的一种控制器件。生活中我们可以见到各种形式的按键,由于其结构简单,成本低廉等特点,在家电、数码产品、玩具等方面有广泛的应用。本章我们将介绍如何使用按键控制多个LED的亮灭。
本章包括以下几个部分:
99.1简介
9.2实验任务
9.3硬件设计
9.4程序设计
9.5下载验证














9.1简介
按键开关是一种电子开关,属于电子元器件类。我们的开发板上有两种按键开关:第一种是本实验所使用的轻触式按键开关(如图 9.1.1),简称轻触开关。使用时以向开关的操作方向施加压力使内部电路闭合接通,当撤销压力时开关断开,其内部结构是靠金属弹片受力后发生形变来实现通断的;第二种是自锁按键(如图 9.1.2),自锁按键第一次按下后保持接通,即自锁,第二次按下后,开关断开,同时开关按钮弹出来,开发板上的电源键就是这种开关。
新建DOCX 文档416.png

图 9.1.1 轻触式按键

新建DOCX 文档475.png

图 9.1.2 自锁式按键

9.2实验任务
使用达芬奇开发板上的四个按键控制四个LED灯。不同按键按下时,四个LED灯显示不同效果。
9.3硬件设计
如图 9.3.1所示,本实验使用四个按键开关控制四个LED灯。
新建DOCX 文档646.png

图 9.3.1 按键电路原理图

如上图所示,开发板上的4个按键未按下时,输出高电平,按下后,输出低电平。
本实验中,系统时钟、复位按键、按键和LED灯的管脚如下表所示。
表 9.3.1 按键控制LED管脚分配图
微信图片_20201109154041.png

对应的XDC约束语句如下:
  1. set_property -dict {PACKAGE_PIN R4 IOSTANDARD LVCMOS33} [get_ports sys_clk]
  2. set_property -dict {PACKAGE_PIN U2 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
  3. set_property -dict {PACKAGE_PIN R2 IOSTANDARD LVCMOS33} [get_ports led[0]]
  4. set_property -dict {PACKAGE_PIN R3 IOSTANDARD LVCMOS33} [get_ports led[1]]
  5. set_property -dict {PACKAGE_PIN V2 IOSTANDARD LVCMOS33} [get_ports led[2]]
  6. set_property -dict {PACKAGE_PIN Y2 IOSTANDARD LVCMOS33} [get_ports led[3]]

  7. set_property -dict {PACKAGE_PIN T1 IOSTANDARD LVCMOS33} [get_ports key[0]]
  8. set_property -dict {PACKAGE_PIN U1 IOSTANDARD LVCMOS33} [get_ports key[1]]
  9. set_property -dict {PACKAGE_PIN W2 IOSTANDARD LVCMOS33} [get_ports key[2]]
  10. set_property -dict {PACKAGE_PIN T3 IOSTANDARD LVCMOS33} [get_ports key[3]]
复制代码

9.4程序设计
我们程序设计最终实现的效果为:无按键按下时,LED灯全灭;按键1按下时,LED灯显示自右向左的流水效果;按键2按下时,LED灯显示自左向右的流水效果;按键3按下时,四个LED灯同时闪烁;按键4按下时,LED灯全亮。
LED在流水效果和闪烁效果在时间间隔均为0.2秒,因此需要在程序中定义一个0.2s的计数器,即每隔0.2s,状态计数器加一。根据当前按键的状态选择不同的显示模式,不同的显示模式下四个led灯的亮灭随状态计数器的值改变,从而呈现出不同的显示效果。
新建DOCX 文档2192.png

图 9.4.1 系统框图

按键控制led模块的代码如下所示:
  1. 1  module key_led(
  2. 2      input               sys_clk  ,    //50Mhz系统时钟
  3. 3      input               sys_rst_n,    //系统复位,低有效
  4. 4      input        [3:0]  key,          //按键输入信号
  5. 5      output  reg  [3:0]  led           //LED输出信号
  6. 6      );
  7. 7  
  8. 8  //reg define     
  9. 9  reg  [23:0] cnt;
  10. 10 reg  [1:0]  led_control;
  11. 11
  12. 12 //用于计数0.2s的计数器
  13. 13 always @ (posedge sys_clk or negedge sys_rst_n) begin
  14. 14     if(!sys_rst_n)
  15. 15         cnt <= 24'd0;         
  16. 16     else if(cnt < 24'd9_999_999)
  17. 17     //else if(cnt < 24'd9)       //仅用于仿真
  18. 18         cnt<= cnt + 1;
  19. 19     else
  20. 20         cnt<= 0;
  21. 21 end
  22. 22
  23. 23 //用于led灯状态的选择
  24. 24 always @(posedge sys_clk or negedge sys_rst_n) begin
  25. 25     if (!sys_rst_n)
  26. 26         led_control <= 2'b00;
  27. 27     else if(cnt == 24'd9_999_999)
  28. 28     //else if(cnt == 24'd9)            //仅用于仿真
  29. 29         led_control <= led_control + 1'b1;
  30. 30     else
  31. 31         led_control <= led_control;
  32. 32 end
  33. 33
  34. 34 //识别按键,切换显示模式
  35. 35 always @(posedge sys_clk or negedge sys_rst_n) begin
  36. 36     if(!sys_rst_n) begin
  37. 37           led <= 4'b0000;
  38. 38     end
  39. 39     else if(key[0]== 0)  //按键1按下时,从右向左的流水灯效果
  40. 40         case (led_control)
  41. 41             2'b00   : led <= 4'b1000;
  42. 42             2'b01   : led <= 4'b0100;
  43. 43             2'b10   : led <= 4'b0010;
  44. 44             2'b11   : led <= 4'b0001;
  45. 45             default  : led <= 4'b0000;
  46. 46         endcase
  47. 47     else if (key[1]==0)  //按键2按下时,从左向右的流水灯效果
  48. 48         case (led_control)
  49. 49             2'b00   : led <= 4'b0001;
  50. 50             2'b01   : led <= 4'b0010;
  51. 51             2'b10   : led <= 4'b0100;
  52. 52             2'b11   : led <= 4'b1000;
  53. 53             default  : led <= 4'b0000;
  54. 54         endcase
  55. 55     else if (key[2]==0)  //按键3按下时,LED闪烁
  56. 56         case (led_control)
  57. 57             2'b00   : led <= 4'b1111;
  58. 58             2'b01   : led <= 4'b0000;
  59. 59             2'b10   : led <= 4'b1111;
  60. 60             2'b11   : led <= 4'b0000;
  61. 61             default  : led <= 4'b0000;
  62. 62         endcase
  63. 63     else if (key[3]==0)  //按键4按下时,LED全亮
  64. 64         led = 4'b1111;
  65. 65     else
  66. 66         led <= 4'b0000;    //无按键按下时,LED熄灭     
  67. 67 end
  68. 68
  69. 69 endmodule
复制代码

代码主要分为三个部分,第12至21行对系统时钟计数,当计数时间达0.2s时,计数器清零,同时使led_control在四个状态(00,01,10,11)内依次变化。第34至67行利用case语句实现对按键状态的检测,当不同的按键按下时,led随着led_control的变化,被赋予不同的值。仿真时我们设为每10个时钟周期,进行一次状态转换一次,如代码第17和28行。
大家可以发现,本次实验和流水灯实验计数时间都是0.2s,本次实验的计数器最大可以计数到9_999_999,而流水灯实验中计数器的值最大可以计数到10_000_000。事实上,这两个实验计数器都是从0开始计数的,本次实验从0计数到9_999_999,需要10_000_000个时钟周期,而系统时钟为20ns,所以计数的时间为0.2s,而流水灯实验从0计数到10_000_000需要10_000_001个时钟周期,因此其计数时间实际上比0.2s要多出20ns。
为了验证我们的程序,我们使用Vivado对代码进行仿真。
Testbench模块代码如下:
  1. 1  `timescale 1 ns/ 1 ns
  2. 2  module tb_key_led();
  3. 3  
  4. 4  parameter T = 20;
  5. 5  
  6. 6  reg  [3:0]  key      ;
  7. 7  reg         sys_clk  ;
  8. 8  reg         sys_rst_n;
  9. 9  
  10. 10 wire [3:0]  led;
  11. 11
  12. 12 initial begin   
  13. 13      key                <=4'b1111;//按键初始状态为全断开
  14. 14      sys_clk            <=1'b0;   //初始时钟为低电平
  15. 15      sys_rst_n          <=1'b0;   //复位信号初始为低电平
  16. 16 #T   sys_rst_n          <=1'b1;   //一个时钟周期后复位信号拉高
  17. 17
  18. 18      key[0]             <=0;      //0.6s时按下按键1
  19. 19 #800 key[0]             <=1;   
  20. 20      key[1]             <=0;      //0.8s后松开按键1,按下按键2
  21. 21 #800 key[1]             <=1;   
  22. 22      key[2]             <=0;      //0.8s后松开按键2,按下按键3
  23. 23 #800 key[2]             <=1;   
  24. 24      key[3]             <=0;      //0.8s后松开按键3,按下按键4   
  25. 25 #800 key[3]             <=1;      //0.8s后松开按键4
  26. 26
  27. 27 end
  28. 28
  29. 29 always # (T/2) sys_clk <= ~sys_clk;
  30. 30 key_led   u_key_led(
  31. 31       .sys_clk   (sys_clk),      
  32. 32       .sys_rst_n (sys_rst_n),     
  33. 33       .key       (key),                  
  34. 34       .led       (led)         
  35. 35       );
  36. 36
  37. 37 endmodule
复制代码

新建DOCX 文档5899.png

图 9.4.2 仿真图像

观察代码,结合波形分析可知。13至18行代码为对时钟信号、复位信号、按键信号赋初始值,默认为按键全断开。在第一个周期按下按键key0(kye[0]由高电平变为低电平),可观察到led3至led0依次点亮,呈现自右向左的流水效果;按键key0断开的同时按下按键key1,可观察到led0至led3依次点亮,呈现自左向右的流水效果;按键key1断开的同时按下按键key2,可观察到led0至led3呈现闪烁效果;按键key2断开的同时按下按键key3,可观察到led0至led3保持全亮。
9.5下载验证
编译工程并生成比特流.bit文件后,接下来我们下载比特流.bit文件,验证按键控制LED灯的功能。程序下载完成后,我们按KEY0、KEY1、KEY2和KEY3,就可以看到按键对应的实验现象了。如下图所示:
新建DOCX 文档6308.png

图 9.5.1 实验现象

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

本版积分规则

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

GMT+8, 2024-4-19 15:48

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

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