一、说明
实现平台:Vivado2018.3
二、内容
1. 使用按键KEY0和KEY_1分别控制LED0和LED1两个LED灯的闪烁方式;
2. 当没有按键按下时,两个LED灯均不亮;
3. 当按键KEY0按下后,LED0灯闪烁,当按键KEY0再次按下后则LED1灯闪烁,如此循环往复;
4. 当按键KEY1按下后,LED0和LED1交替闪烁,当按键KEY1再次按下后则LED0和LED1同时闪烁,如此循环往复;
5. 在内容3中若按键KEY1按下,则执行内容4操作;在内容4中若按键KEY0按下,则执行内容3操作。
三、步骤
(1)设计要求
- 时钟频率为50MHZ;
- 按键KEY0和KEY1;
- LED灯LED0和LED1。
(2)设计思路
本实验设计可分为四个模块:
- 计数器模块:用于计数LED灯闪烁间隔;
- LED闪烁状态控制模块:用于改变LED灯状态;
- 按键边缘检测模块:用于检测按键按下的状态;
- 按键控制闪烁实现模块:使用两个状态机,分别实现KEY0和KEY1的LED灯闪烁控制。
(3)具体实现
0.相关信号声明:
module key_led(
input sys_clk,
input sys_rst_n,
input [1:0] key,
output reg [1:0] led
);
reg [24:0] cnt;
reg led_ctrl;
reg [1:0] key_edg0; //边缘检测
reg [1:0] key_edg1;
reg [1:0] state_key0; //按键状态
reg [1:0] state_key1;
wire [1:0] key_en; //控制小灯闪烁
1. 计数器模块实现:
其中cnt计满为25_000_000,时钟频率为50MHZ,25_000_000/50_000_000 = 0.5s=500ms
//计数器
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
cnt <= 25'd0;
else if(cnt < 25'd25_000_000) //计数500ms
// else if(cnt < 25'd25) //仿真用
cnt <= cnt + 1'b1;
else
cnt <= 0;
end
2. LED闪烁状态控制模块:
//每隔500ms就更改LED的闪烁状态
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
led_ctrl <= 1'b0;
else if(cnt == 25'd25_000_000)
// else if(cnt == 25'd25) //仿真用
led_ctrl <= ~led_ctrl;
end
3.按键边缘检测模块:
其中使用该模块的原因主要是实现按键仅按一下即实现相关操作的功能,而无需一直按住按键才能执行相关操作。代码中检测上升沿或下降沿均可。
assign key_en[0] = (~key_edg0[0]) & key_edg1[0]; //按键0下降沿检测
assign key_en[1] = (~key_edg0[1]) & key_edg1[1]; //按键1下降沿检测
//PL_KEY边缘检测
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
key_edg0 <= 0;
key_edg1 <= 0;
end
else begin
key_edg0 <= key;
key_edg1 <= key_edg0;
end
end
4.按键控制闪烁实现模块:
此处使用两个状态机,状态机1控制KEY0实现对应的LED灯闪烁;状态机2控制KEY1实现对应的LED灯闪烁。
//两个状态机,根据按键KEY0来控制LED的闪烁
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
state_key0 <= 2'd0;
state_key1 <= 2'd0;
led <= 0;
end
else begin
case(state_key0) //状态机1
2'd0 : begin
led <= led; //默认保持原状态
state_key0 <= (key_en[0]) ? 2'd1:2'd0;
end
2'd1 : begin
led[0] <= (led_ctrl) ? 1'b1:1'b0; //LED0闪烁
led[1] <= 0; //LED1不亮
if (key_en[0])
state_key0 <= 2'd2; //切换到下一状态
else if(key_en[1]) //若按键1按下,则返回状态机2
state_key1 <= 2'd1;
else
state_key0 <= 2'd1;
end
2'd2 : begin
led[1] <= (led_ctrl) ? 1'b1:1'b0; //LED1闪烁
led[0] <= 0; //LED0不亮
if (key_en[0])
state_key0 <= 2'd1; //返回上一状态
else if(key_en[1]) //若按键1按下,则返回状态机2
state_key1 <= 2'd1;
else
state_key0 <= 2'd2;
end
default:state_key0 <= 2'd0;
endcase
case(state_key1) //状态机2
2'd0 : begin
state_key1 <= (key_en[1]) ? 2'd1:2'd0;
end
2'd1 : begin
led <= (led_ctrl) ? 2'b01:2'b10; //LED0和1交替闪烁
state_key1 <= (key_en[1]) ? 2'd2:2'd1; //切换到下一状态
if (key_en[1])
state_key1 <= 2'd2; //切换到下一状态
else if(key_en[0])begin //若按键0按下,则返回状态机1
state_key0 <= 2'd1;
state_key1 <= 2'd0;
end
else
state_key1 <= 2'd1;
end
2'd2 : begin
led <= (led_ctrl) ? 2'b11:2'b00; //LED0和1同时闪烁
if (key_en[1])
state_key1 <= 2'd1; //切换到上一状态
else if(key_en[0])begin //若按键0按下,则返回状态机1
state_key0 <= 2'd1;
state_key1 <= 2'd0;
end
else
state_key1 <= 2'd2;
end
default:state_key1 <= 2'd0;
endcase
end
end
5.testbenc仿真测试程序
此处我们模拟按键操作,分别按一下KEY0,再按一下KEY0,查看是否实现了LED0和LED1的切换闪烁操作;之后按KEY1,再按一下KEY1,查看时候实现了两个LED灯的交替以及同时闪烁;最后再仿真按下两次KEY0操作,查看是否实现了按键切换的操作。
其中为了防止仿真时间过长,主程序文件的cnt计数可以改的小一些,方便仿真。
`timescale 1ns / 1ns
module tb_key_led();
//输入
reg sys_clk;
reg sys_rst_n;
reg [1:0] key;
//输出
wire [1:0] led;
//信号初始化
initial begin
sys_clk = 1'b0;
sys_rst_n = 1'b0;
key = 2'b11;
#200
sys_rst_n = 1'b1;
#200
key = 2'b10;
#100
key = 2'b11;
#2000
key = 2'b10;
#100
key = 2'b11;
#2000
key = 2'b01;
#100
key = 2'b11;
#2000
key = 2'b01;
#100
key = 2'b11;
#2000
key = 2'b10;
#100
key = 2'b11;
#2000
key = 2'b10;
#100
key = 2'b11;
#2000
$finish;
end
//生成时钟
always #10 sys_clk = ~sys_clk;
//例化待测设计
key_led u_key_led(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.key (key),
.led (led)
);
endmodule
四、仿真结果
文章来源:https://www.toymoban.com/news/detail-817925.html
从仿真图可以看出,左边白框部分实现了LED0(01,00,01,00)和LED1(00,10,00,10)的闪烁功能;中间框部分则实现了LED等交替闪烁和同时闪烁的功能;最后右边蓝框部分,其实现功能和白框部分一样,实现了按键的切换实现LED灯闪烁功能,表明实验成功。文章来源地址https://www.toymoban.com/news/detail-817925.html
五、完整程序代码
//`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/06/20 08:28:10
// Design Name:
// Module Name: key_led
// Project Name:
// Target Devices:
// Tool Versions:
// Description:使用PL_KEY0和PL_KEY_1来控制底板上的PL_LED0和PL_LED1两个LED的闪烁方式。
// 没有按键按下时,两个LED不亮,若按键0按下,则LED0闪烁,若再次按下则LED1闪烁,再按
// 下则LED0闪烁,如此交替;若1按下,则两个LED交替闪烁,再次按下则两个LED同时闪烁,如此反复。
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module key_led(
input sys_clk,
input sys_rst_n,
input [1:0] key,
output reg [1:0] led
);
reg [24:0] cnt;
reg led_ctrl;
reg [1:0] key_edg0; //边缘检测
reg [1:0] key_edg1;
reg [1:0] state_key0; //按键状态
reg [1:0] state_key1;
wire [1:0] key_en; //控制小灯闪烁
//计数器
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
cnt <= 25'd0;
else if(cnt < 25'd25_000_000) //计数500ms
// else if(cnt < 25'd25) //仿真用
cnt <= cnt + 1'b1;
else
cnt <= 0;
end
//每隔500ms就更改LED的闪烁状态
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
led_ctrl <= 1'b0;
else if(cnt == 25'd25_000_000)
// else if(cnt == 25'd25) //仿真用
led_ctrl <= ~led_ctrl;
end
assign key_en[0] = (~key_edg0[0]) & key_edg1[0]; //按键0下降沿检测
assign key_en[1] = (~key_edg0[1]) & key_edg1[1]; //按键1下降沿检测
//PL_KEY边缘检测
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
key_edg0 <= 0;
key_edg1 <= 0;
end
else begin
key_edg0 <= key;
key_edg1 <= key_edg0;
end
end
//两个状态机,根据按键KEY0来控制LED的闪烁
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
state_key0 <= 2'd0;
state_key1 <= 2'd0;
led <= 0;
end
else begin
case(state_key0) //状态机1
2'd0 : begin
led <= led; //默认保持原状态
state_key0 <= (key_en[0]) ? 2'd1:2'd0;
end
2'd1 : begin
led[0] <= (led_ctrl) ? 1'b1:1'b0; //LED0闪烁
led[1] <= 0; //LED1不亮
if (key_en[0])
state_key0 <= 2'd2; //切换到下一状态
else if(key_en[1]) //若按键1按下,则返回状态机2
state_key1 <= 2'd1;
else
state_key0 <= 2'd1;
end
2'd2 : begin
led[1] <= (led_ctrl) ? 1'b1:1'b0; //LED1闪烁
led[0] <= 0; //LED0不亮
if (key_en[0])
state_key0 <= 2'd1; //返回上一状态
else if(key_en[1]) //若按键1按下,则返回状态机2
state_key1 <= 2'd1;
else
state_key0 <= 2'd2;
end
default:state_key0 <= 2'd0;
endcase
case(state_key1) //状态机2
2'd0 : begin
state_key1 <= (key_en[1]) ? 2'd1:2'd0;
end
2'd1 : begin
led <= (led_ctrl) ? 2'b01:2'b10; //LED0和1交替闪烁
state_key1 <= (key_en[1]) ? 2'd2:2'd1; //切换到下一状态
if (key_en[1])
state_key1 <= 2'd2; //切换到下一状态
else if(key_en[0])begin //若按键0按下,则返回状态机1
state_key0 <= 2'd1;
state_key1 <= 2'd0;
end
else
state_key1 <= 2'd1;
end
2'd2 : begin
led <= (led_ctrl) ? 2'b11:2'b00; //LED0和1同时闪烁
if (key_en[1])
state_key1 <= 2'd1; //切换到上一状态
else if(key_en[0])begin //若按键0按下,则返回状态机1
state_key0 <= 2'd1;
state_key1 <= 2'd0;
end
else
state_key1 <= 2'd2;
end
default:state_key1 <= 2'd0;
endcase
end
end
endmodule
到了这里,关于LED灯闪烁拓展实验——单按键控制LED灯不同闪烁方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!