Verilog实现4位按键分别控制蜂鸣器发出不同音阶(未完成,请指导)

实验任务:

使用板载4位独立按键,进行4位按键消抖检测,当没有按键按下时不响,按下则发出声响,分别为 DO RE MI FA。

实验思路

还是有两个part,一个part用来检测按键是否按下,输入key_in,输出key_out,为第几位。
第二个part用来运行蜂鸣器,根据按键值case,未按下的,不响,按下就DO RE MI FA四个输出。

4位按键消抖

关于这部分,已经在之前一篇博客中写过了,
Verilog实现4位按键消抖,分别控制一个LED
所以这里重点在于怎么利用按键控制蜂鸣器。

蜂鸣器控制

[3:0] beep_ctrl里面就的4位分别对应一位按键,为1即为该按键按下。

如果只是像下面这么改,其实是没有用的,因为beep_ctrl中是一个脉冲信号,只能在一个clk的时间让freq等于四个值中的一个,其他时间都是等于0,根本不能响,所以需要将这个脉冲信号转换为电平信号。

//音阶切换,根据cnt_500ms来切换freq_data的值
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        freq_data <= 0;
    else    case(beep_ctrl)
        4'd0:   freq_data <= 0 ;
        4'd1:   freq_data <= RE;
        4'd2:   freq_data <= MI;
        4'd4:   freq_data <= FA;
        4'd8:   freq_data <= SO;
        // 4'd5:   freq_data <= LA;
        // 4'd6:   freq_data <= XI;
        default:freq_data <= 0;
    endcase
end

笔者确实不会了,附上现在的代码。写崩溃了,这么简单的程序都不会,我。。。。。请路过的大佬指导

module key_beep
#(
    parameter KEY_20MS = 999_999,
    parameter TIME_500MS = 25'd24_999_999, //0.5s 计数值
    parameter DO = 18'd190839 , //"哆"音调分频计数值(频率 262)
    parameter RE = 18'd170067 , //"来"音调分频计数值(频率 294)
    parameter MI = 18'd151514 , //"咪"音调分频计数值(频率 330)
    parameter FA = 18'd143265 , //"发"音调分频计数值(频率 349)
    parameter SO = 18'd127550 , //"梭"音调分频计数值(频率 392)
    parameter LA = 18'd113635 , //"拉"音调分频计数值(频率 440)
    parameter XI = 18'd101214   //"西"音调分频计数值(频率 494)
)
(
    input   wire        sys_clk     ,  
	input   wire        sys_rst_n   ,  
	input   wire [3:0]  key_in		,  
	
	output  reg         beep	
);

reg key_rst;//检测是否有按键按下,并且同步到时钟下

always @(posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n)
		key_rst <= 1'b1;
	else
		key_rst <= key_in[3] & key_in[2] & key_in[1] & key_in[0];//将四个按键的值存进,只要有一位被按下就会发生跳变
end

reg key_rst_reg;//对key_rst进行延一拍

always @(posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n)
		key_rst_reg <= 1'b1;
	else
		key_rst_reg <= key_rst;
end

//检测下降沿操作
wire key_en = (~key_rst) & key_rst_reg;

reg [19:0]	cnt_20ms;//20ms计数器

//cnt_20ms 计数器
always@(posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n)
		cnt_20ms <= 20'd0;
	else if(key_en)		 //检测到抖动
		cnt_20ms <= 20'd0;
	//else if(cnt_20ms == CNT_MAX )
	//	cnt_20ms <= CNT_MAX;	        //计数到最大值就保持
	else						
		cnt_20ms <= cnt_20ms + 20'd1;	
end

reg [3:0] key_flag;//作为按键检测标志位

always@(posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n)
		key_flag <= 4'b1111;
	else	if(cnt_20ms == KEY_20MS)//每20ms保存一次键值	
		key_flag <= key_in;
end

reg [3:0] key_flag_reg;//延一拍

always@(posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n)
		key_flag_reg <= 4'b1111;
	else	
		key_flag_reg <= key_flag;
end

//保存按键值
wire [3:0] beep_ctrl = (~key_flag) & key_flag_reg;



//蜂鸣器部分代码

reg [24:0]  cnt         ;//0.5s计数
reg [17:0]  freq_cnt    ;//音调计数器
reg [2:0]   cnt_500ms   ;//0.5s个数计数器
reg [17:0]  freq_data   ;//音调分频计数值

wire [16:0] duty_data   ;//占空比计数值

//设置占空比 50%
assign duty_data = freq_data >> 1;//使用移位来实现除2

//0.5s计数器
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
		cnt <= 25'b0;
	else	if(cnt == TIME_500MS)
		cnt <= 25'b0;
	else	
		cnt <= cnt + 1'b1;	
end

reg	[3:0] beep_ctrl_dp;

//将脉冲信号转换为电平信号
always @(posedge sys_clk or negedge sys_rst_n ) begin
    if(!sys_rst_n)
		beep_ctrl_dp <= 4'b0000;
	else	if(cnt ==  TIME_500MS)
		beep_ctrl_dp <= 4'b0000;
	else 	if(beep_ctrl != beep_ctrl_dp)
		beep_ctrl_dp <= beep_ctrl;
end


//音阶切换,根据cnt_500ms来切换freq_data的值
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        freq_data <= 0;
    else    case(beep_ctrl_dp)
        4'd0:   freq_data <= 0 ;
        4'd1:   freq_data <= RE;
        4'd2:   freq_data <= MI;
        4'd4:   freq_data <= FA;
        4'd8:   freq_data <= SO;
        // 4'd5:   freq_data <= LA;
        // 4'd6:   freq_data <= XI;
        default:freq_data <= 0;
    endcase
end

//freq_cnt:当计数到音阶计数值或跳转到下一音阶时,开始重新计数
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        freq_cnt <= 18'd0;
    else    if(freq_cnt == freq_data || cnt == TIME_500MS)
        freq_cnt <= 18'd0;
    else
        freq_cnt <= freq_cnt+ 1'b1;
end

//beep:输出蜂鸣器波形
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        beep <= 1'b0;
    else    if(freq_cnt >= duty_data)
        beep <= 1'b1;
    else
        beep <= 1'b0;
end


endmodule

疑问

//将脉冲信号转换为电平信号
always @(posedge beep_ctrl or posedge cnt or negedge sys_rst_n ) begin
    if(!sys_rst_n)
		beep_ctrl_dp <= 4'b0000;
	else	if(beep_ctrl != beep_ctrl_dp)//只响0.5s
	 	beep_ctrl_dp <= 4'b0000;
	else	if(cnt ==  TIME_500MS)
		beep_ctrl_dp <= beep_ctrl;
end

Error (10200): Verilog HDL Conditional Statement error at keep_beep.v(121): cannot match operand(s) in the condition to the corresponding edges in the enclosing event control of the always construct
报错如下,也没搞懂什么意思。
一篇介绍这个错误的。没看懂

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值