开源伪和弦淫乐声的产生原理及电路,源码。
有位兄弟发帖问如何产生清脆的“丁丁”声音,手贱回了一帖,没想到引来更多兄弟对此的性趣。约下的炮,肯定要打完,在此奉上电路和源码。其实,这种听起来比较悦耳的声音产生原理也非常简单。就是利用电容的放电产生一个渐弱的尾音,模拟出击打风铃的音色。
电路如下:
BUZ-H负责输出音频频率,BUZ-L负责对C12的充电作控制。
例如,要发出“叮~~~~”的一声,在BUZ-H输出2400Hz的方波,BUZ-L输出72ms的高电平,此段时间内,蜂鸣器将由幅值12V的频率驱动,发出类似击打瞬间的声音,同时对C12充电。72ms后,BUZ-L输出低电平,这个时候,蜂鸣器将由C12来提供驱动电流,并且随著电容放电,声音逐渐减弱,产生类似风铃尾音的效果。1秒后,关闭BUZ-H的输出。
这种发声方式,其实还是单音频发声,只是在单音频的基础上,用电容的充放电模拟了击打和尾音,产生比较丰满悦耳的听感,所以称之为“伪和弦”。
各位有兴趣的话,可以用多个蜂鸣器同时发出不同音调,组成多音的真和弦,一个音调输出占用一个定时器。俺以前10多年前蛋疼,搞过几十个蜂鸣器的(5和弦,蜂鸣器多个并联),并且并增加一个IO用作电容的放电回路来产生短音,听感还是不错的。真有空时回老家翻出来拍个视频给大家看看。
源码如下,带音量控制,带家电常用的音调组合,还附上一个超级玛丽的1UP声音,玩过的朋友肯定会觉得很亲切,哈哈。
源码不是整个工程,我也懒得整理了,生活艰苦,搬砖不易。
用法,在您的工程里面增加两个文件,一个名为Music.c,一个名为Music.h(头文件)。现在源码,使用的是STM32F1xx,主频72M,使用的定时器是TIM2(任意定时器均可,自己修改),使用硬件PWM输出。所以您单片机有N个定时器,则可以最多N-1个真和弦(留一个做主时基),做产品,通常一个伪和弦就够了。Music_Srv()这个函数,没4ms调用一次,您放中断也行,放主循环也行(前提是您主循环没有阻塞的占用)。需要发声的时候,任意地方放一句 Music_Triger=MUSIC_XXX;即可,不阻塞,也不用等它播完再调用,随传随叫春。
BUZ-L现在接的是PA1,这个任意IO即可,请自行修改。BUZ-H接的是PA0,这个随您用不同的TIM而不同,自己修改,例程用的是TIM2。
//*************************************************************************************************************************************
Music.h源码:
#ifndef __MUSIC_H_
#define __MUSIC_H_
//BUZ-L定义IO
#define BEEPL_1 GPIOA_DSRR=BIT1
#define BEEPL_0 GPIOA_DRR=BIT1
#define BEEPL_XOR {if(BitTst(GPIOA_ODR,BIT1)) BEEPL_0; else BEEPL_1;}
//音乐声定义
#define MUSIC_PWR_UP 1
#define MUSIC_TURN_ON 2
#define MUSIC_TURN_OFF 4
#define MUSIC_DING 3
#define MUSIC_UP 5
#define MUSIC_DOWN 6
#define MUSIC_1UP 7
extern volatileuint8Music_Triger; //触发发声标志
extern uint8flg_MusicPlaying; //非0表示正在发声
void Music_Srv(void); //4ms调用一次
void Music_InitIO(void); //初始化IO
void Music_Init(void); //初始化Music模块。
#endif
//*************************************************************************************************************************************
Music.c源码:
#include "music.h"
#define TIM2_ARR (*((volatile uint16 *)(TIM2_BASE + 0x002c)))
#define TIM2_CR1 (*((volatile uint16 *)(TIM2_BASE + 0)))
#define TIM2_CCR1 (*((volatile uint16 *)(TIM2_BASE + 0x0034)))
#define TIM2_CCER (*((volatile uint16 *)(TIM2_BASE + 0x0020)))
#define TIM2_CNT (*((volatile uint16 *)(TIM2_BASE + 0x0024)))
#define TIM2_CCR2 (*((volatile uint16 *)(TIM2_BASE + 0x0038)))
// 定义常用频率,数字多少就是多少Hz
#define _28 2850
#define _24 2400
#define _22 2250
#define _21 2100
#define _18 1850
#define _16 1650
// 定义duo,rui,mi,fa,so等等
#define _l1 130
#define _l2 146
#define _l3 164
#define _l4 174
#define _l5 196
#define _l6 220
#define _l7 246
#define _1 261
#define _2 293
#define _3 329
#define _4 349
#define _5 392
#define _6 440
#define _7 494
#define _1d1 523
#define _2d1 587
#define _3d1 659
#define _4d1 698
#define _5d1 784
#define _6d1 880
#define _7d1 987
#define _1d2 1046
#define _2d2 1175
#define _3d2 1318
#define _4d2 1397
#define _5d2 1568
#define _6d2 1760
#define _7d2 1976
#define _1d3 (_1d2*2)
#define _2d3 (_2d2*2)
#define _3d3 (_3d2*2)
#define _4d3 (_4d2*2)
#define _5d3 (_5d2*2)
#define _6d3 (_6d2*2)
#define _7d3 (_7d2*2)
//定义不同的乐曲数组,0 结束
const uint16 Music1_FrqTab[]={//频率表,对应BUZ-H的输出频率,0 结束
_18, _18, _21, _21, _24, _24, _28, _28, 0,
};
const uint8 Music1_TimeTab[]={ //BUZ-L输出时间,偶数高电平,奇数为低电平尾音,x4ms,0 结束
20, 30, 20, 30, 20, 30, 20, 255, 0,
};
const uint16 Music2_FrqTab[]={
_21, _21, _22, _22, _24, _24, 0
};
const uint8 Music2_TimeTab[] ={ //x4ms
10, 18, 10, 18, 10, 255, 0,
};
constuint16 Music3_FrqTab[]={
_24, _24, 0,
};
constuint8 Music3_TimeTab[] ={ //x4ms
18, 255, 0,
};
constuint16 Music4_FrqTab[] ={
_28, _28, _24, _24, _21, _21, 0
};
constuint8 Music4_TimeTab[]={ //x4ms
10, 18, 10, 18, 10, 255, 0,
};
constuint16 Music5_FrqTab[] ={
_16, _16, _18, _18, _21, _21, 0
};
constuint8 Music5_TimeTab[] ={ //x4ms
6, 16, 6, 16, 6, 255, 0,
};
constuint16 Music6_FrqTab[] ={
_21, _21, _18, _18, _16, _16, 0
};
constuint8 Music6_TimeTab[] ={ //x4ms
6, 16, 6, 16, 6, 255, 0,
};
const uint16 Music7_FrqTab[]={
1324,1324,1574,1574,2645,2645, 2114,2114,2347,2347,3154,3154, 0,
};
const uint8 Music7_TimeTab[]={ //x4ms
15, 25, 15, 25, 15, 25, 15, 25 , 15 , 25,15,255, 0,
};
uint8 Music_Vol=137; //音量
volatile uint8Music_Triger=0; //触发播放哪一支,例如播放“叮~~~”,则任意地方调用 Music_Triger=MUSIC_DING;
uint8flg_MusicPlaying=0; //非零播放中。
//乐曲表指针
uint16 const*music_frq_tab;
uint8 const*music_interval_tab;
TIM_TimeBaseInitTypeDef T2_TimeBaseStruct;
TIM_OCInitTypeDef T2_OCInitStruct;
void Music_SetVolumn(uint8 vol){ //设置音量,并且初始化TIM输出
uint32 lTmp;
lTmp=T2_TimeBaseStruct.TIM_Period;
lTmp*=vol;
lTmp/=255;
T2_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
T2_OCInitStruct.TIM_Pulse = lTmp;
T2_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
T2_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OC1Init(TIM2, &T2_OCInitStruct);
}
/* ---------------------------------------------------------------
TIM2 Configuration: Output Compare Toggle Mode:
TIM2CLK = 72 MHz, Prescaler = 0x9, TIM2 counter clock = 7.2 MHz
--------------------------------------------------------------- */
void Music_SetFrq(uint16 frq){ //设置频率并初始化TIM
uint32 clk;
clk=7200000;
clk/=frq;
clk--;
/* Time base configuration */
T2_TimeBaseStruct.TIM_Period = clk;
T2_TimeBaseStruct.TIM_Prescaler = 0x9;
T2_TimeBaseStruct.TIM_ClockDivision = 0x0;
T2_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &T2_TimeBaseStruct);
Music_SetVolumn(Music_Vol);
}
void Music_ChangeFrq(uint16 frq){ //改变频率。
uint32 clk;
clk=7200000;
clk/=frq;
clk--;
/* Time base configuration */
TIM2_ARR = clk;
clk*=Music_Vol;
clk/=255;
TIM2_CCR1=clk;
}
void Music_Frq_Enable(void){
TIM2_CCER|=BIT0;
}
void Music_Frq_Diable(void){
TIM2_CCER&=(~BIT0);
}
void Music_Init(void){
Music_SetFrq(4000);
TIM_ARRPreloadConfig(TIM2, ENABLE); // 这个记得要开
//启用CCR1寄存器的影子寄存器(直到产生更新事件才更改设置)
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
Music_Frq_Diable();
TIM_Cmd(TIM2, ENABLE);
}
void Music_InitIO(void){
GPIO_InitTypeDef tmpGPIO;
tmpGPIO.GPIO_Mode=GPIO_Mode_Out_PP;
tmpGPIO.GPIO_Speed=GPIO_Speed_50MHz;
tmpGPIO.GPIO_Pin=GPIO_Pin_1;
GPIO_Init(GPIOA,&tmpGPIO);
tmpGPIO.GPIO_Pin=GPIO_Pin_0;
tmpGPIO.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&tmpGPIO);
BEEPL_1;
}
void Music_Select(void){
switch(Music_Triger){
default:
flg_MusicPlaying=0;
return;
case MUSIC_PWR_UP:
music_frq_tab=Music1_FrqTab;
music_interval_tab=Music1_TimeTab;
break;
case MUSIC_TURN_ON:
music_frq_tab=Music2_FrqTab;
music_interval_tab=Music2_TimeTab;
break;
case MUSIC_DING:
music_frq_tab=Music3_FrqTab;
music_interval_tab=Music3_TimeTab;
break;
case MUSIC_TURN_OFF:
music_frq_tab=Music4_FrqTab;
music_interval_tab=Music4_TimeTab;
break;
case MUSIC_UP:
music_frq_tab=Music5_FrqTab;
music_interval_tab=Music5_TimeTab;
break;
case MUSIC_DOWN:
music_frq_tab=Music6_FrqTab;
music_interval_tab=Music6_TimeTab;
break;
case MUSIC_1UP:
music_frq_tab=Music7_FrqTab;
music_interval_tab=Music7_TimeTab;
break;
}
flg_MusicPlaying=1;
}
void Music_Srv(void){
static uint8PlayStep=0;
static uint8PlayCt=0;
uint8 cTmp;
if(Music_Triger){
Music_Select();
Music_Triger=0;
PlayStep=0;
PlayCt=0;
Music_ChangeFrq(music_frq_tab);
Music_Frq_Enable();
BEEPL_1;
}
if(flg_MusicPlaying){
cTmp=music_interval_tab;
PlayCt++;
if(PlayCt>=cTmp){
PlayCt=0;
PlayStep++;
Music_ChangeFrq(music_frq_tab);
if(music_interval_tab==0){
flg_MusicPlaying=0;
}
else{
BEEPL_XOR;
}
}
}
else{
BEEPL_0;
Music_Frq_Diable();
}
}
楼主好人,1024。 赞哦,支持兄弟的奉献! {:lol:} 顶楼主,感兴趣 感谢分享,谢谢 好人 1024
楼主好人,1024。
好人 1024 楼主给力,赞 约下的炮,肯定要打完
对于这种负责任的态度,表示“钦敬” {:biggrin:} 今晚约一下! 赞,这得花不少功夫研究 盖楼速度有点快,补充一下,最好使用TDK的17mm的无源蜂鸣器,声音非常悦耳,某商城有卖。 楼主好人,一晚几十炮。{:lol:} 本帖最后由 lrzxc 于 2020-1-2 15:46 编辑
问下楼主,图中的buz是无源的蜂鸣器?
============================
看到了,为仔细看帖,原来13楼有关于蜂鸣器的说明 给力,祝楼主新年快乐。 楼主厉害,标题很劲爆 这个供电电压要12V,,,3.3V或者5~6V不行吗?很多手持设备没12V的 ljq77402 发表于 2020-1-2 15:24
这个供电电压要12V,,,3.3V或者5~6V不行吗?很多手持设备没12V的
多少伏都行,3.3也行,声音小一些而已,听感一样的。 不错,多谢分享! 给大佬点赞。 求贴效果录音听听 祝楼主一晚几十炮 给楼主赞一个{:victory:} 强!多谢分享! 战略性马克!祝楼主一夜七次狼。 来听听淫乐声{:lol:} 好人 1024 楼主无私奉献,收藏点赞!!! amigenius 发表于 2020-1-2 15:14
盖楼速度有点快,补充一下,最好使用TDK的17mm的无源蜂鸣器,声音非常悦耳,某商城有卖。 ...
楼主说到做到,好样的 点赞
学习学习长见识了 amigenius 发表于 2020-1-2 15:14
盖楼速度有点快,补充一下,最好使用TDK的17mm的无源蜂鸣器,声音非常悦耳,某商城有卖。 ...
看来这个很重要 楼主好人,以后约炮肯定都是大美女 楼主好人,学习学习,小小蜂鸣器玩法挺多 楼主好人啊,非常感谢~~~ 楼主好人,1024。 楼主真好,学习了,点赞! 楼主这次约的都是老男人,下次约美女,{:titter:} 学习了,楼主 1024! 祝楼主炮火连天 好人 1024 祝楼主炮火连天 谢谢楼主分享 tim 发表于 2020-1-2 15:32
求贴效果录音听听
等有兄弟弄出来,就请他上传一下吧,我也懒得回老家翻以前的项目垃圾了,估计要翻个半天才能找到 好东西,多谢楼主分享! amigenius 发表于 2020-1-2 15:14
盖楼速度有点快,补充一下,最好使用TDK的17mm的无源蜂鸣器,声音非常悦耳,某商城有卖。 ...
在严谨点,应该说无源压电蜂鸣器,因为无源 还有电磁式的。有点班门弄斧了。{:lol:} 看看春节有没有时间回老家翻出以前的项目垃圾,里面有周华健的爱相随 的3和弦,在此基础上加个液晶或OLED配上淫乐,做个电子情书撩妹应该不错。 楼主好人,1024{:titter:} {:biggrin:}不错 LZ好人 顶顶 感谢楼主分享,有空折腾一下玩玩
怎么想到的啊,LZ利害啊,
祝楼主炮火连天! 感谢楼主,有时间搭个电路试试{:lol:} 楼主好人,mark 楼主好人,祝楼主夜夜做新郎 LZ这个蜂鸣器不用无源电磁式的吗? 收藏了,谢谢分享 哇咧,这个妙妙妙 撸主好人一生平安,1024,收藏了 楼主牛逼,收藏学习 好人 1024 好帖,必须收藏。 楼主厉害了 楼主好人,1024{:lol:} 怎么想到的啊,LZ利害啊, 楼主强人,顶你 楼主好人,1024 好資料,多謝分享。 楼主好人 楼主好人,1024。 感觉好厉害,楼主这是你原创的吗,佩服一下 看起来这个很厉害啊
我看B站上大部分的蜂鸣器视频还停留在基本的旋律上
老哥这个代码完爆他们的 1024 mark下 这次约了一群抠脚大汉{:titter:} 楼主牛逼,学习了。 楼主好人 1024 谢谢分享,好人一生平安 楼主牛逼,学习了。 楼主牛掰,想看下楼主当年拍的视频{:lol:} 楼主好人,学习了 要产生不同的乐声,是不是还得学习下乐理知识 楼主好人,1024 好人一生平安,1024 楼主好人,蜂鸣器多了一种玩法。 楼主好人一生平安,1024 感谢楼主奉献,学到了,这玩意儿还有这样的玩法,高 楼主好人,1024 学习了,多谢 超级棒,哪位再配个实物音频就更棒了!
感谢楼主奉献 音乐贺卡效果? 感谢,实用,好用,方便 撸主好人一生平安,1024,收藏了 感谢楼主无私 楼主好人1024 支持分享,收藏备用,谢谢。 感谢,实用,好用,方便 学习了,谢谢! HappySmile 发表于 2020-1-2 15:05
楼主好人,1024。
有种走错了地方的赶脚~{:lol:}