FPGA实战(三)按键控制蜂鸣器实验

来自正点原子的学习笔记
上一个博客是这个哦可以去看看
链接: FPGA实战(二)按键控制LED实验.

1 蜂鸣器简介

蜂鸣器 分有源无源的(源:震荡源)
有源蜂鸣器自带震荡源,只需要两端加上电压就可以发出蜂鸣声(控制简单
无源蜂鸣器不带震荡源,需要在两端加上脉冲/高低变化的脉冲信号(控制相对复杂一些)

有加号就为正极

2 硬件设计

本例程是有源的
在这里插入图片描述三极管是为了增大蜂鸣器的驱动电流,电流越大声音越小
当给BEEP的的时候,电路导通,如图所示
在这里插入图片描述

3 程序设计

实验任务:使用按键控制蜂鸣器发声。初始状态为蜂鸣器鸣叫,按下开关后蜂鸣器停止鸣叫,再按,重新鸣叫。

3.1 机械按键抖动

在这里插入图片描述

3.2 消抖

实验目的可以看出,每次状态的变化都是通过判断上升沿/下降沿来检测的
但是由于消抖,所以说我们在第一次判断之后,延时20ms,跳过5~10ms的抖动时间,然后再判断
(从按键开始就开始处理。一律都这么处理)

还有另外一种消抖的方法是:
在抖动的过程中,按键的频率是非常高的,如果我们检测到按键的状态稳定并且超过20ms,则可以判断为抖动结束,稳定的状态。
(从按键结束开始处理)

3.3 思路 系统框图

在这里插入图片描述

3.4 程序设计

3.4.1 新建工程+创建源文件(基础操作)

先新建工程,
如果不会的话看看这个 Vivado 2018.3入门教程(一):创建工程+新建源文件.

3.4.2 程序编写-key_beep

module key_beep(
	input 		clk,
	input 		rst_n,
	
	output 		key,//外部输入的按键值
	output  reg key_value,//消抖之后的有效值
	output 	reg key_flag//消抖后的按键值的效标志
	//指定了reg类型,下面才能赋初值
    );
//reg define   
reg [19:0] cnt;//定义计数器
//计数器的位宽, 系统时钟是50MHz,周期的话是20ns,要计数20ms的话每次得计数10的6次方次。
//而10的6次方用二进制表达得20位,因此采用20位宽能达够用来计算


reg key_reg;//定义寄存器,记录上一次的状态

//按键值消抖
always @ (posedge clk or negedge rst_n)begin 
	if(!rst_n)begin 
		cnt <= 20'd0;
		key_reg <= 1'b1;
	end 
	else begin 
		key_reg <= key;//将按键值延迟一拍
		if(key_reg != key)begin //抖动状态
			cnt <= 20'd100_0000;//给寄存器赋初值
			//作为倒计时,看倒计时期间能否一直保持稳定
			//即延时100_0000 * 20ns(1s/50MHz) = 20ms
			
		end 
		else begin//如果当前按键值和前一个按键值一样,即按键没有发生变化
		//开始递减,看是否稳定
			if(cnt > 20'd0 )//一直递减到零
				cnt <= cnt -1'b1;
			else 
				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
	//在计数器递减到1时送出按键值
    else if(cnt == 20'd1) begin//稳定
    //是20'd1而不是20'd0吗,因为cnt从10的6次方递减到0之后,
    //else让cnt一直保持在0了,因此只能检测1的时候
    //原因在于
		key_value <= key;
		key_flag  <= 1'b1;//拉高为1
		//我们想要key_flag只保持一个周期,
        end
    else begin//不稳定
		key_value <= key_value;//依然寄存上一次的按键值,继续下一次20ms的判断
		key_flag  <= 1'b0;//拉低为0
    end
end
 
endmodule

3.4.3 程序编写-beep_control

module beep_control(
	input 		clk,
	input 		rst_n,
	//这里不需要定义key变量了
	input  	 	key_value,//消抖之后的有效值
	input 	 	key_flag,//消抖后的按键值的效标志
	
	output reg 	beep
    );
    
always @ (posedge clk or negedge rst_n)begin 
	 if(!rst_n)
        beep <= 1'b1;
    else if(key_flag && (key_value == 1'b0))
        beep <= ~beep;
	     
end    
endmodule

3.4.4 程序编写-top_key_beep

模块例化更多请看3.5.

module top_key_beep(
    input    clk ,
    input    rst_n ,

    input    key ,
    output   beep//不需要reg因为这里顶层不需要赋值了
);

//wire define
wire key_value ;
wire key_flag ;


//例化 按键消抖模块
key_beep  u_key_beep(//起一个例化之后的名称
	//进行模块的连接
	//按住ctrl +alt键进行列操作,替换成为.	
	
    .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_value  (key_value),
    .key_flag   (key_flag),
    .beep       (beep)
    );

endmodule
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值