目录
Vivado 下按键控制 LED 实验
1、简介
2、实验环境
3、实验任务
4、硬件设计
5、程序设计
5.1、按键控制 led 模块代码
5.2、Vivado 仿真验证
5.2.1、Testbench 模块代码如下:
5.2.2、Vivado 仿真验证
6、下载验证
Vivado 下按键控制 LED 实验
按键是常用的一种控制器件。生活中我们可以见到各种形式的按键,由于其结构简单,成本低廉等特点,在家电、数码产品、玩具等方面有广泛的应用。本章我们将介绍如何使用按键控制多个 LED 的亮灭。
1、简介
按键开关是一种电子开关,属于电子元器件类。我们的开发板上有两种按键开关:第一种是本实验所使用的轻触式按键开关(如下图1.1 ),简称轻触开关。使用时以向开关的操作方向施加压力使内部电路闭合接通,当撤销压力时开关断开,其内部结构是靠金属弹片受力后发生形变来实现通断的;第二种是自锁按键(如下图1.2 ),自锁按键第一次按下后保持接通,即自锁,第二次按下后,开关断开,同时开关按钮弹出来,开发板上的电源键就是这种开关。
2、实验环境
- Windows 10 64 位
- vivado 2020.2
- Xinlinx 黑金 FPGA 开发板(AX7A035t 开发板、AX7A100t 开发板、AX7A200t 开发板)
3、实验任务
使用 Xinlinx 黑金 FPGA 开发板上的四个按键控制四个 LED 灯。不同按键按下时,四个 LED 灯显示不同效果。
4、硬件设计
如图 3.1 所示,本实验使用四个按键开关控制四个 LED 灯。
如上图所示,开发板上的 4 个按键未按下时,输出高电平,按下后,输出低电平。
5、程序设计
我们程序设计最终实现的效果为:无按键按下时,LED 灯全灭;按键 1 按下时,LED 灯显示自右向左的流水效果;按键 2 按下时,LED 灯显示自左向右的流水效果;按键 3 按下时,四个 LED 灯同时闪烁;按键 4 按下时,LED 灯全亮。
LED 在流水效果和闪烁效果在时间间隔均为 0.2 秒,因此需要在程序中定义一个 0.2s 的计数器,即每隔 0.2s,状态计数器加一。根据当前按键的状态选择不同的显示模式,不同的显示模式下四个 led 灯的亮灭随状态计数器的值改变,从而呈现出不同的显示效果。
5.1、按键控制 led 模块代码
按键控制 led 模块的代码如下所示:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/05/10 20:25:57
// Design Name:
// Module Name: key_led
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
//实验任务:按键控制LED灯
//使用开发板上的四个按键控制四个 LED 灯。不同按键按下时,四个 LED 灯显示不同效果。module key_led(
// input sys_clk, //50MHz系统时钟(一个周期是20ns:1/50MHz=0.02us=20ns)//differential system clocks //200MHz系统时钟(一个周期是5ns:1/200MHz=0.005us=5ns)input sys_clk_p, // Differential input clock 200Mhzinput sys_clk_n, // Differential input clock 200Mhzinput sys_rst_n, //reset ,low active //系统复位,低电平有效input [3:0] key, //按键输入信号output reg [3:0] led //LED输出信号);//define the time counter
reg [26:0] cnt;
reg [1:0] led_control;//*********差分时钟这么处理***START******************
wire sys_clk;
//差分输入时钟缓冲器-黑金FPGA
IBUFDS sys_clk_ibufgds //generate single end clock
(.O (sys_clk ), //Differential clock converted to single terminal clock.I (sys_clk_p ),.IB (sys_clk_n )
);
//*********差分时钟这么处理*****END*******************//用于计数0.2s的计数器.
//(1/50MHz=0.02us=20ns)(0.2s需计数:0.2s/20ns=10_000_000次)
//(1/200MHz=0.005us=5ns)(0.2s需计数:0.2s/5ns=40_000_000次)
always @(posedge sys_clk or negedge sys_rst_n) beginif (!sys_rst_n)cnt <= 26'd0;//else if (cnt < 26'd9_999_999)else if (cnt < 26'd39_999_999)//else if (cnt < 26'd9) //仅用于仿真cnt <= cnt + 1;elsecnt <= 0;
end//用于led灯状态的选择
always @(posedge sys_clk or negedge sys_rst_n) beginif (!sys_rst_n)led_control <= 2'b00;else if (cnt == 26'd39_999_999)//else if (cnt == 26'd9) //仅用于仿真led_control <= led_control + 1'b1;elseled_control <= led_control;
end//识别按键,切换显示模式
always @(posedge sys_clk or negedge sys_rst_n) beginif (!sys_rst_n) beginled <= 4'b0000;endelse if (key[0]==0) //按键1 按下时,从右向左的流水灯效果case(led_control)2'b00 : led <= 4'b1000;2'b01 : led <= 4'b0100;2'b10 : led <= 4'b0010;2'b11 : led <= 4'b0001;default : led <= 4'b0000;endcaseelse if (key[1]==0) //按键2 按下时,从左向右的流水灯效果case(led_control)2'b00 : led <= 4'b0001;2'b01 : led <= 4'b0010;2'b10 : led <= 4'b0100;2'b11 : led <= 4'b1000;default :led <= 4'b0000;endcaseelse if (key[2]==0) //按键3 按下时,LED灯闪烁case(led_control)2'b00 : led <= 4'b1111;2'b01 : led <= 4'b0010;2'b10 : led <= 4'b1111;2'b11 : led <= 4'b0000;default :led <= 4'b0000;endcaseelse if (key[3]==0) //按键4 按下时,LED灯全亮led <= 4'b1111;elseled <= 4'b0000; //无按键按下时,LED全熄灭
endendmodule
代码主要分为三个部分,第 49 至 61 行对系统时钟计数,当计数时间达 0.2s 时,计数器清零,同时使led_control 在四个状态(00,01,10,11)内依次变化。第 74 至 107 行利用 case 语句实现对按键状态的检测,当不同的按键按下时,led 随着 led_control 的变化,被赋予不同的值。仿真时我们设为每 10 个时钟周期,进行一次状态转换一次,如代码第 57 和 68 行。
大家可以发现,本次实验和流水灯实验计数时间都是0.2s,本次实验的计数器最大可以计数到39_999_999,而流水灯实验中计数器的值最大可以计数到 40_000_000。事实上,这两个实验计数器都是从 0 开始计数的,
本次实验从 0 计数到 39_999_999,需要 40_000_000 个时钟周期,而系统时钟为 5ns,所以计数的时间为 0.2s, 而流水灯实验从 0 计数到 40_000_000 需要 40_000_001 个时钟周期,因此其计数时间实际上比 0.2s 要多出 5ns。
5.2、Vivado 仿真验证
为了验证我们的程序,我们使用 Vivado 对代码进行仿真。
5.2.1、Testbench 模块代码如下:
//`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/05/10 21:08:42
// Design Name:
// Module Name: tb_key_led
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//`timescale 1ns / 1ns //定义仿真时间单位为1ns,仿真时间精度为1ns
module tb_key_led(); //测试模块//parameter T = 20; //时钟周期为20ns
parameter T = 5; //时钟周期为5ns// Inputs
reg [3:0] key; //按键信号
//reg sys_clk; //时钟信号
reg sys_clk_p; //时钟信号
wire sys_clk_n;
reg sys_rst_n; //复位信号// Outputs
wire [3:0] led;//***************************************
//** main code
//***************************************initial beginkey <=4'b1111;//按键初始状态全为断开
// sys_clk <=1'b0; //初始时钟为低电平sys_clk_p <=1'b0; //初始时钟为低电平sys_rst_n <=1'b0; //复位信号初始为低电平
#T sys_rst_n <=1'b1; //一个时钟周期后复位信号拉高key[0] <=0; //0.6s时按下按键1
#800 key[0] <=1;key[1] <=0; //0.8s后松开按键1,按下按键2
#800 key[1] <=1;key[2] <=0; //0.8s后松开按键2,按下按键3
#800 key[2] <=1;key[3] <=0; //0.8s后松开按键3,按下按键4
#800 key[3] <=1; //0.8s后松开按键4end//always #(T/2) sys_clk <= ~sys_clk; //每半个周期后,电平取反一次。
always #(T/2) sys_clk_p <= ~sys_clk_p; //每半个周期后,电平取反一次。
assign sys_clk_n=~sys_clk_p;//实例化key_led模块
key_led u_key_led(
// .sys_clk (sys_clk),.sys_clk_p (sys_clk_p), .sys_clk_n (sys_clk_n),.sys_rst_n (sys_rst_n),.key (key),.led (led)
);endmodule
5.2.2、Vivado 仿真验证
仿真波形如下:
观察代码,结合波形分析可知。43 至 49 行代码为对时钟信号、复位信号、按键信号赋初始值,默认为按键全断开。在第一个周期按下按键 key0(kye[0]由高电平变为低电平),可观察到 led3 至 led0 依次点亮,呈现自右向左的流水效果;按键 key0 断开的同时按下按键 key1,可观察到 led0 至 led3 依次点亮,呈现自左向右的流水效果;按键 key1 断开的同时按下按键 key2,可观察到 led0 至 led3 呈现闪烁效果;按键 key2 断开的同时按下按键 key3,可观察到 led0 至 led3 保持全亮。
6、下载验证
编译工程并生成比特流.bit 文件后,接下来我们下载比特流.bit 文件,验证按键控制 LED 灯的功能。程序下载完成后,我们按 KEY0、KEY1、KEY2 和 KEY3,就可以看到按键对应的实验现象了。
详细步骤见: Vivado 下 LED 流水灯实验_OliverH-yishuihan的博客-CSDN博客 中的 “4.6 下载和调试”、“4.7、FLASH 程序固化”