赞
踩
轻触式(回弹式)按键
略
蜂鸣器:
分为蜂鸣器按照结构原理不同可分为压电式蜂鸣器和电磁式蜂鸣器。 压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、 阻抗匹配器及共鸣箱、外壳等组成; 电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。
其他资料:1
发声原理:压电式蜂鸣器是利用压电效应原理工作的,当对其施加交变电压时它会产生机械振动发声; 电磁式蜂鸣器是接通电源后,振荡器产生的音频信号电流通过电磁线圈,使电磁线圈产生磁场, 振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声。
压电式蜂鸣器和电磁式蜂鸣器由于发音原理不同, 产生的声音信号也不一样。 压电式结构简单耐用但音调单一,适用于报警器等设备; 而电磁式由于音质好,所以多用于语音、音乐等设备。 本次实验使用的蜂鸣器为电磁式蜂鸣器。
蜂鸣器按照驱动方式不同又可分为有源蜂鸣器和无源蜂鸣器,其主要区别为蜂鸣器内部是否含有震荡源。一般的有源蜂鸣器内部自带了震荡源,只要通电就会发声。而无源蜂鸣器由于不含内部震荡源,需要外接震荡信号才能发声
其中,key_debounce是将输入的key信号消抖后输出,这个模块的输出信号是key_filter,key_beep则是简单的控制逻辑,检测到有下降沿则判断为一次按键按下,beep信号翻转,最后是顶层模块将两个模块例化到一块,顶层模块中连接的信号key_filter为wire型,这样的结构清晰且富有条例,而我自己写的模块的结构应该如下面这个一样的
关键模块:
消抖处理模块:电平跳变就进行计数,计数时间超过20ms说明此信号已经平稳,抖动信号已经过滤掉,将key信号直接赋值给key_filter即可。(我写的较为麻烦)
边沿检测模块:key信号是异步信号,所以要有个同步打拍子过程,然后进行边沿检测,
buf_res != buffer2 ,就说明有边沿出现。
人家的代码和我的代码对比:
module top_key_beep( input sys_clk , //系统时钟 input sys_rst_n , //系统复位,低电平有效 input key , //按键 output beep //蜂鸣器 ); //parameter define parameter CNT_MAX = 20'd100_0000; //消抖时间20ms //wire define wire key_filter ; //按键消抖后的值 //***************************************************** //** main code //***************************************************** //例化按键消抖模块 key_debounce #( .CNT_MAX (CNT_MAX) )u_key_debounce( .sys_clk (sys_clk), .sys_rst_n (sys_rst_n), .key (key), .key_filter (key_filter) ); //例化按键控制蜂鸣器模块 key_beep u_key_beep( .sys_clk (sys_clk), .sys_rst_n (sys_rst_n), .key_filter (key_filter), .beep (beep) ); endmodule / 按键消抖模块 module key_debounce( input sys_clk , input sys_rst_n , input key , //外部输入的按键值 output reg key_filter //按键消抖后的值 ); //parameter define parameter CNT_MAX = 20'd100_0000; //消抖时间20ms //reg define reg [19:0] cnt ; reg key_d0; //将按键信号延迟一个时钟周期 reg key_d1; //将按键信号延迟两个时钟周期 //***************************************************** //** main code //***************************************************** //对按键端口的数据延迟两个时钟周期 always @ (posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) begin key_d0 <= 1'b1; key_d1 <= 1'b1; end else begin key_d0 <= key; key_d1 <= key_d0; end end //按键值消抖 always @ (posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) cnt <= 20'd0; else begin if(key_d1 != key_d0) //检测到按键状态发生变化 cnt <= CNT_MAX; //则将计数器置为20'd100_0000, //即延时100_0000 * 20ns(1s/50MHz) = 20ms else begin //如果当前按键值和前一个按键值一样,即按键没有发生变化 if(cnt > 20'd0) //则计数器递减到0 cnt <= cnt - 1'b1; else cnt <= 20'd0; end end end //将消抖后的最终的按键值送出去 always @ (posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) key_filter <= 1'b1; //在计数器递减到1时送出按键值 else if(cnt == 20'd1) key_filter <= key_d1; else key_filter <= key_filter; end endmodule 按键控制逻辑 module key_beep( input sys_clk, input sys_rst_n, input key_filter, //消抖后按键值 output reg beep //蜂鸣器 ); //reg define reg key_filter_d0; //将消抖后的按键值延迟一个时钟周期 //wire define wire neg_key_filter; //按键有效脉信号 //***************************************************** //** main code //***************************************************** //捕获按键端口的下降沿,得到一个时钟周期的脉冲信号 assign neg_key_filter = (~key_filter) & key_filter_d0; //对按键端口的数据延迟一个时钟周期 always @ (posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) key_filter_d0 <= 1'b1; else key_filter_d0 <= key_filter; end //每次按键按下时,就翻转蜂鸣器的状态 always @ (posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) beep <= 1'b1; else if(neg_key_filter) //有效的一次按键被按下 beep <= ~beep; else beep <= beep; end endmodule
我的代码:
module key_beep( input sys_clk, input sys_rst_n, input key, output reg beep ); wire key_filter; reg buffer2, beep_flag; //例化按键消抖模块 key_filter key_filter_1( .key(key), .sys_clk(sys_clk), .sys_rst_n(sys_rst_n), .key_filter(key_filter) ); //边沿检测电路 always @(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) buffer2 <= 1'b0; else buffer2 <= key_filter; end always@(posedge sys_clk or negedge sys_rst_n)begin if(!sys_rst_n) beep_flag <= 1'b0; else if((key_filter == 1'b1)&&(buffer2 == 1'b0)) beep_flag <= 1'b1; //一个脉冲的按键标志信号 else beep_flag <= 1'b0; end always @(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) beep <= 1'b0; else if(beep_flag == 1'b1) //检测到一次按键 beep <= ~beep; else beep <= beep; //保持 end endmodule 按键消抖 module key_filter ( input key, input sys_clk, input sys_rst_n, output reg key_filter ); parameter CNT_MAX = 20'd1_000_000; //20ms reg [19:0] cnt; reg buffer1,buf_res; reg pose_flag,nege_flag; //ĺćĽććĺ? always@(posedge sys_clk or negedge sys_rst_n)begin if(!sys_rst_n) buffer1 <= 1'b0; else buffer1 <= key; end always@(posedge sys_clk or negedge sys_rst_n)begin if(!sys_rst_n) buf_res <= 1'b0; else buf_res <= buffer1; end //ä¸čžšć˛żćŁćľçľčˇ? always@(posedge sys_clk or negedge sys_rst_n)begin if(!sys_rst_n)begin pose_flag <= 1'b0; nege_flag <= 1'b0; end else if((buf_res == 1'b1)&&(buffer1 == 1'b0))begin pose_flag <= 1'b0; nege_flag <= 1'b1; end else if((buf_res == 1'b0)&&(buffer1 == 1'b1))begin pose_flag <= 1'b1; nege_flag <= 1'b0; end else begin pose_flag <= pose_flag; nege_flag <= nege_flag; end end //ćŁ?ćľĺ°čžšć˛żĺ°ąĺźĺ§čŽĄć? always@(posedge sys_clk or negedge sys_rst_n)begin if(!sys_rst_n) cnt <= 10'd0; //ćŁ?ćľĺ°čžšć˛żďźĺźĺ§ć¸éśčŽĄć? else if(((buf_res == 1'b1)&&(buffer1 == 1'b0))||((buf_res == 1'b0)&&(buffer1 == 1'b1))) cnt <= 10'd0; //else if((pose_flag == 1'b1)||(nege_flag == 1'b1)) //ĺŞćć螚沿觌ĺďźĺ°ąĺźĺ§čŽĄć°ďźčŽĄć°čśčż20msďźćĺłçćŻä¸ćŹĄćé? else if(cnt == CNT_MAX - 1'b1) cnt <= 10'd0; else cnt <= cnt + 1'd1; end //ĺ¤ć莥ć°ćśé´ćŻĺŚč˝čžžĺ?20ms always@(posedge sys_clk or negedge sys_rst_n)begin if(!sys_rst_n) key_filter <= 1'b0; else if((cnt == CNT_MAX - 1'b1)&&(nege_flag == 1'b1)) //莥ć°čžžĺ°1000ďźĺł20ms key_filter <= 1'b1; //ćä¸ćŹĄćéŽćä¸äş else if((cnt == CNT_MAX - 1'b1)&&(pose_flag == 1'b1)) key_filter <= 1'b0;//ćéŽĺˇ˛çťćžĺźäş? else key_filter <= key_filter; end endmodule
功能验证正确,但是我引入了较多的中间变量,而且输出的key_filter是与key信号消抖后的信号相反的,不过功能都验证正确了,也说明实现功能的方法可以有很多。
按键消抖模块,边沿检测模块,同步打拍子操作(解决亚稳态问题)
自锁:一直输出有效电平。
非自锁:仅输出一个周期的有效电平,需要自己对有效电平进行采集和保持。
参数重定义,我的CNT_MAX是在key_filter模块定义的,然后key_beep例化了此模块,然后我在这个key_beep模块加入parameter语句or采用参数传递的模式(#(.CNT_MAX(CNT_MAX)))都不行,编译不报错,但是仿真的时候,也就是例化key_beep模块的时候,一直给我提示了CNT_MAX 不能被overwrite这个错误,但是正点原子的代码也参数重定义了,他的没有错误,我暂时还不知道问题出在哪,待定,等那天知道答案了来补充吧。贴一个将参数传递的文字:
待补充.....
over
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。