正点原子v1-蜂鸣器-爱代码爱编程
实验任务:按键按下切换蜂鸣器开关状态
module key_debounce(
input clk,
input rst_n,
input key,
output reg key_value,
output reg key_flag
);
reg key_reg; //存储按键状态的寄存器,用来判别按键是处于消抖起始时间点
reg [19:0]delay_cnt; //用来延时的计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin //复位信号生效
key_reg <= 1'b1; //寄存器里存储嘎电平,也就是没按下是的电平
delay_cnt <= 20'd0; //计数器清零
end
else begin
key_reg <=key; //存储现在的按键值
if(key!=key_reg) //如果按键状态发生变化
delay_cnt <= 20'd1000_000; //计数值满载开始倒计时
else begin //还没有到开始消抖的时间点
if(delay_cnt > 20'd0) //已经满载了
delay_cnt <= delay_cnt - 1; //开始倒计时
else
delay_cnt <= 20'd0; //根本就没到时间,保持原样
end
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin //复位信号生效
key_value <= 1'b1; //初始没按下默认为高电平
key_flag <= 1'b0; //消抖标志默认为零
end
else begin
if(delay_cnt == 20'd1)begin //倒计时结束 为了和初始的0区分开来
key_flag <= 1'b1; //消抖完成,标志为1
key_value <= key; //小豆成功的按键值取出
end
else begin //倒计时没有结束
key_flag <= 1'b0; //完成标志位还是为0
key_value <= key_value; //按键值保持不变
end
end
end
endmodule
module beep_control(
input clk,
input rst_n,
input key_flag,
input key_value,
output reg beep
);
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
beep <= 1'b1; //初始为鸣叫状态
else
if(key_flag&(~key_value)) //消抖标志为1且按键被按下
beep<=~beep;
else
beep = beep;
end
endmodule
module top_key_beep(
input clk,
input rst_n,
input key,
output beep
);
wire key_value;
wire key_flag;
key_debounce u_key_debounce(
.clk (clk),
.rst_n (rst_n),
.key (key ),
.key_value (key_value),
.key_flag (key_flag)
);
beep_control u_beep_control(
.clk (clk ),
.rst_n (rst_n ),
.key_flag (key_flag),
.key_value (key_value),
.beep (beep)
);
endmodule
本次模块中比较重要的在于消抖模块,消抖模块的思路就是首先判断开始消抖的时间,等消抖点开始倒计时开始然后倒计时结束之后,判断消抖值,产出消抖标志,输送给下一个模块。
1.需要注意的是不是所有的if后面都要加begin和end但是比begin和end的是在同一个操作内进行的不能横跨多个,除非是always后面的begin和end。
2.对于头文件的例化可以选择输出生成新模块,在PDF头文件里面进行操作,也可以将各模块的输入输出全部复制到头文件里面之后进行相应的操作,首先删去定义module这个单词,然后把所有的input和output换成点。再把相应的输入进来的信号放在括号里面,跟在原变量之后,如果它只是中间的寄存器变量,那么需要在头文件里面进行wire变量的定义之后再进行例化,最后把头文件设置成顶层文件进行编译。