正点原子 发表于 2021-1-23 15:09:25

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

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





第九章按键控制LED灯实验

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


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

图 9.1.1 轻触式按键

图 9.1.2 自锁式按键
9.2实验任务
使用超越者开发板上的四个按键控制四个LED灯。不同按键按下时,四个LED灯显示不同效果。
9.3硬件设计
如图 9.3.1所示,本实验使用四个按键开关控制四个LED灯。

图 9.3.1 按键电路原理图
如上图所示,开发板上的5个按键未按下时,输出高电平,按下后,输出低电平。
本实验中,系统时钟、复位按键、按键和LED灯的管脚如下表所示。
表 9.3.1 触摸按键控制LED管脚分配图

对应的 UCF 约束语句如下:
# PlanAhead Generated physical constraints
NET "sys_clk" LOC = N8 | IOSTANDARD = "LVCMOS33";
NET "sys_rst_n" LOC = G16 | IOSTANDARD = "LVCMOS33";
NET "led" LOC = T3 | IOSTANDARD = "LVCMOS33";
NET "led" LOC = M7 | IOSTANDARD = "LVCMOS33";
NET "led" LOC = M6 | IOSTANDARD = "LVCMOS33";
NET "led" LOC = T5 | IOSTANDARD = "LVCMOS33";
NET "key" LOC = R3 | IOSTANDARD = "LVCMOS33";
NET "key" LOC = N6 | IOSTANDARD = "LVCMOS33";
NET "key" LOC = N5 | IOSTANDARD = "LVCMOS33";
NET "key" LOC = P5 | IOSTANDARD = "LVCMOS33";
9.4程序设计
我们程序设计最终实现的效果为:无按键按下时,LED灯全灭;按键key0按下时,LED灯显示自右向左的流水效果;按键key1按下时,LED灯显示自左向右的流水效果;按键key2按下时,四个LED灯同时闪烁;按键key3按下时,LED灯全亮。
LED在流水效果和闪烁效果在时间间隔均为0.2秒,因此需要在程序中定义一个0.2s的计数器,即每隔0.2s,状态计数器加一。根据当前按键的状态选择不同的显示模式,不同的显示模式下四个led灯的亮灭随状态计数器的值改变,从而呈现出不同的显示效果。

图 9.4.1 系统框图
按键控制led模块的代码如下所示:
1module key_led(
2      input               sys_clk,    //50Mhz系统时钟
3      input               sys_rst_n,    //系统复位,低有效
4      input      key,          //按键输入信号
5      outputregled         //LED输出信号
6      );
7
8//reg define   
9reg cnt;
10 regled_control;
11
12 //用于计数0.2s的计数器
13 always @ (posedge sys_clk or negedge sys_rst_n) begin
14   if(!sys_rst_n)
15         cnt<=24'd9_999_999;
16   else if(cnt<24'd9_999_999)
17         cnt<=cnt+1;
18   else
19         cnt<=0;
20 end
21
22 //用于led灯状态的选择
23 always @(posedge sys_clk or negedge sys_rst_n) begin
24   if (!sys_rst_n)
25         led_control <= 2'b00;
26   else if(cnt == 24'd9_999_999)
27         led_control <= led_control + 1'b1;
28   else
29         led_control <= led_control;
30 end
31
32 //识别按键,切换显示模式
33 always @(posedge sys_clk or negedge sys_rst_n) begin
34   if(!sys_rst_n) begin
35         led<=4'b 0000;
36   end
37   else if(key== 0)//按键1按下时,从右向左的流水灯效果
38         case (led_control)
39             2'b00   : led<=4'b1000;
40             2'b01   : led<=4'b0100;
41             2'b10   : led<=4'b0010;
42             2'b11   : led<=4'b0001;
43             default: led<=4'b0000;
44         endcase
45      else if (key==0)//按键2按下时,从左向右的流水灯效果
46         case (led_control)
47             2'b00   : led<=4'b0001;
48             2'b01   : led<=4'b0010;
49             2'b10   : led<=4'b0100;
50             2'b11   : led<=4'b1000;
51             default: led<=4'b0000;
52         endcase
53   else if (key==0)//按键3按下时,LED闪烁
54         case (led_control)
55             2'b00   : led<=4'b1111;
56             2'b01   : led<=4'b0000;
57             2'b10   : led<=4'b1111;
58             2'b11   : led<=4'b0000;
59             default: led<=4'b0000;
60         endcase
61   else if (key==0)//按键4按下时,LED全亮
62         led<=4'b1111;
63   else
64         led<=4'b0000;    //无按键按下时,LED熄灭   
65 end
66
67 endmodule
代码主要分为三个部分,第12至20行对系统时钟计数,当计数时间达0.2s时,计数器清零,同时使led_control在四个状态(00,01,10,11)内依次变化。第33至65行利用case语句实现对按键状态的检测,当不同的按键按下时,led随着led_control的变化,被赋予不同的值。
大家可以发现,本次实验和流水灯实验计数时间都是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。
为了验证我们的程序,我们在modelsim内对代码进行仿真。
Testbench模块代码如下:
1`timescale 1 ns/ 1 ns
2module tb_key_led();
3
4parameter T = 20;
5
6regkey      ;
7reg         sys_clk;
8reg         sys_rst_n;
9reg         key_value;
10
11 wire led;
12
13 initial begin   
14      key                <=4'b1111;//按键初始状态为全断开
15      sys_clk            <=1'b0;   //初始时钟为低电平
16      sys_rst_n          <=1'b0;   //复位信号初始为低电平
17 #T   sys_rst_n          <=1'b1;   //一个时钟周期后复位信号拉高
18
19 #600_000_020 key   <=0;      //0.6s时按下按键1
20 #800_000_000 key   <=1;   
21 key                  <=0;      //0.8s后松开按键1,按下按键2
22 #800_000_000 key   <=1;   
23 key                  <=0;      //0.8s后松开按键2,按下按键3
24 #800_000_000 key   <=1;   
25 key                  <=0;      //0.8s后松开按键3,按下按键4   
26 #800_000_000 key   <=1;      //0.8s后松开按键4
27
28 end
29
30 always # (T/2) sys_clk <= ~sys_clk;
31 key_led   u_key_led(
32       .sys_clk(sys_clk),      
33       .sys_rst_n(sys_rst_n),   
34       .key(key),                  
35       .led(led)         
36       );
37
38 endmodule

图 9.4.2 仿真图像
观察代码,结合波形分析可知。14至16行代码为对时钟信号、复位信号、按键信号赋初始值,默认为按键全断开。第0.6s时按下按键key0(kye由高电平变为低电平),可观察到led3至led0依次点亮,呈现自右向左的流水效果;按键key1断开的同时按下按键key2,可观察到led0至led3依次点亮,呈现自左向右的流水效果;按键key2断开的同时按下按键key3s,可观察到led0至led3呈现闪烁效果;按键key3断开的同时按下按键key4,可观察到led0至led3保持全亮。
9.5下载验证
首先我们打开按键控制LED灯工程,在工程所在的路径下打开key_led/prj/key_led文件夹,在里面找到“key_led.xise”并双击打开。注意工程所在的路径名只能由字母、数字以及下划线组成,不能出现中文、空格以及特殊字符等。key_led工程打开后如图 9.5.1所示。

图 9.5.1 按键控制LED灯工程
工程打开后双击“Configure Target Device”一栏中的“Manage Configuration Project(iMAPCT)” (上图红框位置),在弹出的界面中双击“Boundary Scan”,下载界面如图 8.5.2所示。

图 9.5.2 程序下载界面
如下图 9.5.3所示。将Xilinx下载器一端连接电脑,另一端与开发板上的JTAG下载口连接,然后连接电源线。

图 9.5.3 超越者开发板实物图
打开电源开关,接下来我们下载程序,验证按键控制LED灯功能。
开发板电源打开后,点击工具栏中的“Initialize chain”图标(图 9.5.4红框位置),添加工程目录下的“key_led.bit”文件。然后双击“Program”将工程编译完成后得到的bit文件下载到开发板中,如图 9.5.5所示。

图 9.5.4 硬件连接

图 9.5.5 程序下载完成界面
下载完成后,就可以利用按键来控制LED了,如下图所示。

图 9.5.6 按键控制LED灯效果图

页: [1]
查看完整版本: 【正点原子FPGA连载】第九章按键控制LED灯实验