具体见正点原子《达芬奇Pro之FPGA开发指南v2.1》
1.硬件介绍:按键
按键开关是一种电子开关,属于电子元器件类。
这里主要用轻触式按键开关。该开关只有在被施加压力时内部电路才会闭合导通,也就是说,只有按住按键时才有动作响应,松开没有。
(1)原理图
①电阻:限流,防止按键按下时电源直接接地造成电路短路。
②按下按键后输出高电平。
结合原理图可知,KEY0对应T4,KEY1对应T3,KEY2对应R6,KEY3对应T6。
管脚约束代码如下:
#------------------LED-----------------------------
set_property -dict {PACKAGE_PIN V9 IOSTANDARD LVCMOS15} [get_ports {led[0]}]
set_property -dict {PACKAGE_PIN Y8 IOSTANDARD LVCMOS15} [get_ports {led[1]}]
set_property -dict {PACKAGE_PIN Y7 IOSTANDARD LVCMOS15} [get_ports {led[2]}]
set_property -dict {PACKAGE_PIN W7 IOSTANDARD LVCMOS15} [get_ports {led[3]}]
#------------------按键----------------------------
set_property -dict {PACKAGE_PIN T4 IOSTANDARD LVCMOS15} [get_ports {key[0]}]
set_property -dict {PACKAGE_PIN T3 IOSTANDARD LVCMOS15} [get_ports {key[1]}]
set_property -dict {PACKAGE_PIN R6 IOSTANDARD LVCMOS15} [get_ports {key[2]}]
set_property -dict {PACKAGE_PIN T6 IOSTANDARD LVCMOS15} [get_ports {key[3]}]
这里采用了整合的写法,用-dict
实现,分开写举例如下:
set_property PACKAGE_PIN V9 [get_ports {led[0]}]
set_property IOSTANDARD LVCMOS15 [get_ports {led[0]}]
和整合写法相比,分开写要写的代码量较大,且重复了一些语句。
2.软件部分:主要代码
主要功能为:
按下KEY0 - LED从低到高流水
按下KEY1 - LED从高到低流水
按下KEY2 - LED间隔0.5s亮灭交替
按下KEY3 - LED常亮
module key_led(
//input
input sys_clk,
input sys_rst_n,
input [3:0] key,
//output
output reg[3:0] led
);
//parameter
parameter CNT_MAX = 25'd2500_0000;
//parameter CNT_MAX = 25'd25;
//reg define
reg [24:0] cnt;
reg [1:0] led_flag;
//***********************************
//** main code
//***********************************
//计数器计时0.5s
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt <= 25'd0;
else if(cnt < (CNT_MAX - 25'd1))
cnt <= cnt + 25'd1;
else
cnt <= 25'd0;
end
//LED状态切换标志位
// 0 1 2 3
// 00 01 10 11
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led_flag <= 2'd0;
else if(cnt == (CNT_MAX - 25'd1))
led_flag <= led_flag + 2'd1;
else
led_flag <= led_flag;
end
//LED控制
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led <= 4'b0000; //LED初始化全灭
else begin
case(key)
4'b1111: led <= 4'b0000; //未按下:LED常灭
4'b1110: begin //按下key0,从低到高流水灯
if(led_flag == 2'd0)
led <= 4'b0001;
else if(led_flag == 2'd1)
led <= 4'b0010;
else if(led_flag == 2'd2)
led <= 4'b0100;
else
led <= 4'b1000;
end
4'b1101: begin //按下key1,从高到低流水灯
if(led_flag == 2'd0)
led <= 4'b1000;
else if(led_flag == 2'd1)
led <= 4'b0100;
else if(led_flag == 2'd2)
led <= 4'b0010;
else
led <= 4'b0001;
end
4'b1011: begin //按下key2,4个LED一起交替闪烁
if(led_flag[0] == 1'b0)
led <= 4'b1111;
else
led <= 4'b0000;
end
4'b0111: begin //按下key3,4个LED一起亮
led <= 4'b1111;
end
default: ;
endcase
end
end
endmodule
①设置了变量led_flag
用来表示四个灯。
②用case
判断是哪个按键按下。
③设置了常量CNT_MAX
便于修改定时器定时时间。
3. 检测部分:仿真
仿真代码:
`timescale 1ns/1ns
module tb_key_led();
//parameter define
parameter CLK_PERIOD = 20; //20ns
parameter CNT_MAX = 25'd25; //仅用于仿真,500ns(20*25 = 500)
//reg define
reg sys_clk;
reg sys_rst_n;
reg [3:0] key;
//wire define
wire [3:0] led;
//产生时钟
always #(CLK_PERIOD/2) sys_clk = ~sys_clk;
//信号初始化
initial begin
sys_clk <= 1'b0;
sys_rst_n <= 1'b0;
key <= 4'b1111;
#200
sys_rst_n <= 1'b1;
#2000
key <= 4'b1110; //按下key0
#2000
key <= 4'b1101; //按下key1
#2000
key <= 4'b1011; //按下key2
#2000
key <= 4'b0111; //按下key3
#2000
key <= 4'b1111; //松开
end
//例化待测设计
key_led #(
.CNT_MAX (CNT_MAX)
)u_key_led(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.key (key),
.led (led)
);
endmodule
仿真结果:
①设置数字格式可以右击变量,选择Radix
,在列表里选择想要的数字格式即可(包括十六进制、十进制等)。