按键控制LED实验
在写这篇文章之前我必须对我的错误表示深刻的道歉
因为我之前的文章自己也是边看边学给大家带来了大的困扰
抱歉抱歉
我们这里讲述一下综合和仿真的关系
其实我们更多的是应该关注仿真下得到的波形情况 然后分析
对于综合,综合的最大的目的还是看功耗,面积使用效率等问题 。而对于网表 我以前看的太重要了 该该放下了
本节实验任务是使用底板上的 PL_KEY0 和 PL_KEY1 按键来控制底板上的 PL_LED0 和 PL_LED1 两
个 LED 闪烁。没有按键被按下时,两个 LED 保持常灭;如果按键 PL_KEY0 被按下,则两个 LED 交替闪
烁;如果按键 PL_KEY1 被按下,则两个 LED 同时闪烁。
根据上面的流水灯的案例我们知道当我们给灯的输出口高电平时点亮LED 0 就是灭
这次实验我们使用的是当我们按下按键的时候才会进行模式的各种变化 虽然我还没有往下品读 但是我大胆的猜测应该不会在这么靠前的地方就讲述按键消抖的原理吧 毕竟按键消抖挺麻烦的 所以这里的设计只是长按
我们在此处设计的方向是 按键设置为低电平有效,好处自己想
而对于灯的控制,我们设置为1为亮 0为灭
长按 KEY0 按键时,key 信号值为 2’b10,此时需要根据 LED 状态控制信号(led_flag)来判断 LED 灯
的状态。led_flag 为低电平时,给 LED 灯信号(led)赋值 2’b01,表示 LED0 灯亮,LED1 灯灭;led_flag 为
高电平时给 LED 灯赋值 2’b10,表示 LED0 灯灭,LED1 灯亮。长按 KEY0 按键,随着 led_flag 信号的翻转,
LED 在 2’b01 与 2’b10 之间交替变化,实物观察的现象就是两个 LED 灯交替闪烁了。
长按 KEY1 按键时,key 信号值为 2’b01,此时需要根据 LED 状态控制信号(led_flag)来判断 LED 灯
的状态。led_flag 为低电平时,给 LED 灯信号(led)赋值 2’b11,表示 LED0 与 LED1 都亮灯;led_flag 为
高电平时给 LED 灯赋值 2’b00,表示 LED0 与 LED1 都灭灯。长按 KEY1 按键,随着 led_flag 信号的翻转,
LED 在 2’b11 与 2’b00 之间交替变化,实物观察的现象就是两个 LED 灯同时闪烁了。
因为对于整个时序的变化其实只有两种,相互交错的跳跃 所以在此处我们引入了一个局内的变量用来控制这两种不同的状态
下面讲述一下代码的基本逻辑
对于整个逻辑思考能力很有帮助 因为电路是并行结构
我们观察可以将电路剖析成3部分
第一部分 因为我们要用系统时钟
所以我们设置一个随着时间而动的计数器 计数25000000次 正好是0.5s
然后我们再根据我们的功能
第二段
因为要求我们在摁下后功能持续变化 那么控制单元 就设置随着计数器的变化而变化
接下来第三段
在按键key 下case if(led_flag)就行
下面是代码详解
module key_led(
input sys_clk , //系统时钟
input sys_rst_n , //系统复位,低电平有效
input [1:0] key , //按键
output reg [1:0] led //LED 灯
);
//parameter define
parameter CNT_MAX = 25'd2500_0000; //LED 灯闪烁频率
//reg define
reg [24:0] cnt; //计数器
reg led_flag; //LED 控制信号
//*****************************************************
//** 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
//每隔 500ms 就更改 LED 的闪烁状态
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led_flag <= 1'b0;
else if(cnt == (CNT_MAX - 25'd1))
led_flag <= ~led_flag;
end
//根据按键的状态以及 LED 的闪烁状态来赋值 LED
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led <= 2'b00;
else case(key)
2'b10 : //如果按键 0 被按下,则两个 LED 交替闪烁
if(led_flag == 1'b0)
led <= 2'b01;
else
led <= 2'b10;
2'b01 : //如果按键 1 被按下,则两个 LED 同时亮灭交替
if(led_flag == 1'b0)
led <= 2'b11;
else
led <= 2'b00;
2'b11 : //如果两个按键都未被按下,则两个 LED 都保持常灭
led <= 2'b00;
default: ;
endcase
end
endmodule
下面讲述的是testbench
`timescale 1ns / 1ns //仿真单位/仿真精度
module tb_key_led();
//parameter define
parameter CLK_PERIOD = 20; //时钟周期 20ns
//reg define
reg sys_clk;
reg sys_rst_n;
reg [1:0] key;
//wire define
wire [1:0] led;
//信号初始化
initial begin
sys_clk <= 1'b0;
sys_rst_n <= 1'b0;
key <= 2'b11;
#200
sys_rst_n <= 1'b1;
//key 信号变化
#200
key <= 2'b11; //两个 PL 按键都未被按下
#1000
key <= 2'b10; //按下按键 0
#2000
key <= 2'b11; //两个 PL 按键都未被按下
#1000
key <= 2'b01; //按下按键 1
end
//产生时钟
always #(CLK_PERIOD/2) sys_clk = ~sys_clk;
//例化待测设计
key_led u_key_led(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.key (key),
.led (led)
);
endmodule
评价是很简单