蜂鸣器应用之播放音乐(STC89C52RC为例)

蜂鸣器原理

乐谱说明

#是升半音(右上角)

b为降半音

分为全音符,二分音符,四分音符。。。。

一般四分音符1为500ms,二分音符为1s=1000ms,数字下面加一根线是250ms

以四分音符为一拍,每小节有4拍

右边加一个点,相当于加上半拍

这左上角有个符号,表示需要按下右上角的升音键(#)黑键

上面这条线叫做延音线

C调音符与频率对照表

以a为基准频率是440Hz,左右两边都是倍数关系,中间是按照等比数列进行平分

以上一个为基准,然后按照这个公式算出结果(满足:12频分率)

算出周期(s)

因为一个周期是需要上去,再下来

然后就可以算出重装载值

完整代码(蜂鸣器播放提示音)

//main.c


#include <REGX52.H>
#include "Key.h"
#include "Delay.h"
#include "Nixie.h"
#include "Buzzer.h"

unsigned char KeyNum;
void main()
{
	while(1){
		KeyNum=Key();
    if(KeyNum)
    { 
      Buzzer_Time(1000);
      Nixie(1,KeyNum);
    }
	}
}
//Key.c


#include <REGX52.H>
#include "Delay.h"
/**
  * @brief 获取独立按键码
  * @param  无  
  * @retval  按下按键的键码,范围:0~4,无按键按下时返回值为0
  */
unsigned char Key()
{
  unsigned char KeyNumber=0;
  
  if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
  if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
  if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
  if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}

  return KeyNumber;
}

//key.h

#ifndef __KEY_H__
#define __KEY_H__
  unsigned char Key();

#endif
//Delay.c

void Delay(unsigned int xms)	
{	while(xms--){
	unsigned char data i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i); }
}
//Delay.h

#ifndef __DELAY_H__
#define __DELAY_H__
	void Delay(unsigned int xms);
#endif
//Buzzer.h

#ifndef __BUZZER_H__
#define __BUZZER_H__
	void Buzzer_Time(unsigned int time);
#endif
//Buzzer.c

#include <REGX52.H>
#include <INTRINS.H>

//蜂鸣器端口:
sbit Buzzer=P0^6;//蜂鸣器

/**
  * @brief 蜂鸣器私有延时函数,延时500us
  * @param    无
  * @retval  无
  */
void Buzzer_Delay500us()		//@12.000MHz
{
	unsigned char i;

	_nop_();
	i = 247;
	while (--i);
}

/**
  * @brief 蜂鸣器发生
  * @param    ms 发生的时长
  * @retval  无
  */
void Buzzer_Time(unsigned int ms){
  unsigned int i;
  for(i=0;i<=ms*2;i++)
      {
        Buzzer=!Buzzer;
        //500us翻转一次,1000Hz
        Buzzer_Delay500us();//这个是毫秒级的,每格一毫秒翻转一次(高电平一毫秒,低电平一毫秒,一个周期就是两毫秒)
      } 
}
//Nixie.h

#ifndef __NIXIE_H__
#define __NIXIE_H__
  void Nixie(unsigned char Location,Number);

#endif
//Nixie.c

#include <REGX52.H>
#include "Delay.h"
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x7,0x7F,0x6F};
//利用数组,将数字和灯的二进制形式联系起来

/**
  * @brief  动态显示数码管显示
  * @param    Location表示位置,范围:1~8。Number表示想要的数字
  * @retval  
  */
void Nixie(unsigned char Location,Number){   //利用调用函数(包含位置和数字),让成像更加的方便
	switch(Location){	 //利用switch函数实现对多重情况的分类
		case 1:P2_4=1;P2_3=1;P2_2=1;break;
		case 2:P2_4=1;P2_3=1;P2_2=0;break;
		case 3:P2_4=1;P2_3=0;P2_2=1;break;
		case 4:P2_4=1;P2_3=0;P2_2=0;break;
		case 5:P2_4=0;P2_3=1;P2_2=1;break;
		case 6:P2_4=0;P2_3=1;P2_2=0;break;
		case 7:P2_4=0;P2_3=0;P2_2=1;break;
		case 8:P2_4=0;P2_3=0;P2_2=0;break;
	}
	P0=NixieTable[Number];//输出想要的数字
//  Delay(1); 
//  P0_0=0x00;

}

完整程序(蜂鸣器播放音乐)

//main.c

#include <REGX52.H>
#include "Delay.h"
#include "Timer0.h"

#define SPEED 250//方便修改演唱的速度500为半拍

#define P 0//休止符
#define LL1 1
#define LL1_ 2
#define LL2 3
#define LL2_ 4
#define LL3 5
#define LL4 6
#define LL4_ 7
#define LL5 8
#define LL5_ 9
#define LL6 10
#define LL6_ 11
#define LL7 12
#define L1 13
#define L1_ 14
#define L2 15
#define L2_ 16
#define L3 17
#define L4 18
#define L4_ 19
#define L5 20
#define L5_ 21
#define L6  22
#define L6_ 23
#define L7 24
#define M1 25
#define M1_ 26
#define M2 27
#define M2_ 28
#define M3 29
#define M4 30
#define M4_ 31
#define M5 32
#define M5_ 33
#define M6 34
#define M6_ 35
#define M7 36
#define H1 37
#define H1_ 38
#define H2 39
#define H2_ 40
#define H3 41
#define H4 42
#define H4_ 43
#define H5 44
#define H5_ 45
#define H6 46
#define H6_ 47
#define H7 48
#define HH1 49
#define HH1_ 50
#define HH2 51
#define HH2_ 52
#define HH3 53
#define HH4 54
#define HH4_ 55
#define HH5 56
#define HH5_ 57
#define HH6 58
#define HH6_ 59
#define HH7 60


sbit Bezzer=P2^5;//蜂鸣器的串口
sbit Key1=P3^1;
sbit Key2=P3^0;
sbit Key3=P3^2;
sbit Key4=P3^3;

//蜂鸣器各个音符高低音数组,(与定时器连用)
unsigned int code FreqTable[]={
  0/*表示休止符*/,
  56733,58761,60029,60898,61530,62010,62387,62692,62943,63153,63331,63485,
  63628,63731,63835,63928,64021,64103,64185,64260,64331,64400,64463,64528,
  64580,64633,64684,64732,64777,64820,64860,64898,64934,64968,65000,65030,
  65058,65085,65110,65134,65157,65178,65198,65217,65235,65252,65268,65283,
  65290,65300,65310,65318,65327,65334,65341,65348,65354,65359,65365,65370

};

//写入谱子(索引),后面跟的是多少个16分音符,也就是半拍

//梦灯笼
unsigned char code Music1[]={
   
  //1
  H1,8+8,
  L5,2,
  M1,2,
  M2,2,
  M5,2,
  M1,4,
  M5,4,
  
  //2
  M5,8+8,
  P,4,
  H1,8+4,
  
  //3
  M5,4,
  M1,2,
  M6,2,
  M6,2,
  M5,2,
  M1,4,
  L5,2,
  L6,2,
  M1,4,
  L5,4,
  L4,4,
  
  //4
  M5,4,
  M1,2,
  L7,2,
  P,4,
  M1,4,
  P,2,
  M1,4,
  M2,2,
  M3,2,
  M5,2,
  M3,2,
  
  //5
  L5,8+8,
  L1,8+8,
  
  //6
  L4,4,
  M1,4,
  M2,4,
  L5,4,
  M1,8,
  L3,2,
  L4,2,
  M1,4,
  
  //7
  L5,8+8,
  L4,8+8,
  
  //8
  L1,8+8+8+8,
  
  
  
  
  
  0xff
};

//红色高跟鞋
unsigned char code Music2[]={
   
  //1
  P,4,
  H3,2,
  H3,2,
  H3,2,
  H3,2,
  H2,4,
  M7,8,
  M7,4,
  H1,4,
  
  //2
  H1,4,
  H1,4,
  M6,4,
  H1,4,
  H1,8+8,
  
  //3
  P,4,
  H3,2,
  H3,2,
  H3,2,
  H3,2,
  H2,4,
  M7,8,
  M7,4,
  H1,4,

  //4
  H1,4,
  H1,4,
  M6,4,
  H1,4,
  H1,8+8,
  
  
  0xff
};



//see you again
unsigned char code Music3[]={
  //1
  M5,4,
  H2,4,
  H1,4,
  M5,4+4,
  H1,2,
  H2,2,
  H3,2,
  H2,2,
  H1,2,
  H2,2,
  
  //2
  M5,4,
  H2,4,
  H1,4,
  M5,4+4,
  H1,2,
  H2,2,
  H3,2,
  H2,2,
  H1,2,
  H2,2,
  
  //3
  M5,4,
  H2,4,
  H1,4,
  M5,4+4,
  H1,2,
  H2,2,
  H3,2,
  H2,2,
  H1,2,
  H2,2,
  
  //4
  M5,4,
  H2,4,
  H1,4,
  M5,4,
  M1,4,
  M3,4,
  M5,4,
  
  //5
  M6,8+4,
  M5,4,
  M5,8,
  P,8+4,
  M1,2,
  
  //6
  M2,4,
  M2,4,
  M1,4,
  M2,4,
  M3,8,
  P,4,
  M3,2,
  M5,2,
  
  //7
  M6,4,
  M7,4,
  M6,4,
  M5,4,
  M3,4,
  M2,4,
  M2_,4,
  M1,4,
  
  0XFF
};

小星星
//unsigned char Music[]={
//    12+1,4,
//    12+1,4,
//    19+1,4,
//    19+1,4,
//    21+1,4,
//    21+1,4,
//    19+1,4+4,
//    17+1,4,
//    0,4,
//    17+1,4,
//    16+1,4,
//    16+1,4,
//    14+1,4,
//    14+1,4,
//    12+1,4+4,
//  
//    0xFF/*用于结束*/
//};

//晴天
unsigned char code Music4[]={
  //1
  L3,4,
  L5,4,
  M2,4,
  L5,4,
  L1,4,
  L2,2,
  L3,2,
  M2,4,
  L5,4,
  
  //2
  LL5,4,
  L2,4,
  M2,4,
  L5,4,
  LL5,4,
  L2,4,
  LL4_,4,
  L2,4,
  
  //3
  L3,4,
  L5,4,
  M2,4,
  L3,4,
  L1,4,
  L2,2,
  L3,2,
  M2,4,
  L5,4,
  
  //4
  LL5,4,
  L2,4,
  M2,4,
  L5,4,
  LL5,4,
  L2,4,
  LL4_,2,
  L5,2,
  L2,4,
  
  //5
  L3,4,
  L5,4,
  M2,4,
  L5,4,
  L1,4,
  L2,2,
  L3,2,
  M2,4,
  L5,4,
  
  //6
  LL5,4,
  L2,4,
  M2,4,
  L5,4,
  LL5,4,
  L2,4,
  LL4_,4,
  L2,4,
  
  //6
  L3,4,
  L5,4,
  M2,4,
  L3,4,
  L1,4,
  L2,2,
  L3,2,
  M2,4,
  L5,4,
  
  //7
  LL5,4,
  L2,4,
  M2,4,
  L5,4,
  LL5,4,
  L2,4,
  LL4_,2,
  L5,2,
  L2,4,
  
  0XFF
};

unsigned char FreqSelect,MusicSelect;//频率选择

void main(){
  Timer0Init();
	while(1){
    
    if(Key1==0)
    {
      while(Music1[MusicSelect]!=0xff)
      {
        FreqSelect=Music1[MusicSelect];
        MusicSelect++;
        Delay(SPEED/4*Music1[MusicSelect]);//以16分音符为基准
        MusicSelect++;
        TR0=0;//模拟抬手
        Delay(5);
        TR0=1;
      }
      TR0=0;
    }
    
    if(Key2==0)
    {
      while(Music2[MusicSelect]!=0xff)
      {
        FreqSelect=Music2[MusicSelect];
        MusicSelect++;
        Delay(SPEED/4*Music2[MusicSelect]);//以16分音符为基准
        MusicSelect++;
        TR0=0;//模拟抬手
        Delay(5);
        TR0=1;
      }
      TR0=0;
    }
    
    if(Key3==0)
    {
      while(Music3[MusicSelect]!=0xff)
      {
        FreqSelect=Music3[MusicSelect];
        MusicSelect++;
        Delay(SPEED/4*Music3[MusicSelect]);//以16分音符为基准
        MusicSelect++;
        TR0=0;//模拟抬手
        Delay(5);
        TR0=1;
      }
      TR0=0;
    }
    
    if(Key4==0)
    {
      while(Music4[MusicSelect]!=0xff)
      {
        FreqSelect=Music4[MusicSelect];
        MusicSelect++;
        Delay(SPEED/4*Music4[MusicSelect]);//以16分音符为基准
        MusicSelect++;
        TR0=0;//模拟抬手
        Delay(5);
        TR0=1;
      }
      TR0=0;
    }
    
	}
}

//定时器中断函数模板
void Timer0_Routine() interrupt 1
{
  if(FreqTable[FreqSelect])//如果是休止符就不发声
  {
    TL0 = FreqTable[FreqSelect]%256;		
    TH0 = FreqTable[FreqSelect]/256;//为了防止溢出过后,初始值会发生变化,所以在这里需要重置一下
    Bezzer=!Bezzer;//直接进行翻转,(1ms,频率=1s/周期=> f=1s/2ms=500hz )
  }
}
//Timer0.c

#ifndef __TIMER0_H__
#define __TIMER0_H__
  void Timer0Init(void);		//1毫秒@12.000MHz

#endif
//Timer0.c

#include <REGX51.H>
/**
  * @brief 定时器初始化,1毫秒@12.000MHz
  * @param   无 
  * @retval  无
  */
  

void Timer0Init(void)		//1毫秒@12.000MHz
{
//	AUXR &= 0x7F;		//定时器时钟12T模式//这句话在旧版的89C52中是可以删去的
	TMOD &= 0xF0;		//设置定时器模式//用来设置工作方式(高四位)(用来设置T1的工方式)
	TMOD |= 0x01;		//设置定时器模式//用来设置工作方式(高四位)(用来设置T0的工方式)
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
  //上面是ISP生成
  
  //下面是自己写
  ET0=1;//打开中断的第一个开关
  EA=1;//打开第二个开关
  PT0=0;//打开第三个开关
}


/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
  static unsigned int T0Count;//定义静态变量//定义了一个新的函数,用来尝试计时一分钟
  //计数器是同步计数,起始值是64536计时才是1ms。
  TH0=64535/256;
  TL0=64535%256;//为了防止溢出过后,初始值会发生变化,所以在这里需要重置一下
  T0Count++;//来计中断的次数
  if(T0Count>=1000){
    T0Count=0;//将T0Count恢复原值
  P2_0=~P2_0;//表示在执行Timer0_Init()的时候,主函数中虽然没有写Timer0_Routine()但还是会点亮灯,这就说明中断起到了作用
  }
}
*/
//Delay.h

#ifndef __DELAY_H__
#define __DELAY_H__
	void Delay(unsigned int xms);
#endif

  • 0
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
STC89C52RC芯片的蜂鸣器可以通过PWM控制,从而实现放音乐的效果。以下是一个简单的示例程序,演示如何通过PWM控制蜂鸣器播放“小星星”的旋律: ``` #include <reg52.h> // 包含STC89C52RC的寄存器定义 sbit beep=P1^5; // P1.5口连接蜂鸣器 // 定义“小星星”的音符频率,0表示休止符 unsigned int freq[] = {262, 262, 392, 392, 440, 440, 392, 0, 349, 349, 330, 330, 294, 294, 262, 0, 392, 392, 349, 349, 330, 330, 294, 0, 392, 392, 349, 349, 330, 330, 294, 0, 262, 262, 392, 392, 440, 440, 392, 0, 349, 349, 330, 330, 294, 294, 262, 0}; // 定义“小星星”的音符时长,单位为ms unsigned int duration[] = {500, 500, 500, 500, 500, 500, 1000, 500, 500, 500, 500, 500, 500, 500, 1000, 500, 500, 500, 500, 500, 500, 500, 1000, 500, 500, 500, 500, 500, 500, 500, 1000, 500, 500, 500, 500, 500, 500, 500, 1000, 500, 500, 500, 500, 500, 500, 500, 1000, 500}; void delay_ms(unsigned int ms) // 延时函数 { unsigned int i,j; for(i=0;i<ms;i++) for(j=0;j<114;j++); } void beep_on(unsigned int freq) // 打开蜂鸣器 { unsigned int n; n = 1000000 / freq / 2; // 计算PWM值 TH0 = n / 256; // 设置定时器初值 TL0 = n % 256; TR0 = 1; // 启动定时器 } void beep_off() // 关闭蜂鸣器 { TR0 = 0; // 停止定时器 beep = 0; // 蜂鸣器输出低电平 } void main() { unsigned int i; TMOD = 0x01; // 设置定时器0为16位自动重载模式 for(i=0;i<sizeof(freq)/sizeof(unsigned int);i++) { beep_on(freq[i]); // 打开蜂鸣器 delay_ms(duration[i]); // 延时 beep_off(); // 关闭蜂鸣器 delay_ms(50); // 音符之间的间隔 } } ``` 在上述代码中,通过PWM控制蜂鸣器发出不同频率的声音,从而实现播放旋律的效果。本例中,程序通过控制定时器0的初值实现PWM控制,每隔一段时间改变一次初值,从而改变蜂鸣器的频率。您可以修改freq数组和duration数组来定义不同的旋律和节奏,以实现不同的音乐效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LYPHARD MELODY。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值