STC89C52RC操作蜂鸣器实现一个music音乐播放器的音乐盒
- 1 概述
- 2 蜂鸣器操作方法
- 3 蜂鸣器发出音声
- 4 硬件电路
- 5 软件实现
- 6 整体工程:
- 7 总结
1 概述
要实现一个基于STC89C52RC单片机的音乐盒,可以按照以下步骤进行:
(1)硬件连接:
将蜂鸣器连接到STC89C52RC单片机的一个IO口上(例如P1.0)。
连接其他必要的硬件,如按键、LCD显示屏等,以实现音乐盒的控制和用户交互功能。
(2)音乐文件准备:
将音乐文件转换为适合播放的格式,例如将音乐转换为一系列音符和节拍的组合。
将转换后的音乐数据保存在单片机的程序或外部存储器中(如EEPROM或Flash存储器)。
(3)编写程序:
使用C语言编写程序来控制STC89C52RC单片机的功能。
初始化必要的硬件接口,如IO口和定时器等。
编写播放音乐的函数,根据音乐数据控制蜂鸣器发声。
编写与用户交互的代码,如按键控制、显示当前播放状态等。
考虑使用定时器来控制音乐的节奏和节拍。
(4)主循环:
在主循环中实现音乐盒的逻辑控制。
监测用户的输入,根据输入进行相应的操作,如播放、暂停、停止、切换曲目等。
调用相应的函数来控制蜂鸣器发声和更新LCD显示。
(5)调试和优化:
进行测试和调试,确保音乐盒的各项功能正常工作。
根据需要进行性能优化,如减小程序体积、优化音乐数据存储等。
请注意,以上步骤只是一个概述,并不包含具体的代码实现。实际开发中需要根据具体需求和硬件环境进行详细的设计和编码。
在具体实现过程中,可以借助STC89C52RC单片机的IO口控制蜂鸣器输出声音,并使用定时器来控制音乐的节奏和节拍。此外,还可以添加其他功能,如音量控制、曲目选择、循环播放等,以增强音乐盒的功能和用户体验。
2 蜂鸣器操作方法
在C51单片机中操作蜂鸣器的方法通常是通过控制相应的IO口输出高低电平信号来实现。以下是一种常见的方法:
首先,确定连接蜂鸣器的IO口,假设为P1.0。
然后,按照以下步骤进行操作:
设置IO口为输出模式:
P1 = P1 & 0xFE; // 将P1.0设置为输出
发出蜂鸣器声音:
P1 = P1 | 0x01; // 将P1.0置为高电平(蜂鸣器发声)
停止蜂鸣器声音:
P1 = P1 & 0xFE; // 将P1.0置为低电平(蜂鸣器停止发声)
根据具体的单片机型号和开发环境,上述代码可能需要适当修改。请确保已经正确设置了IO口的方向和状态,并且将蜂鸣器正确连接到相应的IO口。
另外,如果需要生成特定频率的声音,可以使用定时器来控制蜂鸣器的开关时间,从而实现不同频率的声音效果。这需要针对具体的单片机和定时器进行相应的配置和编程。
请注意,在使用蜂鸣器时,要特别注意电源和电流的要求,以防止对单片机和蜂鸣器造成损坏。确保根据蜂鸣器的规格和要求进行正确的电气连接和电流限制。
以上是一种简单的方法来操作蜂鸣器,具体的实现可能会因单片机型号、开发环境和需求而有所不同。
3 蜂鸣器发出音声
蜂鸣器通常通过控制电流或电压的变化来产生不同的声音效果。通过改变电流或电压的频率、持续时间和幅度,可以产生不同频率和音调的声音。
在嵌入式系统中,控制蜂鸣器发声通常通过单片机或其他电路来实现。通过控制相应的IO口输出高低电平信号或调节PWM(脉冲宽度调制)信号,可以控制蜂鸣器的开关和声音的频率,从而产生不同的音效。具体的控制方法可以根据蜂鸣器类型和使用的电路进行调整和实现。
(1)为了尽可能还原音乐,国际标准音高包含了多个音高,使用了哆唻咪发嗦来嘻(表中用1234567)的音符,并对应不同的频率。为了模拟这些音高,下表列出了9个频率对应的音高。
(2)接下来,我们可以在Excel表格中使用以下公式来快速计算各个音高对应的计数值:T = 65535 - (1 / (频率 * 2 * 1.0851)) + 1。下图显示了上述频率对应的计数值:
(3)到这一步,还需要将之前计算得到的十进制计数值转换为十六进制计数值,因为51单片机的定时器计数值由高位和低位两部分组成。为了实现这个转换,我们可以在Excel中使用函数=DEC2HEX(单元格)来将对应单元格的十进制计数值转换为十六进制计数值。下图显示了之前计算得到的十进制计数值对应的十六进制计数值:
4 硬件电路
根据原理图所示:
控制引脚需要跳线到J18的第七引脚,才能控制喇叭。
5 软件实现
(1)定时器
为了实现音乐的还原,我们使用定时器来还原音高,并使用延时函数来还原音长。设计采用定时器中断产生一定频率的方波信号,驱动无源蜂鸣器来还原音高。同时,延时函数用于控制该频率的维持时间,从而还原音长。通过这样的方式,我们可以实现简谱中一个音符的还原,将它们连贯起来就能还原整段音乐。
根据表格添加音高对应的定时器计数值常量至ROM(9个音高)
code unsigned char yingaoh[63]={
0x92,0xC8,0xE4,0xF2,0xF9,0xFC,0xFE,0xFF,0xFF, //音符1的9个音高
0x9E,0xCE,0xE7,0xF3,0xF9,0xFC,0xFE,0xFF,0xFF, //音符2的9个音高
0xA8,0xD4,0xEA,0xF5,0xFA,0xFD,0xFE,0xFF,0xFF, //音符3的9个音高
0xAD,0xD6,0xEB,0xF5,0xFA,0xFD,0xFE,0xFF,0xFF, //音符4的9个音高
0XB6,0XDB,0XED,0XF6,0XFB,0XFD,0XFE,0XFF,0XFF, //音符5的9个音高
0XBE,0XDF,0XEF,0XF7,0XFB,0XFD,0XFE,0XFF,0XFF, //音符6的9个音高
0XC5,0XE2,0XF1,0XF8,0XFC,0XFE,0XFF,0XFF,0XFF, //音符7的9个音高
}; //7个音符的9个八度高位计数值
code unsigned char yingaol[63]={
0x3C,0xF3,0x79,0x3C,0x1E,0x8F,0x47,0x23,0x91, //音符1的9个音高
0x2A,0xF3,0x79,0xBC,0xDE,0xEF,0x77,0x3B,0x9D, //音符2的9个音高
0x9D,0x4E,0x27,0x13,0x89,0x45,0xA2,0x51,0xA8, //音符3的9个音高
0x6D,0xCE,0x61,0xB0,0xD8,0x6C,0xB6,0x5B,0xAD, //音符4的9个音高
0X86,0X43,0XA1,0XD0,0X68,0XB4,0XDA,0X6D,0XB6, //音符5的9个音高
0X8A,0X45,0XA2,0XD1,0XE8,0XF4,0XFA,0X7D,0XBE, //音符6的9个音高
0XBE,0XD3,0X6C,0XB5,0X5A,0X2D,0X16,0X8B,0XC5, //音符7的9个音高
}; 7个音符的9个八度低位计数值
(2)添加音乐对应的单片机代码(爱拼才会赢)
其中,music[0]代表节拍数,music[1]代表每分钟的节拍数。数组的结尾放入0表示音乐的结束。数组中的其他值按顺序每两个值表示一个音高和维持的时间(需要通过换算计算出实际时间)。。
code unsigned char music[]={
4,89,
5,4,2,5,4,1,6,4,1,
1,5,6,6,4,2,5,4,2,
6,4,1,1,5,1,6,4,2,
5,4,2,3,4,12,3,4,2,
3,4,1,5,4,1,6,4,6,
1,5,2,5,4,2,3,5,2,
3,5,1,2,5,1,1,5,2,
2,5,12,1,5,2,2,5,2,
3,5,2,3,5,2,2,5,2,
3,5,1,2,5,1,1,5,6,
6,4,1,1,5,1,2,5,2,
2,5,2,2,5,1,1,5,1,
6,4,2,5,4,8,6,4,2,
5,4,1,6,4,1,5,4,2,
1,5,2,6,4,2,5,4,2,
3,4,2,1,4,4,2,4,12,
1,4,2,2,4,2,3,4,6,
5,4,2,5,4,2,3,4,2,
1,5,2,7,4,2,6,4,6,
6,4,2,6,4,4,1,5,2,
2,5,1,3,5,1,5,5,4,
3,5,4,2,5,2,1,5,2,
5,4,2,1,5,2,2,5,1,
3,5,1,2,5,12,3,5,1,
2,5,1,1,5,4,2,5,1,
1,5,1,6,4,4,1,5,2,
3,4,1,1,5,1,1,5,2,
6,4,2,1,5,4,6,4,1,
5,4,1,3,4,2,5,4,16,
5,4,2,6,4,2,1,5,2,
6,4,2,6,4,8,3,5,2,
3,5,2,3,5,2,3,5,1,
2,5,1,2,5,6,2,5,1,
1,5,1,6,4,6,3,5,2,
2,5,4,1,5,1,2,5,1,
1,5,1,6,4,1,1,5,16,
5,4,2,6,4,2,1,5,6,
6,4,2,5,4,2,6,4,1,
1,5,1,6,4,2,5,4,2,
3,4,12,3,4,2,3,4,1,
5,4,1,6,4,6,1,5,2,
5,4,2,3,5,2,3,5,1,
2,5,1,1,5,2,2,5,12,
1,5,2,2,5,2,3,5,2,
3,5,2,2,5,2,3,5,1,
2,5,1,1,5,6,6,4,1,
1,5,1,2,5,2,2,5,2,
2,5,1,1,5,1,6,4,2,
5,4,8,6,4,2,5,4,1,
6,4,1,5,4,2,1,5,2,
6,4,2,5,4,2,3,4,2,
1,4,4,2,4,12,1,4,2,
2,4,2,3,4,6,5,4,2,
5,4,2,3,4,2,1,5,2,
7,4,2,6,4,6,6,4,2,
6,4,4,1,5,2,2,5,1,
3,5,1,5,5,2,3,5,4,
2,5,2,1,5,2,5,4,2,
1,5,2,2,5,1,3,5,1,
2,5,12,3,5,1,2,5,1,
1,5,4,2,5,1,1,5,1,
6,4,4,1,5,2,3,4,1,
1,5,1,1,5,2,6,4,2,
1,5,4,6,4,1,5,4,1,
3,4,2,5,4,16,5,4,2,
6,4,2,1,5,2,6,4,2,
6,4,8,3,5,2,3,5,2,
3,5,2,3,5,1,2,5,1,
2,5,6,2,5,1,1,5,1,
6,4,6,3,5,2,2,5,4,
1,5,1,2,5,1,1,5,1,
6,4,1,1,5,16,1,4,2,
2,4,2,3,4,6,5,4,2,
5,4,2,3,4,2,1,5,2,
7,4,2,6,4,6,6,4,2,
6,4,4,1,5,2,2,5,1,
3,5,1,5,5,4,3,5,4,
2,5,2,1,5,2,5,4,2,
1,5,2,2,5,1,3,5,1,
2,5,12,3,5,1,2,5,1,
1,5,4,2,5,1,1,5,1,
6,4,4,1,5,2,3,4,1,
1,5,1,1,5,2,6,4,2,
1,5,4,6,4,1,5,4,1,
3,4,2,5,4,16,5,4,2,
6,4,2,1,5,2,6,4,2,
6,4,8,3,5,2,3,5,2,
3,5,2,3,5,1,2,5,1,
2,5,6,2,5,1,1,5,1,
6,4,6,3,5,2,2,5,4,
1,5,1,2,5,1,1,5,1,
6,4,1,1,5,16,0
};
(3)实现音高的控制程序
//使用定时器方式,实现发音的频率来实现音高
void sys_music_init(void)
{
TMOD=0x01; //置T0定时器工作在方式1
EA=1; //开总中断
ET0=1; //开定时器0中断,这两句等效于IE=0x82
TR0=1; //开定时器0
}
//音高模拟函数实际上就是利用定时器中断产生一定频率方波驱动蜂鸣器发出一定频率的声音。
void music_t0_isr() interrupt 1 //定时器0中断函数
{
TR0=0; //关闭定时器TR0
BEEP=!BEEP; //蜂鸣状态取反
TH0=timeh; //把timeh赋给定时0高位计数值
TL0=timel; //把timel赋给定时0低位计数值
TR0=1; //开定时器TR0
}
void music_delay(unsigned int t) //节拍延时函数
{
//根据每分钟节拍数,求解四分之一音符保持时长,四舍五入单位为10ms
unsigned int time;
unsigned int time_tmp = 0;
//1000*((60/M1)) *t/M0
time_tmp = (unsigned int)music[1]*(unsigned int)music[0];
//time=15000UL*t/time_tmp; //根据节拍算出10ms的计数次数
time = 80*t;
delay_ms(time);
//TR0=0;
}
void sys_music_test(void)
{
unsigned char m,n;
m=(music[buf_i]-1)*9+music[buf_i+1]; //获取音符对应计数值所在下标
n=music[buf_i+2]; //获取音符保持时长值
timeh=yingaoh[m]; //获取音符对应定时器计数值高位
timel=yingaol[m]; //获取音符对应定时器计数值低位
TH0=timeh; //把timeh赋给定时0高位计数值
TL0=timel; //把timel赋给定时0低位计数值
//TR0=1; //开定时器0
music_delay(n); //执行音符保持函数
buf_i=buf_i+3; //读下一个音符
if(music[buf_i]==0)
{
buf_i=2; //如果到末尾则回到开头,循环播放
}
}
6 整体工程:
//main.c文件
#include "includes.h"
/******************************************************************/
/* 微秒延时函数 //10us */
/******************************************************************/
void delay_us(unsigned int us)//delay us
{
while(us--)
{
}
}
/******************************************************************/
/* 微秒延时函数 */
/******************************************************************/
void delay_ms(unsigned int Ms)//delay us
{
while(Ms--)
{
delay_us(100);
}
}
/*------------------------------------------------
延时子程序
------------------------------------------------*/
void delay(unsigned int cnt)
{
while(--cnt);
}
/*------------------------------------------------
主函数
------------------------------------------------*/
void main (void)
{
sys_music_init();
delay(10);
delay_ms(1);
sys_keynum_ledon(1,0);
buf_i = 2;
while(1)
{
sys_music_test();
}
}
//includes.h文件
#ifndef __INCLUDES_H__
#define __INCLUDES_H__
//#include<reg52.h>
#include<intrins.h> //汇编指令_nop_
#include<stdio.h> //标准输入输出
//_nop_(); 产生一条NOP指令
//作用:对于延时很短的,要求在us级的,采用“_nop_”函数,这个函数相当汇编NOP指令,延时几微秒。
//NOP指令为单周期指令,可由晶振频率算出延时时间。
//8051 为每个机器周期 12 时钟
//对于12M晶振,延时1uS。
//11.0592M晶振,延时1.0851uS。
//对于延时比较长的,要求在大于10us,采用C51中的循环语句来实现。
//包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include "STC89C5xRC_RDP.h"
//应用层头文件
//#include "c51_gpio.h"
#include "c51_ledtube.h"
//#include "c51_key.h"
//#include "c51_timer.h"
//#include "c51_exit.h"
//#include "c51_lcd1602.h"
//#include "c51_iic.h"
//#include "c51_tx1838.h"
//#include "c51_uart.h"
#include "c51_music.h"
extern void delay(unsigned int cnt);
extern void delay_us(unsigned int us);//delay us;
extern void delay_ms(unsigned int Ms);//delay Ms;
#endif
//c51_ledtube.c文件
#include "includes.h"
// 显示段码值01234567,可对应原理图查看显示不同图形对应的引脚高点电平配置状态
unsigned char const EL[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,\
0x77,0x7c,0x39,0x5e,0x79,0x71};//0-F
///********************************************************
//函数名称:sys_ledtube_on1
//函数功能:点亮一个数码管全为亮起来
//入口参数:
//出口参数:
//修 改:
//内 容:
//********************************************************/
//void sys_ledtube_on1(void)
//{
// //根据原理图,将P0口全部输出高电平,P2选择0号数码管
// P0=0xFF;//取显示数据,段码
// P2=0; //取位码
//}
///********************************************************
//函数名称:sys_ledtube_on2
//函数功能:显示一组数据
//入口参数:
//出口参数:
//修 改:
//内 容:
//********************************************************/
//static unsigned char ledtube_cnt = 0;
//void sys_ledtube_on2(void)
//{
// ledtube_cnt++;
// if(ledtube_cnt>7)
// {
// ledtube_cnt = 0;
// }
// P0 = 0x00; //防止切换数码管瞬间有虚影出现
// P2 = 0x00;
// P0 = EL[ledtube_cnt]; //取显示数据,段码
// P2 = ledtube_cnt; //取位码
//
// //根据人眼适应虚影缓冲时间为50ms左右
// //我们调整delay在500以下可以看到明显的看起来是一串数据一起显示
// delay(100);
//}
/********************************************************
函数名称:sys_keynum_ledon
函数功能:显示按键数值
入口参数:按键数值
出口参数:
修 改:
内 容:
********************************************************/
void sys_keynum_ledon(unsigned char num,unsigned char pn)
{
//根据原理图,将P0口全部输出高电平,P2选择0号数码管
P0 = 0x00; //防止切换数码管瞬间有虚影出现
P2 = pn; //取位码
P0 = EL[num]; //取显示数据,段码
}
//c51_music.c 文件
#include "includes.h"
unsigned char timeh=0;
unsigned char timel=0;//TR0计数器高位值、低位值
unsigned int buf_i = 2;
code unsigned char yingaoh[63]={
0x92,0xC8,0xE4,0xF2,0xF9,0xFC,0xFE,0xFF,0xFF, //音符1的9个音高
0x9E,0xCE,0xE7,0xF3,0xF9,0xFC,0xFE,0xFF,0xFF, //音符2的9个音高
0xA8,0xD4,0xEA,0xF5,0xFA,0xFD,0xFE,0xFF,0xFF, //音符3的9个音高
0xAD,0xD6,0xEB,0xF5,0xFA,0xFD,0xFE,0xFF,0xFF, //音符4的9个音高
0XB6,0XDB,0XED,0XF6,0XFB,0XFD,0XFE,0XFF,0XFF, //音符5的9个音高
0XBE,0XDF,0XEF,0XF7,0XFB,0XFD,0XFE,0XFF,0XFF, //音符6的9个音高
0XC5,0XE2,0XF1,0XF8,0XFC,0XFE,0XFF,0XFF,0XFF, //音符7的9个音高
}; //7个音符的9个八度高位计数值
code unsigned char yingaol[63]={
0x3C,0xF3,0x79,0x3C,0x1E,0x8F,0x47,0x23,0x91, //音符1的9个音高
0x2A,0xF3,0x79,0xBC,0xDE,0xEF,0x77,0x3B,0x9D, //音符2的9个音高
0x9D,0x4E,0x27,0x13,0x89,0x45,0xA2,0x51,0xA8, //音符3的9个音高
0x6D,0xCE,0x61,0xB0,0xD8,0x6C,0xB6,0x5B,0xAD, //音符4的9个音高
0X86,0X43,0XA1,0XD0,0X68,0XB4,0XDA,0X6D,0XB6, //音符5的9个音高
0X8A,0X45,0XA2,0XD1,0XE8,0XF4,0XFA,0X7D,0XBE, //音符6的9个音高
0XBE,0XD3,0X6C,0XB5,0X5A,0X2D,0X16,0X8B,0XC5, //音符7的9个音高
}; //7个音符的9个八度低位计数值
code unsigned char music[]={
4,89,
5,4,2,5,4,1,6,4,1,
1,5,6,6,4,2,5,4,2,
6,4,1,1,5,1,6,4,2,
5,4,2,3,4,12,3,4,2,
3,4,1,5,4,1,6,4,6,
1,5,2,5,4,2,3,5,2,
3,5,1,2,5,1,1,5,2,
2,5,12,1,5,2,2,5,2,
3,5,2,3,5,2,2,5,2,
3,5,1,2,5,1,1,5,6,
6,4,1,1,5,1,2,5,2,
2,5,2,2,5,1,1,5,1,
6,4,2,5,4,8,6,4,2,
5,4,1,6,4,1,5,4,2,
1,5,2,6,4,2,5,4,2,
3,4,2,1,4,4,2,4,12,
1,4,2,2,4,2,3,4,6,
5,4,2,5,4,2,3,4,2,
1,5,2,7,4,2,6,4,6,
6,4,2,6,4,4,1,5,2,
2,5,1,3,5,1,5,5,4,
3,5,4,2,5,2,1,5,2,
5,4,2,1,5,2,2,5,1,
3,5,1,2,5,12,3,5,1,
2,5,1,1,5,4,2,5,1,
1,5,1,6,4,4,1,5,2,
3,4,1,1,5,1,1,5,2,
6,4,2,1,5,4,6,4,1,
5,4,1,3,4,2,5,4,16,
5,4,2,6,4,2,1,5,2,
6,4,2,6,4,8,3,5,2,
3,5,2,3,5,2,3,5,1,
2,5,1,2,5,6,2,5,1,
1,5,1,6,4,6,3,5,2,
2,5,4,1,5,1,2,5,1,
1,5,1,6,4,1,1,5,16,
5,4,2,6,4,2,1,5,6,
6,4,2,5,4,2,6,4,1,
1,5,1,6,4,2,5,4,2,
3,4,12,3,4,2,3,4,1,
5,4,1,6,4,6,1,5,2,
5,4,2,3,5,2,3,5,1,
2,5,1,1,5,2,2,5,12,
1,5,2,2,5,2,3,5,2,
3,5,2,2,5,2,3,5,1,
2,5,1,1,5,6,6,4,1,
1,5,1,2,5,2,2,5,2,
2,5,1,1,5,1,6,4,2,
5,4,8,6,4,2,5,4,1,
6,4,1,5,4,2,1,5,2,
6,4,2,5,4,2,3,4,2,
1,4,4,2,4,12,1,4,2,
2,4,2,3,4,6,5,4,2,
5,4,2,3,4,2,1,5,2,
7,4,2,6,4,6,6,4,2,
6,4,4,1,5,2,2,5,1,
3,5,1,5,5,2,3,5,4,
2,5,2,1,5,2,5,4,2,
1,5,2,2,5,1,3,5,1,
2,5,12,3,5,1,2,5,1,
1,5,4,2,5,1,1,5,1,
6,4,4,1,5,2,3,4,1,
1,5,1,1,5,2,6,4,2,
1,5,4,6,4,1,5,4,1,
3,4,2,5,4,16,5,4,2,
6,4,2,1,5,2,6,4,2,
6,4,8,3,5,2,3,5,2,
3,5,2,3,5,1,2,5,1,
2,5,6,2,5,1,1,5,1,
6,4,6,3,5,2,2,5,4,
1,5,1,2,5,1,1,5,1,
6,4,1,1,5,16,1,4,2,
2,4,2,3,4,6,5,4,2,
5,4,2,3,4,2,1,5,2,
7,4,2,6,4,6,6,4,2,
6,4,4,1,5,2,2,5,1,
3,5,1,5,5,4,3,5,4,
2,5,2,1,5,2,5,4,2,
1,5,2,2,5,1,3,5,1,
2,5,12,3,5,1,2,5,1,
1,5,4,2,5,1,1,5,1,
6,4,4,1,5,2,3,4,1,
1,5,1,1,5,2,6,4,2,
1,5,4,6,4,1,5,4,1,
3,4,2,5,4,16,5,4,2,
6,4,2,1,5,2,6,4,2,
6,4,8,3,5,2,3,5,2,
3,5,2,3,5,1,2,5,1,
2,5,6,2,5,1,1,5,1,
6,4,6,3,5,2,2,5,4,
1,5,1,2,5,1,1,5,1,
6,4,1,1,5,16,0
};
//使用定时器方式,实现发音的频率来实现音高
void sys_music_init(void)
{
TMOD=0x01; //置T0定时器工作在方式1
EA=1; //开总中断
ET0=1; //开定时器0中断,这两句等效于IE=0x82
TR0=1; //开定时器0
}
//音高模拟函数实际上就是利用定时器中断产生一定频率方波驱动蜂鸣器发出一定频率的声音。
void music_t0_isr() interrupt 1 //定时器0中断函数
{
TR0=0; //关闭定时器TR0
BEEP=!BEEP; //蜂鸣状态取反
TH0=timeh; //把timeh赋给定时0高位计数值
TL0=timel; //把timel赋给定时0低位计数值
TR0=1; //开定时器TR0
}
void music_delay(unsigned int t) //节拍延时函数
{
//根据每分钟节拍数,求解四分之一音符保持时长,四舍五入单位为10ms
unsigned int time;
unsigned int time_tmp = 0;
//1000*((60/M1)) *t/M0
time_tmp = (unsigned int)music[1]*(unsigned int)music[0];
//time=15000UL*t/time_tmp; //根据节拍算出10ms的计数次数
time = 168*t;
delay_ms(time);
//TR0=0;
}
void sys_music_test(void)
{
unsigned char m,n;
m=(music[buf_i]-1)*9+music[buf_i+1]; //获取音符对应计数值所在下标
n=music[buf_i+2]; //获取音符保持时长值
timeh=yingaoh[m]; //获取音符对应定时器计数值高位
timel=yingaol[m]; //获取音符对应定时器计数值低位
TH0=timeh; //把timeh赋给定时0高位计数值
TL0=timel; //把timel赋给定时0低位计数值
//TR0=1; //开定时器0
music_delay(n); //执行音符保持函数
buf_i=buf_i+3; //读下一个音符
if(music[buf_i]==0)
{
buf_i=2; //如果到末尾则回到开头,循环播放
}
}
//c51_music.h文件
#ifndef __C51_MUSIC_H__
#define __C51_MUSIC_H__
#define BEEP P12
extern unsigned char timeh;
extern unsigned char timel;//TR0计数器高位值、低位值
extern unsigned int buf_i;
extern void sys_music_init(void);
extern void music_t0_isr();
extern void music_delay(unsigned int t); //节拍延时函数
extern void sys_music_test(void);
#endif
//c51_ledtube.h文件
#ifndef __C51_LEDTUBE_H__
#define __C51_LEDTUBE_H__
extern unsigned char const EL[];
//extern void sys_ledtube_on1(void);
//extern void sys_ledtube_on2(void);
extern void sys_keynum_ledon(unsigned char num,unsigned char pn);
#endif
7 总结
蜂鸣器操作的一般总结:
(1)硬件连接:
将蜂鸣器连接到单片机的一个IO口上,通常使用GPIO口。
(2)初始化:
在程序开始时,需要对相关IO口进行初始化,将其配置为输出模式。
(3)发出声音:
要使蜂鸣器发出声音,将相应的IO口置高电平(或低电平,具体根据电路设计而定)即可。
通过控制IO口的电平状态,可以控制蜂鸣器的开关状态。
(4)延时:
要控制蜂鸣器发声的时间长度,可以使用延时函数。
在C51中,常用的延时函数包括delay、_nop_等,它们可以提供一定的延时效果。
(5)控制频率和音调:
要实现不同的频率和音调,可以使用定时器功能。
在C51中,可以通过配置定时器相关寄存器,设置定时器的工作方式、计数值和预分频等,从而控制定时器的频率和周期。
通过定时器中断,可以实现产生一定频率的方波信号,驱动蜂鸣器发声。
(6)停止声音:
要停止蜂鸣器的声音,将相应的IO口置低电平(或高电平)即可。
需要注意的是,具体的蜂鸣器操作步骤和代码实现可能会根据使用的单片机型号和编程环境而有所差异。在编写程序时,可以参考相关的单片机手册和编程指南,以及使用的开发工具提供的文档和示例代码。