verilog fpga 按键控制蜂鸣器发声并能改变占空比

img

图中48行为什么加了k&&后 add_cnt输出变0了(k是1)

img


想实现按下key0时有源蜂鸣器发声,按下key1时有源蜂鸣器发声占空比改变
我按下key0蜂鸣器能发声,用assign add_cnt = ~key_value1;时按下key1能改变占空比,但是松手时 会有点问题
然后我就想加个K但是为什么加了K后按key1没有反应了。


`timescale 1ns / 1ps

module top_key_beep(
  input sys_clk, //时钟信号 50Mhz
  input sys_rst_n, //复位信号
  input[1:0] key, //按键信号
  output beep //蜂鸣器控制信号
  );
  
  //wire define
  wire key_value0;
  wire key_flag0;
  wire key_value1;
  wire key_flag1;
  //*****************************************************
  //** main code
  //*****************************************************
  
  //例化按键消抖模块
  key_debounce u_key_debounce(
 .sys_clk (sys_clk),
 .sys_rst_n (sys_rst_n),
 
 .key (key[0]),
 .key_flag0 (key_flag0),
 .key_value0 (key_value0)
 );
 
 key_debounce2 u_key_debounce2(
 .sys_clk (sys_clk),
 .sys_rst_n (sys_rst_n),
 
 .key1 (key[1]),
 .key_flag1 (key_flag1),
 .key_value1 (key_value1)
 );
  //例化蜂鸣器控制模块
 beep_control u_beep_control(
 .sys_clk (sys_clk),
 .sys_rst_n (sys_rst_n),
 
 .key_flag0 (key_flag0), 
 .key_value0 (key_value0),
 .key_flag1 (key_flag1), 
 .key_value1 (key_value1),

 .beep (beep)
 );
 
 endmodule
 module key_debounce(
 input sys_clk, //外部 50M 时钟
 input sys_rst_n, //外部复位信号,低有效
 input  key, //外部按键输入
 output reg key_flag0, //按键数据有效信号
 output reg key_value0, //按键消抖后的数据 
 output reg k 
 );
 
 //reg define 
 reg [31:0] delay_cnt;
 reg[1:0] key_reg;

 //*****************************************************
 //** main code
 //*****************************************************
 always @(posedge sys_clk or negedge sys_rst_n) begin
   if (!sys_rst_n) begin
     key_reg[0] <= 1'b1;
     delay_cnt <= 32'd0;
   end
   else begin
     key_reg[0] <= key;
     if(key_reg[0] != key) //一旦检测到按键状态发生变化(有按键被按下或释放)
     delay_cnt <= 32'd1000000; //给延时计数器重新装载初始值(计数时间为 20ms)
     //delay_cnt <= 32'd4; //仅用仿真
     else if(key_reg[0] == key) begin //在按键状态稳定时,计数器递减,开始 20ms 倒计时
     if(delay_cnt > 32'd0)
     delay_cnt <= delay_cnt - 1'b1;
     else
     delay_cnt <= delay_cnt;
     end 
   end 
 end

 always @(posedge sys_clk or negedge sys_rst_n) begin
   if (!sys_rst_n) begin
     key_flag0 <= 1'b0;
     key_value0 <= 1'b1;
     k<=  1'b0; 
   end
   else begin
     if(delay_cnt == 32'd1) begin //当计数器递减到 1 时,说明按键稳定状态维持了 20ms
       key_flag0 <= 1'b1; //此时消抖过程结束,给出一个时钟周期的标志信号
       key_value0 <= key; //并寄存此时按键的值
//       k<= ~k;
         k<=1'b1;
     end
     else begin
       key_flag0 <= 1'b0;
       key_value0<= key_value0;
       k<=k;
     end 
   end 
 end
 
 endmodule
 module key_debounce2(
 input sys_clk, //外部 50M 时钟
 input sys_rst_n, //外部复位信号,低有效
 input  key1, //外部按键输入
 output reg key_flag1, //按键数据有效信号
 output reg key_value1 //按键消抖后的数据
 
 );
 
 //reg define 
 reg [31:0] delay_cnt;
 reg[1:0] key_reg;

 //*****************************************************
 //** main code
 //*****************************************************
 always @(posedge sys_clk or negedge sys_rst_n) begin
   if (!sys_rst_n) begin
    key_reg[1] <= 1'b1;
     delay_cnt <= 32'd0;
   end
   else begin
     key_reg[1] <= key1;
     if(key_reg[1] != key1) //一旦检测到按键状态发生变化(有按键被按下或释放)
     delay_cnt <= 32'd1000000; //给延时计数器重新装载初始值(计数时间为 20ms)
     //delay_cnt <= 32'd4; //仅用仿真
     else if(key_reg[1] == key1) begin //在按键状态稳定时,计数器递减,开始 20ms 倒计时
     if(delay_cnt > 32'd0)
     delay_cnt <= delay_cnt - 1'b1;
     else
     delay_cnt <= delay_cnt;
     end 
   end 
 end

 always @(posedge sys_clk or negedge sys_rst_n) begin
   if (!sys_rst_n) begin
     key_flag1 <= 1'b0;
     key_value1<= 1'b1;   
   end
   else begin
     if(delay_cnt == 32'd1) begin //当计数器递减到 1 时,说明按键稳定状态维持了 20ms
       key_flag1 <= 1'b1; //此时消抖过程结束,给出一个时钟周期的标志信号
       key_value1 <= key1; //并寄存此时按键的值
       
     end
     else begin
       key_flag1 <= 1'b0;
       key_value1<= key_value1;
     end 
   end 
 end
 
 endmodule
  module beep_control(
 //input
 input sys_clk, //系统时钟
 input sys_rst_n, //复位信号,低电平有效
 
 input key_flag0, //按键有效信号
 input key_value0, //消抖后的按键信号 
 input key_flag1, //按键有效信号
 input key_value1, //消抖后的按键信号 
 input k,
 output reg beep //蜂鸣器控制信号 
 );
 parameter TIM1_PWM = 2_400_000;
  parameter TIM1_100MS = 4_000_000;
  reg [21:0] cnt;
  wire add_cnt;
  wire end_cnt;
 //*****************************************************
 //** main code
 //*****************************************************
 always @ (posedge sys_clk or negedge sys_rst_n) begin
   if(!sys_rst_n)
      beep <= 1'b0;
   else if(key_flag0 && (~key_value0)) //判断按键是否有效按下
      beep <= ~beep; 
//  else if(k==1'b1 &&( add_cnt && cnt ==TIM1_PWM-1))
   else if( add_cnt && cnt ==TIM1_PWM-1) 
      beep<= 1'b1;
   else if(end_cnt)
      beep<= 1'b0;
   else if(k==1'b1 && !add_cnt)
      beep<= 1'b1;
 end
 

 
 always @ (posedge sys_clk or negedge sys_rst_n) begin
   if(!sys_rst_n)
     cnt<=0;
   else if(add_cnt)begin
     if(end_cnt)
       cnt<=0;
     else
       cnt<=cnt + 1;
   end
 end
 
 assign add_cnt = k && (~key_value1);
//assign add_cnt = ~key_value1;
 assign end_cnt = add_cnt && cnt == TIM1_100MS-1;
 

   
 

 endmodule

以下内容由CHATGPT及阿里嘎多学长共同生成、有用望采纳:

首先,关于加了 k&& 后 add_cnt 输出变 0 的问题,是因为当 k=1 时,只有 key_value1=0 才能使 add_cnt=1,否则 add_cnt=0,所以在这种情况下,add_cnt 会一直为 0。

至于按下 key1 松手后的问题,可能是因为没有对计数器进行清零,导致松手后计数器仍在继续计数,进而影响占空比的改变。

以下是修改后的代码,包括对 add_cnt 的修改和对计数器的清零:

module beep_control(
    //input
    input sys_clk, //系统时钟
    input sys_rst_n, //复位信号,低电平有效
    input key_flag0, //按键有效信号
    input key_value0, //消抖后的按键信号 
    input key_flag1, //按键有效信号
    input key_value1, //消抖后的按键信号 
    output reg beep //蜂鸣器控制信号 
);
    parameter TIM1_PWM = 2_400_000;
    parameter TIM1_100MS = 4_000_000;
    reg [21:0] cnt;
    wire add_cnt;
    wire end_cnt;
    reg last_k;
    reg last_key_value1;
    reg [21:0] duty_cnt;

    //*****************************************************
    //** main code
    //*****************************************************
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if (!sys_rst_n) begin
            beep <= 1'b0;
            duty_cnt <= 22'h0;
            last_k <= 1'b0;
            last_key_value1 <= 1'b0;
        end
        else begin
            if (key_flag0 && (~key_value0)) //判断按键是否有效按下
                beep <= ~beep; 
            else if (k && ~last_k && add_cnt) begin
                duty_cnt <= duty_cnt + 1;
                if (duty_cnt >= TIM1_100MS) begin
                    duty_cnt <= 0;
                    beep <= ~beep;
                end
            end
            last_k <= k;
            if (key_value1 != last_key_value1) begin
                last_key_value1 <= key_value1;
                if (key_value1 == 1'b1)
                    duty_cnt <= 0;
            end
        end
    end

    assign add_cnt = k && (~key_value1);

    assign end_cnt = add_cnt && (cnt == TIM1_100MS-1);

    always @ (posedge sys_clk or negedge sys_rst_n) begin
        if (!sys_rst_n)
            cnt <= 0;
        else if (add_cnt) begin
            if (end_cnt)
                cnt <= 0;
            else
                cnt <= cnt + 1;
        end
        else
            cnt <= 0;
    end
endmodule

其中加入了一个 duty_cnt 计数器,用于计算每个占空比的时间,并在达到对应时间时改变蜂鸣器的状态。

同时,还加入了一个 last_key_value1 记录上一次 key_value1 的值,用于检测 key_value1 的变化并清空计数器。