本帖最后由 正点原子运营 于 2023-3-24 14:33 编辑
第九章 按键控制LED实验
1)实验平台:正点原子 DFZU2EG/4EV MPSoC开发板
2) 章节摘自【正点原子】DFZU2EG/4EV MPSoC之FPGA开发指南 V1.0
6)FPGA技术交流QQ群:994244016
按键是常用的一种控制器件。生活中我们可以见到各种形式的按键,由于其结构简单,成本低廉等特点,在家电、数码产品、玩具等方面有广泛的应用。本章我们将介绍如何使用按键来控制LED闪烁的方式。 本章包括以下几个部分: 9.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 实验任务本节实验任务是使用开发板上的PL_KEY1和PL_KEY2按键来控制开发板上的PL_LED1和PL_LED1两个LED的闪烁方式。没有按键按下时,两个LED保持常亮;如果按键PL_KEY1按下,则两个LED交替闪烁;如果按键PL_KEY2按下,则两个LED同时闪烁。
9.3 硬件设计开发板上按键的原理图如下图所示: 图 9.3.1 按键电路原理图
在图 9.3.1中,PL_KEY1和PL_KEY2与PL_RST连接到MPSoC的PL端,PS_KEY1和PS_KEY2连接到MPSoC的PS端。在《DFZU2EG/4EV MPSoC开发板之FPGA开发指南》中,我们只使用PL端的外设。 PL端的按键没有按下时,对应的IO端口为高电平;当按键按下时,对应的IO端口变为低电平。 本实验的管脚分配如下表所示: 表 9.3.1 按键控制LED实验管脚分配
对应的XDC约束语句如下所示: - #IO管脚约束
- #时钟周期约束
- create_clock-name sys_clk_p -period 10.000 [get_ports sys_clk_p]
- #时钟
- set_propertyIOSTANDARD DIFF_HSTL_I_12 [get_ports sys_clk_p]
- set_propertyIOSTANDARD DIFF_HSTL_I_12 [get_ports sys_clk_n]
- set_propertyPACKAGE_PIN AE5 [get_ports sys_clk_p]
- set_propertyPACKAGE_PIN AF5 [get_ports sys_clk_n]
- #复位
- set_property-dict {PACKAGE_PIN AH11 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
- #按键
- set_property-dict {PACKAGE_PIN AD11 IOSTANDARD LVCMOS33} [get_ports key[0]]
- set_property-dict {PACKAGE_PIN AD10 IOSTANDARD LVCMOS33} [get_ports key[1]]
- #LED灯
- set_property-dict {PACKAGE_PIN AE10 IOSTANDARD LVCMOS33} [get_ports {led[0]}]
- set_property-dict {PACKAGE_PIN AF10 IOSTANDARD LVCMOS33} [get_ports {led[1]}]
复制代码
9.4 程序设计按键控制LED系统框图如下图所示: 图 9.4.1 按键控制LED系统框图
在图 9.4.1中,计数器对由差分转单端得到的系统时钟(sys_clk)100MHz时钟进行计数,从而达到计时的目的。计数器在每次计时到0.5秒的时候,就改变LED的显示状态,然后清零并重新开始计数。 然后根据两个按键(KEY0和KEY1)的状态,在不同的LED状态下,分别设置LED的显示模式(是同时闪烁,或者交替闪烁)。 顶层模块代码如下: - 1 module key_led(
- 2 input sys_clk_p, //系统差分输入时钟
- 3 input sys_clk_n, //系统差分输入时钟
- 4 input sys_rst_n, //系统复位
- 5
- 6 input [1:0 key, //按键
- 7 output reg [1:0 led //LED灯
- 8 );
- 9
- 10 //reg define
- 11 reg [26:0 cnt; //计数器
- 12 reg led_ctrl;
- 13
- 14 //*****************************************************
- 15 //** main code
- 16 //*****************************************************
- 17
- 18 //转换差分信号
- 19 IBUFDS diff_clock
- 20 (
- 21 .I (sys_clk_p), //系统差分输入时钟
- 22 .IB(sys_clk_n), //系统差分输入时钟
- 23 .O (sys_clk) //输出系统时钟
- 24 );
- 25
- 26 //计数器
- 27 always @ (posedge sys_clk or negedge sys_rst_n) begin
- 28 if(!sys_rst_n)
- 29 cnt <= 27'd0;
- 30 else if(cnt < 27'd5000_0000) //计数500ms
- 31 cnt <= cnt + 1'b1;
- 32 else
- 33 cnt <= 27'd0;
- 34 end
- 35
- 36 //每隔500ms就更改LED的闪烁状态
- 37 always @ (posedge sys_clk or negedge sys_rst_n) begin
- 38 if(!sys_rst_n)
- 39 led_ctrl <= 1'b0;
- 40 else if(cnt == 27'd5000_0000)
- 41 led_ctrl <= ~led_ctrl;
- 42 end
- 43
- 44 //根据按键的状态以及LED的闪烁状态来赋值LED
- 45 always @ (posedge sys_clk or negedge sys_rst_n) begin
- 46 if(!sys_rst_n)
- 47 led <= 2'b11;
- 48 else case(key)
- 49 2'b10 : //如果按键0按下,则两个LED交替闪烁
- 50 if(led_ctrl == 1'b0)
- 51 led <= 2'b01;
- 52 else
- 53 led <= 2'b10;
- 54 2'b01 : //如果按键1按下,则两个LED同时亮灭交替
- 55 if(led_ctrl == 1'b0)
- 56 led <= 2'b11;
- 57 else
- 58 led <= 2'b00;
- 59 2'b11 : //如果两个按键都未按下,则两个LED都保持点亮
- 60 led <= 2'b11;
- 61 default: ;
- 62 endcase
- 63 end
- 64
- 65 endmodule
复制代码代码的第27行的always块用于产生计数器,计时500ms。代码的第37行的always块功能是每隔500ms就给出led的闪烁状态控制信号。代码第45行的always块使用了一个case语句,来根据当前按键的输入值和led闪烁状态控制信号,来进行两个led的赋值。如果按键1按下,则两个LED交替闪烁;如果按键0按下,则两个LED同时亮灭交替;如果两个按键都未按下,则两个LED都保持点亮。
9.5 下载验证 连接开发板的下载器,然后连接电源线,最后将开发板的电源拨码开关按键往电源指示灯的方向拨动对开发板进行上电,上电成功后开发板的电源指示灯会亮蓝灯。在工程编译之后,将生成的bit文件下载到开发板中。下载完成之后,开发板上两个PL LED处于点亮状态。然后按下PL_KEY1,可以看到两个PL LED交替闪烁;按下PL_KEY2,可以看到两个PL的LED同时闪烁。如下图所示: 图 9.5.1 实验现象
|