任务510蜂鸣器和音乐发生器概要.docx
- 文档编号:12291242
- 上传时间:2023-04-17
- 格式:DOCX
- 页数:20
- 大小:116.57KB
任务510蜂鸣器和音乐发生器概要.docx
《任务510蜂鸣器和音乐发生器概要.docx》由会员分享,可在线阅读,更多相关《任务510蜂鸣器和音乐发生器概要.docx(20页珍藏版)》请在冰豆网上搜索。
任务510蜂鸣器和音乐发生器概要
任务5.10蜂鸣器的原理和驱动
5.9.1任务介绍
在实际应用中,经常利用利用单片机控制蜂鸣器产生各种音乐用于报警和提示,如手机的铃声、时钟的音乐报时和按键提示音等。
本节的任务是:
通过单片机I/O控制开发板上的蜂鸣器演奏音乐。
5.9.2知识准备
1、蜂鸣器的原理和分类
蜂鸣器按结构分有压电式蜂鸣器和电磁式蜂鸣器两种类型。
压电蜂鸣器内部有压电陶瓷和金属片,是利用压电陶瓷的压电效应,带动金属片的振动来发声,频率在1KHz~10KHz。
电磁式蜂鸣器内部有磁铁和线圈,振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声,频率在0.5KHz~5KHz。
压电蜂鸣器结构简单耐用,声音大,多用于报警器等设备。
电磁蜂鸣器音色好,多用于语音、音乐等设备。
蜂鸣器按其是否带有振荡器又分为有源和无源两种类型。
有源蜂鸣器内部带有振荡器,只需要在其供电端加上额定直流电压,其内部的振荡器就可以产生固定频率的信号,驱动蜂鸣器发出声音。
无源蜂鸣器内部没有振荡器,需要在其供电端上加上高低不断变化的电信号
才可以驱动发出声音。
开发板上的蜂鸣器属于电磁式无源蜂鸣器。
2、开发板蜂鸣器驱动电路
开发板蜂鸣器驱动电路如图5.10.1所示。
5.10.1开发板蜂鸣器驱动电路
蜂鸣器的驱动和继电器相似,需要几十mA的电流,通常借助于三极管来作为中间功率驱动。
图5.10.1中,蜂鸣器接在PNP三极管(8550)的集电极上,单片机I/O接三极管的基极,电阻R10是三极管基极限流电阻,电阻R11是上拉电阻。
蜂鸣器内部线圈是感性器件,二极管D10并联在蜂鸣器两端,起到限制反峰电压的作用。
3、无源蜂鸣器的程序驱动
无源蜂鸣器本身不带振荡器,只有让蜂鸣器不停的处于“通电-断电”的状态,才能发出声音。
对于开发板上蜂鸣器驱动电路而言,只需要让控制蜂鸣器的I/O口不停的“置1-置0”就可以了。
下面是利用51单片机P.20驱动蜂鸣器的程序。
#incldue
#defineucharunsignedchar
#defineuintunsigendint
sbitBuzzer=P2^0;//蜂鸣器接口定义
#defineBuzzerOnBuzzer=0
#defineBuzzerOffBuzzer=1
//ms级延时函数
voidDelayMs(uintxms)
{
uinti,j;
for(i=0;i for(j=0;j<122;j++); } //主函数 voidmain() { while (1) { BuzzerOn; DelayMs (1); BuzzerOff DelayMs (1); } } 在程序中,1ms让蜂鸣器通电,1ms让蜂鸣器断电,频率500Hz。 程序编译下载后,蜂鸣器引脚控制端接P2.0引脚,蜂鸣器发出“嗡嗡”的声音。 然后在把延时改为2ms、3ms、5ms,蜂鸣器会发出不同频响的声音。 4、蜂鸣器程序改造和按键提示音 利用延时函数来驱动蜂鸣器显然不是个好的办法,下面的程序通过定时器驱动蜂鸣器,开发板上2个独立按键,每个按键按下时,蜂鸣器响一声,持续时间为0.3秒。 2个按键对应的频率分别为500Hz和1KHz。 要求程序不堵塞CPU,效率高。 (1)工程结构和主函数 工程结构图如图5.10.2所示。 除了主函数外,还有按键模块、定时器模块和键值处理模块。 图5.10.2工程结构图 主函数如下: #include #include"MicroDefine.h" #include"Timer.h" #include"IndependentKey.h" #include"KeyProcess.h" /*************************************************************************** *函数名称: main() *功能: 主函数 *入口参数: 无 *出口参数: 无 *说明: 按键被按下时,蜂鸣器产生0.5S提示音。 按键A提示音频率: 500Hz 按键B提示音频率: 1KHz ***************************************************************************/ voidmain() { ucharKeyValue=0; DelayMs(200); TimerInit();//定时器初始化 while (1) { if(FlagSystem1Ms==1)//1ms时标信号 { FlagSystem1Ms=0; KeyValue=KeyGetValue();//获取键值 KeySound(KeyValue);//键值处理 } } } 程序解释: 主函数内容简单,获取按键键值,并处理键值。 (2)其它功能模块 定时器模块(Timer.c,Timer.h不列出) #include"Timer.h" bitFlagSystem1Ms=0;//1m时标信号 ucharT1High=0;//T0高8位 ucharT1Low=0;//T1低8位 /*************************************************************************** *函数名称: TimerInit() *功能: 定时器初始化 *入口参数: 无 *出口参数: 无 *说明: 定时器0: 产生1ms时标信号,方式2 定时器1: 驱动蜂鸣器,方式1 ***************************************************************************/ voidTimerInit() { TMOD=0x12; TH0=TL0=56; TH1=TL1=0; TR0=1;//只开定时器0,定时器1的开启由按键决定 } ET0=ET1=1; EA=1; TR0=1;//开定时器0, TR1=0;//定时器1关闭,按键按下,才能开定时器1 } /*************************************************************************** *函数名称: Timer0Isr() *功能: 定时器0中断服务函数 *入口参数: 无 *出口参数: 无 *说明: ***************************************************************************/ voidTimer0Isr()interrupt1 { staticucharCnt200us=0; if(++Cnt200us<=5)//产生1ms时标信号 { Cnt200us=0; FlagSystem1Ms=1; } } /*************************************************************************** *函数名称: Timer1Isr() *功能: 定时器1中断服务函数 *入口参数: 无 *出口参数: 无 *说明: 通过改变定时器的初装值,产生不同频率的蜂鸣器驱动信号 ***************************************************************************/ voidTimer1Isr()interrupt3 { TH1=T1High;//加载初值,键值处理模块设置初值 TL1=T1Low; Buzzer=~Buzzer;//电平反转 } 程序解释: 使用了2个定时器,定时器0用来产生1ms时标信号,定时器1用来驱动蜂鸣器。 在定时器初始化中,定时器1配置好后,先不开定时器1,只有按键按下后,才能开定时器1。 定时器1使用了方式1(16位),每一次溢出后,在中断服务函数中,手动重装初值,初值的大小由键值处理模块给定。 在中断服务函数中,实现蜂鸣器驱动I/O的电平反转。 键值处理模块(KeyProcess.h) #include"KeyProcess.h" /*************************************************************************** *函数名称: KeySound() *功能: 按键提示音 *入口参数: 按键值 *出口参数: 无 *说明: ***************************************************************************/ voidKeySound(ucharKeyValue) { staticucharSoundState=0;//状态机变量 staticuintCnt1Ms=0;//1ms计数器 switch(SoundState) { case0: //状态0: 按键被按下,开定时器1 { if(KeyValue==0x81)//按键A被按下,蜂鸣器响 { T1High=0xFC;//定时器1初值,输出500Hz方波 T1Low=0x18; TH1=0xFF;//让定时器快速完成第一次溢出, TL1=0xFF; TR1=1;//开定时器 SoundState=1;//跳转到状态0 } if(KeyValue==0x82)//按键B被按下,蜂鸣器响 { T1High=0xFE; T1Low=0x0c; TH1=0xFF; TL1=0xFE; SoundState=1; TR1=1; } }break; case1: //状态1: 延时299ms,关闭蜂鸣器 { if(++Cnt1Ms>=299) { Cnt1Ms=0; TR1=0;//关闭定时器,蜂鸣器不响 SoundState=0;//跳转到状态0 } } } } 程序解释: KeySound()由状态机构成,分成两个状态。 状态0: 检测到按键被按下,根据按键值,给定时器赋初值,并启动定时器。 状态1: 延时299ms后,关闭定时器1,并返回到状态0。 利用状态机构成按键提示音函数,不堵塞CPU,系统效率高。 5.9.3任务实施 1、音符和频率的关系 通过以上知识的学习,初学者了解到蜂鸣器发声的原理,即通过I/O口输出脉冲信号,再将信号通过三极管放大,推动发声器件(蜂鸣器)发声。 脉冲信号的频率不同,蜂鸣器发出的声音不同。 要完成本节的音乐播放器,需弄清楚两个概念即可,也就是“音符”和“节拍”。 音符其实就是我们常说的“DoReMiFaSolLaSiDo”,每一个音符对应一定的频率。 以中音“1”为例,其频率为523Hz,周期为1秒/523=1912us,半周期为956us。 通常没有做特殊说明,我们把音乐的一个节拍的时间长度定位0.4秒,1/4节拍的时间则为0.1秒。 如果以1/4节拍为基准长度,则1拍为4个基准长度,1/2拍为2个基准长度。 定时器要产生中音“1”对应的频率(523Hz),则定时器每次溢出的时间为半个周期(即956us)。 假设中音“1”的时间长度为1/4拍,则定时器溢出的次数为0.1秒/956us=105次。 1/2拍和1拍对应的溢出次数分别105次*2和105次*4。 为了程序的方便,我们把低音音符(“5”~“7”)、中音音符(“1”~“7”)和高音音符(“ ”~“ ”)的频率、半周期及1/4节拍内半周期数放在表5.10.1中。 表5.10.114个音符频率对应表 数组下标 音符 频率(Hz) 周期(us) 半周期(us) 1/4节拍(0.1S) 内半周期数的个数 0 5 392 2551 1276 78 1 6 440 2273 1136 88 2 7 494 2024 1012 99 3 1 523 1912 956 105 4 2 587 1074 851 117 5 3 659 1517 758 132 6 4 698 1436 716 140 7 5 783 1277 638 157 8 6 880 1136 568 176 9 7 988 1012 506 198 10 1046 956 478 209 11 1175 851 425 235 12 1318 759 379 264 根据表5.10,我们先构建两个数组,分别存放以上音符的半周期时间和1/4拍内半周期的个数。 //13个音符的半周期长度 ucharcodeTableNoteTime[]={1276,1136,1012,956,851,758,716,638,568,506,478,425,379}; //13个音符1/4拍内半周期的个数 ucharcodeTableNoteNum[]={78,88,99,105,117,132,140,157,176,198,209,235,264}; 图5.10.3是儿童歌曲“两支老虎”的简谱。 图5.10.3“两只老虎”简谱 根据简谱,我们把简谱中对应的音符和其拍数再分别放到数组中。 需要说明的是,该数组元素和简谱中音符的对应关系,例如音符“1”,在数组TableNoteTime[]中是第4个元素,所以在音乐简谱数组中应写为“3”。 拍数以1/4拍为基本单位,拍数数组中元素的“1”、“2”和“4”分别对应音符的1/4拍、1/2拍和1拍。 //简谱中对应的音符 ucharcodeTableMusicNote[]={3,4,5,3,3,4,5,3,5,6,7,5,6,7,7,8,7,6,5,3,7,8,7,6,5,3,4,0,3,4,0,3}; //简谱中音符对应的拍数 ucharcodeTalbeMusicBeat[]={2,2,2,2,2,2,2,2,2,2,4,2,2,4,1,1,1,1,2,2,1,1,1,1,2,2,2,2,4,2,2,4}; 有了这4个数组,音乐播报就变得简单了。 根据TableMusicNote[]数组中的值,从TableNoteTime[]数组中找到待播放音符的半周期长度,将半周期长度作为定时器的溢出值,启动定时器,蜂鸣器就会产生该音符。 在播报音符的同时,根据TableMusicNote[]数组中的值,从TableNoteNum[]数组中找到该音符所对应的1/4拍内半周期的个数,然后再从TalbeMusicBeat[]数组中,找到该音符在简谱中的拍数,两者相乘,即为定时器产生该音符所对应频率的时间长度。 播报完了第一个音符,然后再播报第二个音符...直到最后一个音符,一首曲子就播放完了。 2、程序实现 (1)工程架构和主函数 程序的工程架构如图5.10.4所示。 除了主函数模块,至于键值获取模块和定时器模块。 音乐播放放在定时器模块中完成。 图5.10。 4工程结构图 主函数如下: #include #include"MicroDefine.h" #include"Timer.h" #include"IndependentKey.h" /*************************************************************************** *函数名称: main() *功能: 主函数 *入口参数: 无 *出口参数: 无 *说明: ***************************************************************************/ voidmain() { ucharKeyValue=0; ucharCnt1Ms=0; DelayMs(200); TimerInit();//定时器初始化 while (1) { if(FlagSystem1Ms==1)//1ms时标信号到 { FlagSystem1Ms=0; if(++Cnt1Ms>=10)//10ms时标信号到 { Cnt1Ms=0; KeyValue=KeyGetValue();//获取按键值 if(KeyValue==0x81) { if(FlagMusicEnd==0)//上一次播放完毕,则启动新的播放 { TR1=1;//启动定时器 FlagMusicEnd=1;//音乐播放中 } } } } } } } } 程序解释: 在主程序中检测按键按下,则启动定时器1,并把音乐结束标志位置1。 (2)其它功能模块 键值处理模块(省略) 定时器模块 Timer.h: #ifndef_TIMER_H_ #define_TIMER_H_ #include #include"MicroDefine.h" sbitBuzzer=P2^0; #defineMusicPlaySpeed20//音乐播放速度宏定义 //变量声明 externbitFlagSystem1Ms;//1m时标信号 externbitFlagMusicEnd;//音乐播放结束标志位 //定时器声明 externvoidTimerInit();//定时器初始化 #endif Timer.c: #include"Timer.h" bitFlagSystem1Ms=0;//1m时标信号 bitFlagMusicEnd=0;//音乐播放结束标志位 //13个音符的半周期长度 uintcodeTableNoteTime[]={1276,1136,1012,956,851,758,\ 716,638,568,506,478,425,379}; //13个音符对应的1/4拍内半周期的个数 uintcodeTableNoteNum[]={78,88,99,105,117,132,140,157,\ 176,198,209,235,264}; //简谱中对应的音符 ucharcodeTableMusicNote[]={3,4,5,3,3,4,5,3,5,6,7,5,6,7,7,8,\ 7,6,5,3,7,8,7,6,5,3,4,0,3,4,0,3}; //简谱中音符对应的拍数 ucharcodeTalbeMusicBeat[]={2,2,2,2,2,2,2,2,2,2,4,2,2,4,1,1,\ 1,1,2,2,1,1,1,1,2,2,2,2,4,2,2,4}; /*************************************************************************** *函数名称: TimerInit() *功能: 定时器初始化 *入口参数: 无 *出口参数: 无 *说明: 定时器0: 产生1ms时标信号,方式2 定时器1: 驱动蜂鸣器,方式1 ***************************************************************************/ voidTimerInit() { TMOD=0x12; TH0=TL0=56; TH1=TL1=0xFF; ET0=ET1=1; EA=1; TR0=1;//只开定时器0,定时器1的开启由按键决定 } /*************************************************************************** *函数名称: Timer0Isr() *功能: 定时器0中断服务函数 *入口参数: 无 *出口参数: 无 *说明: ***************************************************************************/ voidTimer0Isr()interrupt1 { staticucharCnt200us=0; if(++Cnt200us>=5)//产生1ms时标信号 { Cnt200us=0; FlagSystem1Ms=1; } } /*************************************************************************** *函数名称: Timer1Isr() *功能: 定时器1中断服务函数 *入口参数: 无 *出口参数: 无 *说明: 通过改变定时器的初装值,产生不同频率的蜂鸣器驱动信号 MusicPlaySpeed是头文件中宏定义,决定音乐的播放速度,其值不能小于10 ***************************************************************************/ voidTimer1Isr()interrupt3 { staticucharNoteCnt=0;//播放音符计数器 staticuintHalfPeriodCnt=0;//半周期计数器 uintTimer1Temp=0;//定时器长度暂存值 //根据当前播放音符,计算出对应的定时器初值 Timer1Temp=65536-TableNoteTime[TableMusicNote[NoteCnt]]; TH1=Timer1Temp/256; TL1=Timer1Temp%256; Buzzer=! Buzzer; //播放一个音符的时间到 if(++HalfPeriodCnt>=(TableNoteNum[TableMusicNote[NoteCnt]]\ *TalbeMusicBeat[NoteCnt])*MusicPlaySpeed/10) { HalfPeriodCnt=0; //简谱中的音符全部播放完 if(++NoteCnt>=32) { NoteCnt=0; TR1=0;//定时器停止 FlagMusicEnd=0;//音乐播放结束结束标志位清零 } } } 程序解释: 程序中使用了两个定时器,和之前按键音一样,一个用来产生系统时标信号,另外一个用于用于驱动蜂鸣器。 按键启动定时器1,定时器1溢出后,从播报的第一音符起,取出该音符半周期时间长度,计算出定时器1的初值,让定时器1输出该音符对应的脉冲波。 定时器1每溢出1次,半周期计数器(HalfPeriodcnt)加1,音符播放的时间长度由半周期计数器的值来决定
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 任务 510 蜂鸣器 音乐 发生器 概要