基于FPGA的电子琴设计(按键和蜂鸣器)----第一版
欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于FPGA的电子琴设计(按键和蜂鸣器)----第一版。
功能说明:
外部输入七个按键,分别对应音符的“1、2、3、4、5、6、7”,唱作do、re、mi、fa、sol、la、si。当某个按键按下时,蜂鸣器发出对应的声音----1. 默认发出0.2秒(可以调整)。2. 蜂鸣器发出对应的中音。
使用平台:本次设计应用Altera的平台设计(芯片:EP4CE10F17C8N)。
仿真平台:Modelsim。
作者QQ:746833924
说明:本篇设计中不涉及到IP和原语,代码在其他平台依然可以适用;当其他板卡电路不同时,会导致不同的现象出现,如有需要修改代码请联系作者;如需作者使用的板卡,请联系作者;
蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件

蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。
压电式蜂鸣器 压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、阻抗匹配器及共鸣箱、外壳等组成。有的压电式蜂鸣器外壳上还装有发光二极管。多谐振荡器由晶体管或集成电路构成。当接通电源后(1.5~15V直流工作电压),多谐振荡器起振,输出1.5~2.5kHZ的音频信号,阻抗匹配器推动压电蜂鸣片发声。
电磁式蜂鸣器电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。接通电源后,振荡器产生的音频信号电流通过电磁线圈,使电磁线圈产生磁场。振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声。
按照内部有无震荡源可以分为有源蜂鸣器和无源蜂鸣器。有源蜂鸣器内部带震荡源,所以只要一通电就会发出声音;而无源内部不带震荡源,所以如果用直流信号无法令其鸣叫。必须用一定频率的方波去驱动它。
蜂鸣器给予不同的频率是可以发出近似1、2、3、4、5、6、7这七个基本音符。

设计思想如下:

key_ctrl模块负责将外部的按键信号进行消抖,并且产生对应边沿变化时的脉冲;piano_beep_ctrl模块负责根据脉冲信号产生输出控制脉冲(一个周期)和应该输出音符对应波形的半周期数;beep_ctrl模块根据piano_beep_ctrl产生脉冲时,接收半周期数,然后产生对应的方波持续0.2秒。
key_ctrl模块设计思想为:按键信号是由外部机械式按键产生,每次按下或者抬起时,会产生一定的抖动。如果直接对其进行边沿检测就会导致多次触发。故而需要设计按键消抖,进而对消抖之后的波形进行边沿检测。消抖原理为:外部按键信号发生改变后,如果能够持续20ms,没有新的改变,就认为此次改变不是抖动,而是真正的按下,然后进行采样即可。
// 记录任意边沿之后没有遇到新的边沿的时间长度是否达到20Ms
//--------------------------------------------------------------------------------------
always@(posedgeclk)begin
if(rst_n ==1'b0)
cnt_20ms <=20'd0;
else
if(pulse_key_negedge ==1'b1||pulse_key_posedge ==1'b1)
cnt_20ms <=20'd1;
else
if(cnt_20ms >20'd0&&cnt_20ms <T_20ms)
cnt_20ms <=cnt_20ms +1'b1;
else
cnt_20ms <=20'd0;
end
// ---------------------------------------------------------------------------------------
// 任意边沿之后没有遇到新的边沿的时间长度达到20Ms,认为按键稳定,此时采样
//--------------------------------------------------------------------------------------
initial key_wave = 1'b1;
always@(posedgeclk)begin
if(rst_n ==1'b0)
key_wave <=1'b1;
else
if(cnt_20ms ==T_20ms)
key_wave <=key_rr;
else
key_wave <=key_wave;
end
//--------------------------------------------------------------------------------------
// 对消抖之后的按键信号进行边沿检测
//---------------------------------------------------------------------------------------------
initialkey_wave_r =1'b1;
always@(posedgeclk)key_wave_r <=key_wave;
assignflag_neg =(key_wave_r ==1'b1&&key_wave ==1'b0)?1'b1:1'b0;
assignflag_pos =(key_wave_r ==1'b0&&key_wave ==1'b1)?1'b1:1'b0;
//--------------------------------------------------------------------------------------------
piano_beep_crtl模块中,计算半周期数的方法如下:
假如要发出中音“1”,就需要输出频率为523.3hz的方波。此方波对应的周期为1910949.742021785 ns,我们取1910950ns。因为我们使用的基本时钟为50MHz,周期为20ns,以及我们预计计数一半取反来生成方波,所以只需要计数一般,即:1910950/2/20 = 47774;
将其他的全部计算出来:
// 1 : 523.3Hz num : 47774
// 2 : 587.3Hz num : 42568
// 3 : 659.3Hz num : 37919
// 4 : 698.5Hz num : 35791
// 5 : 784Hz num : 31888
// 6 : 880Hz num : 28409
// 7 : 987.8Hz num : 25309
// 产生输出脉冲:无论外部那个脉冲有效,都对外产生一个脉冲
always @ (posedge clk) begin
if (rst_n == 1'b0)
flag <= 1'b0;
else
flag <= |key_flag;
end
// 如果外部多个脉冲同时有效,那么输出num为0
always @ (posedge clk) begin
if (rst_n == 14'b0)
num <= 32'd0;
else
case (key_flag)
7'b100_0000 : num <= 32'd47774;
7'b010_0000 : num <= 32'd42568;
7'b001_0000 : num <= 32'd37919;
7'b000_1000 : num <= 32'd35791;
7'b000_0100 : num <= 32'd31888;
7'b000_0010 : num <= 32'd28409;
7'b000_0001 : num <= 32'd25309;
default : num <= 32'd0;
endcase
end
以上即为piano_beep_ctrl模块的设计思想;
在beep_ctrl中,首先设计一个当输入脉冲时,就让一个计数器cnt_200ms记录0.2秒。
// 外部输入一个脉冲,cnt_200ms计数器记录200ms的时间
// 如果第一个脉冲输入后,没有计时到200ms,第二个脉冲没有任何作用
always @ (posedge clk) begin
if (rst_n == 1'b0)
cnt_200ms <= 32'd0;
else
if (flag == 1'b1 && cnt_200ms == 32'd0)
cnt_200ms <= cnt_200ms + 1'b1;
else
if (cnt_200ms > 32'd0 && cnt_200ms < T_200ms - 1'b1)
cnt_200ms <= cnt_200ms + 1'b1;
else
cnt_200ms <= 32'd0;
end
由于外部给予半周期数时,只有一个周期有效,所以需要寄存一下。
//外部输入脉冲时,寄存外部输入的半周期的时钟数
always @ (posedge clk) begin
if (rst_n == 1'b0)
num_r <= 32'd0;
else
if (flag == 1'b1 && cnt_200ms == 32'd0)
num_r <= num;
else
num_r <= num_r;
end
当200ms计数器开始计数后,我们启动另外一个计数器ocnt,来记录需要输出方波的半周期数。然后当到半周期数的时候,将输出值取反。
// 当200ms开始计时后,输出计数器开始计数,
// 只需要计数到外部输入的半周期时钟数即可
always @ (posedge clk) begin
if (rst_n == 1'b0)
ocnt <= 32'd0;
else
if (cnt_200ms > 32'd0)
if (ocnt < num_r)
ocnt <= ocnt + 1'b1;
else
ocnt <= 32'd0;
else
ocnt <= 32'd0;
end
// 当外部输入的半周期时钟数为0时,蜂鸣器不动作
// 当不为0时,到半周期时钟数,将输出取反
always @ (posedge clk) begin
if (rst_n == 1'b0)
beep <= 1'b0;
else
if (num_r == 32'd0)
beep <= 1'b0;
else
if (ocnt == num_r)
beep <= ~beep;
else
beep <= beep;
end
以上即为所有的设计说明。
仿真时,需要将消抖模块中的20ms进行调小,否则仿真的时长将会格外的长。

下板后,经过按下不同的按键,蜂鸣器就可以产生对应的声音。
下板后,演示视频(链接)如下:
https://www.bilibili.com/video/BV1Gk4y1X7XT/?spm_id_from=333.999.0.0&vd_source=b5405faeab8632f02533bcbfc5e52e55
本设计所有内容(设计代码、设计工程)链接为:
链接:https://pan.baidu.com/s/1VGbPqU9O_k2UBtOGkMJjIQ
提取码:dzye
本篇内容中有部分资源来源于网络,如有侵权,请联系作者。
如果您觉得本公众号还不错的话,可以推给身边的朋友们,感谢并祝好!
基于FPGA的电子琴设计(按键和蜂鸣器)----第一版的更多相关文章
- 基于FPGA的DDS设计(一)
最近在学习基于FPGA的DDS设计,借此机会把学习过程记录下来,当作自己的学习笔记也希望能够帮助到学习DDS的小伙伴. DDS(Direct Digital Synthesizer)直接数字合成器,这 ...
- 基于FPGA的DDS设计(二)
在DDS设计中,如果相位累加器每个时钟周期累加1,就会输出频率为195.313KHz的波形.如果每个时钟周期累加2,就会输出频率为2*195.313KHz的波形·······,如果每两个时钟周期累加1 ...
- 38.基于FPGA的FIR设计二
利用fdatool工具生成的滤波器系数与用代码生成的系数不一致,在网上查询得知,fdatool生成的滤波器系数是有符号小数,而且是浮点型,而代码生成的滤波器系数是定点型有符号数,故不一样. 浮点型数据 ...
- 优化基于FPGA的深度卷积神经网络的加速器设计
英文论文链接:http://cadlab.cs.ucla.edu/~cong/slides/fpga2015_chen.pdf 翻译:卜居 转载请注明出处:http://blog.csdn.net/k ...
- 自己动手写CPU(基于FPGA与Verilog)
大三上学期开展了数字系统设计的课程,下学期便要求自己写一个单周期CPU和一个多周期CPU,既然要学,就记录一下学习的过程. CPU--中央处理器,顾名思义,是计算机中最重要的一部分,功能就是周而复始地 ...
- 基于FPGA的按键扫描程序
最近在学习FPGA,就试着写了个按键扫描的程序.虽说有过基于单片机的按键扫描处理经验,对于按键的处理还是有一些概念.但是单片机程序的编写通常都采用C写,也有用汇编,而FPGA却是采用VHDL或者Ver ...
- 基于FPGA的HDMI显示设计(三)
上一篇:基于FPGA的VGA显示设计(二) 10月10日 ~ 20日期间实习,令我万万没想到的是实习题目是 “便携式高清电视显示屏测试系统原型设计” 也就是 “基于FPGA的视频显示”. 实习要求用 ...
- 基于FPGA的XPT2046触摸控制器设计
基于FPGA的XPT2046触摸控制器设计 小梅哥编写,未经许可,文章内容和所涉及代码不得用于其他商业销售的板卡 本实例所涉及代码均可通过向 xiaomeige_fpga@foxmail.com 发 ...
- 基于FPGA的VGA显示设计(二)
上一篇:基于FPGA的VGA显示设计(一) 参照 CrazyBingo 的 基于FPGA的VGA可移植模块终极设计代码 的工程代码风格,模块化处理了上一篇的代码,并增加了一点其它图形. 顶层 ...
- 基于FPGA的VGA可移植模块终极设计【转】
本文转载自:http://www.cnblogs.com/lueguo/p/3373643.html 略过天涯 基于FPGA的VGA可移植模块终极设计 一.VGA的诱惑 首先,VGA的驱动,这事, ...
随机推荐
- Spring内存马分析
环境搭建 踩了很多坑....,不过还好最后还是成功了 IDEA直接新建javaEE项目,然后记得把index.jsp删了,不然DispatcherServlet会失效 导入依赖: <depend ...
- RabbitMQ 02 安装
安装 推荐使用Docker进行安装. 执行如下命令. docker run -d --restart always --name rabbitmq \ -e RABBITMQ_DEFAULT_USER ...
- Push failed idea将项目发布到gitHub失败
此时需要点击VCS --> inport into version..-->create git ...重新生成仓库
- HuffmanTree,哈夫曼树的原理和c++实现
目录 一.什么是哈夫曼树 二.构造哈夫曼树 三.路径.编码.解码 四.代码 一.什么是哈夫曼树 哈夫曼树又称为最优树. 通过权值来构造树,权值越大,离根节点越近 经常用于无损压缩算法 用于需要优化存储 ...
- Harbor仓库高可用
一.搭建两台Harbor 搭建方法参考:https://www.cnblogs.com/hanfuming/p/15750031.html 二.两台新建相同项目 三.第二台harbor上仓库管理中新建 ...
- 重新点亮linux 命令树————文件权限和目录权限[九]
前言 简单整理一下文件权限和目录权限. 正文 当打开ls -al的时候会出现相关的权限信息. 那么上面文件类型包括: 普通文件 d 目录文件 b 块特殊文件 (设备,比如u盘) c 字符特殊文件 (终 ...
- 力扣500(java&python)-键盘行(简单)
题目: 给你一个字符串数组 words ,只返回可以使用在 美式键盘 同一行的字母打印出来的单词.键盘如下图所示. 美式键盘 中: 第一行由字符 "qwertyuiop" 组成.第 ...
- Quick BI新版本功能解读系列之-V3.5
前言Quick BI V3.5版本于2019年11月底正式发布啦!本次大版本在智能.开放.以及可视化等方面都有重磅上新,具体包含智能小Q.开放数据服务.主题模板.以及散点图.地图系列等一系列功能的发布 ...
- Flutter+FaaS一体化任务编排的思考与设计
作者:闲鱼技术-古风 Flutter+Serverless三端一体研发架构,客户端不仅仅是编写双端的代码,而是扩展了客户端的工作边界,形成完整的业务闭环.在新的研发模式落地与实践的过程中,一直在思考如 ...
- 技术干货 | mPaaS 小程序高玩带你起飞:客户端预置小程序无视网络质量
简介: 弱网拉包无障碍,深度提升用户体验 传统的小程序技术容易受到网络环境影响,当网络质量不佳时可能导致拉取不到小程序包的情况.通过预置小程序,即可规避该问题.本文介绍了预置小程序的原理和预置小程序的 ...