新手上路
- 积分
- 37
- 金钱
- 37
- 注册时间
- 2023-10-14
- 在线时间
- 4 小时
|
本帖最后由 huochangling 于 2023-11-22 21:59 编辑
我是正在学习FPGA的新手小白,目前在B站正在跟着 QinQZ 的最新的真人出镜FPGA视频学习。本次分享是因为我跟着视频学到了触摸按键点灯,学到最后 QinQZ大大 提出了一个拓展训练:
通过触摸按键控制流水灯的运行,开发板上电时开发板上的LED灯实现流水灯效果,当按下触摸按键时,流水灯效果暂停,松开时保持此效果;当再次按下时,流水灯继续玉兴,松开时保持此效果。
先将思路分享如下:
1、通过加入一个输入端口:touch_key,还是利用视频中的打两拍,捕获 上升沿 的方式,表示触摸按键被按下。
2、在捕获 上升沿 后,做一个标志位,通过定义一个标志位 led_run_flag 的状态去控制 计数器 的计数的暂停和继续 从而达到控制流水灯状态。具体原理是每次检测到(touch_key)上升沿时,改变led_run_flag 的状态。
例如 led_run_flag =1'b0 的时候表示流水灯暂停运行
led_run_flag =1'b1 的时候表示流水灯开始运行。
代码分享:module flow_touch_led(
input sys_clk,
input sys_rst_n,
input touch_key,
output reg[1:0] led
);
//设置打两拍
reg touch_key_d0;
reg touch_key_d1;
wire post_touch_key;//声明捕获上升沿
reg led_run_flag; //定义标志位决定计数器是否工作,该标志位由捕获post_touch_key的上升沿决定
//定义25位计数器
reg [24:0] cnt;
//定义一个外部参数,便于修改
parameter CNT_MAX = 25'd25000000;//在仿真时25'd25为计时500ns
//post_touch_key是组合逻辑,因此使用assign语句
//采集上升沿
assign post_touch_key = ~touch_key_d1 & touch_key_d0;
//打两拍操作,在always语句中实现
always @ (posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
touch_key_d0 <= 1'b0;
touch_key_d1 <= 1'b0;
end
else begin
touch_key_d0 <= touch_key;
touch_key_d1 <= touch_key_d0;//实现打两拍的操作
end
end
//由post_touch_key控制标志位 led_run_flag 是否取反 从而控制计数器 继续or暂停计数
always @ (posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
led_run_flag <= 1'b0;//板子复位信号有效时,给led_run_flag默认为1'b0
else if(post_touch_key == 1'b1)//当捕获到上升沿时,标志位进行取反(因为该标志位为 1bit,直接取反即可)
led_run_flag <= ~led_run_flag;
else //当没有捕获到上升沿时,标志位保持不变
led_run_flag <= led_run_flag;
end
//计数器由led_run_flag的状态决定,计时0.5s
always @ (posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
cnt <= 25'd0;
else if(led_run_flag == 1'b1 & cnt < CNT_MAX)begin //led_run_flag的状态和cnt计数状态 相与为真的情况下 进行如下操作
if(cnt == CNT_MAX -25'd1) //如果计数器计数到了CNT_MAX -25'd1,那么就应该给其复位为25'd1
cnt <= 25'd1;
else //否则计数器正常进行累加计数
cnt <= cnt + 25'd1;
end
else
cnt <= cnt;
end
//实现流水灯的移位操作
always @ (posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
led <= 2'b10;
else if(cnt == CNT_MAX - 25'd1)
led <= {led[0],led[1]};
else
led <= led;
end
endmodule
仿真例化:
`timescale 1ns/1ns //声明: 仿真单位 / 仿真精度
module tb_flow_touch_led();
parameter CLK_PERIOD = 20;
reg sys_clk; //时钟周期为20ns,每隔10ns翻转一次即可
reg sys_rst_n;
reg touch_key;
wire [1:0] led;
initial begin //赋初始值
sys_clk <= 1'b0;
sys_rst_n <= 1'b0;
touch_key <= 1'b0;
#200
sys_rst_n <= 1'b1;
#1000 //延迟1000ns后,触摸按键被按下
touch_key <=1'b1;//触摸按键被按下后变为高电平1
#2000 //延迟2000ns后,松开触摸按键
touch_key <=1'b0;//触摸按键被松开后变为低电平0
//重复按下触摸按键和松开触摸按键的操作
#1000 //延迟1000ns后,触摸按键被按下
touch_key <=1'b1;//触摸按键被按下后变为高电平1
#2000 //延迟2000ns后,松开触摸按键
touch_key <=1'b0;//触摸按键被松开后变为低电平0
//重复按下触摸按键和松开触摸按键的操作
#1000 //延迟1000ns后,触摸按键被按下
touch_key <=1'b1;//触摸按键被按下后变为高电平1
end
always #(CLK_PERIOD/2) sys_clk = ~sys_clk; //周期为20ns,除以2即为:每隔10ns翻转一次
flow_touch_led u_flow_touch_led
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.touch_key (touch_key),
.led (led )
);
endmodule
|
|