⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 test025.c

📁 51单片机全套学习资料 提供电路原理图 各种C语言实验程序 包括LED流水灯,数码管显示,中断,定时器,串口通信,DS18B20温度显示,液晶1602,12864显示,看门狗,按键检测,音乐播放等程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/********************************************************************************************
* 文 件 名:test025.c
* 功    能:单片机播放音乐演示。
* 硬件条件:1.CPU型号:AT89S52
*           2.晶振:12.000MHz
*           3.用跳线帽短接BEEP_P1.3
*           4.用跳线帽短接P2.3__SI2
*             用跳线帽短接P2.2__RCK2
*             用跳线帽短接P2.1__SCK2
* 注    意:使用无源蜂鸣器可以达到较好的播放效果。
* 说    明:========================================================================================
*           曲谱存储格式: uint8 code MusicName{音高,音长,音高,音长...., 0,0}; 末尾的0,0 表示结束。
*
*           音高由三位数字组成:
*               个位是表示 1~7 这七个音符 
*               十位是表示音符所在的音区:1-低音,2-中音,3-高音;
*               百位表示这个音符是否要升半音: 0-不升,1-升半音。
*
*           音长最多由三位数字组成: 
*               个位表示音符的时值,其对应关系是: 
*                   |数值(n):  |0 |1 |2 |3 | 4 | 5 | 6 
*                   |几分音符: |1 |2 |4 |8 |16 |32 |64   音符=2^n
*               十位表示音符的演奏效果(0-2):  0-普通,1-连音,2-顿音
*               百位是符点位: 0-无符点,1-有符点
*           ========================================================================================
* 作    者:POWER
* 声    明:本程序调用了由Jiang jian jun编写的单片机播放简谱的库函数,在此对他表示感谢!
* 日    期:2006年12月12号
* 斯凯科技主页:www.armsky.net
* 斯凯科技论坛:www.armsky.net/bbs
*********************************************************************************************/
#include "reg52.h"                               // 包含头文件    

/* 与编译器无关的数据类型定义 */
/********************************************************************************************/
typedef unsigned char      uint8;                // 无符号8位整型变量
typedef signed   char      int8;                 // 有符号8位整型变量
typedef unsigned short     uint16;               // 无符号16位整型变量
typedef signed   short     int16;                // 有符号16位整型变量
typedef unsigned int       uint32;               // 无符号32位整型变量
typedef signed   int       int32;                // 有符号32位整型变量
typedef float              fp32;                 // 单精度浮点数(32位长度)
typedef double             fp64;                 // 双精度浮点数(64位长度)
/********************************************************************************************/

/* 定义位变量 */
sbit BEEP = P1 ^ 3;                              // 定义蜂鸣器控制引脚
sbit P2_3 = P2 ^ 3;                              
sbit P2_2 = P2 ^ 2;
sbit P2_1 = P2 ^ 1;                                                

#define SI2_H()       (P2_3=1)                   // 定义"SI2_H()"为P2.3输出高电平,作为74HC595_2的数据输入信号
#define SI2_L()       (P2_3=0)                   // 定义"SI2_L()"为P2.3输出低电平,作为74HC595_2的数据输入信号  

#define RCK2_H()      (P2_2=1)                   // 定义"RCK2_H()"为P2.2输出高电平,作为74HC595_2的片选输入信号
#define RCK2_L()      (P2_2=0)                   // 定义"RCK2_L()"为P2.2输出低电平,作为74HC595_2的片选输入信号

#define SCK2_H()      (P2_1=1)                   // 定义"SCK2_H()"为P2.1输出高电平,作为74HC595_2的时钟输入信号
#define SCK2_L()      (P2_1=0)                   // 定义"SCK2_L()"为P2.1输出低电平,作为74HC595_2的时钟输入信号

#define SYSTEM_OSC    12000000                   // 定义开发板晶振频率为12000000Hz
#define SOUND_SPACE   4/5                        // 定义普通音符演奏的长度为每4分音符间隔

uint16 code FreTab[12]   = {262,277,294,311,330,349,369,392,415,440,466,494};  // 定义原始频率表
uint8  code SignTab[7]   = {0,2,4,5,7,9,11};     // 定义'1'~'7'在频率表中的位置
uint8  code LengthTab[7] = {1,2,4,8,16,32,64};
uint8  Sound_Temp_TH0,Sound_Temp_TL0;            // 定义音符定时器初值暂存变量
uint8  Sound_Temp_TH1,Sound_Temp_TL1;            // 定义音长定时器初值暂存变量

/********************************************************************************************
* 函数名称:Delay()
* 功    能:软件延时
* 入口参数:count    延时参数,值越大,延时越长
* 出口参数:无
*********************************************************************************************/
void Delay(uint16 count)
{
  uint8 i;                

  while(--count != 0)        
 	  {
	    for(i = 0; i < 125; i++);                // ";" 表示空语句,CPU空转。
	  }   				                         // i 从0加到125,在12M晶体下CPU大概耗时1毫秒
}

 /********************************************************************************************
* 函数名称:SendDataTo74HC595_2()
* 功    能:向74HC595_2发送一字节数据
* 入口参数:data    要发送的数据
* 出口参数:无
* 注    意:发送数据时,高位先发送
*********************************************************************************************/
void SendDataTo74HC595_2(uint8 dat)
{
  uint8 i;
  
  RCK2_L();                                      // RCK2为低电平
  for(i=0;i<8;i++)                               // 发送8位数据(1个字节)
     {
       SCK2_L();                                 // SCK2为低电平
       
	   /* 设置SI2的输出值 */
       if((dat & 0x80)!=0)
         {SI2_H();}                              // SI2输出高电平
       else
         {SI2_L();}                              // SI2输出低电平
       
	   dat<<=1;                                  // 将要发送的1字节数据左移一位
       SCK2_H();                                 // SCK2为高电平
     }
  RCK2_H();                                      // RCK2为高电平     
}

/********************************************************************************************
* 函数名称:Init_Sound()
* 功    能:音乐播放程序初始化
* 入口参数:无
* 出口参数:无
*********************************************************************************************/
void Init_Sound(void)
{
  BEEP = 0;

  Sound_Temp_TH1 = (65535-(1/1200)*SYSTEM_OSC)/256;//计算TH1应装入的初值(10ms的初装值)
  Sound_Temp_TL1 = (65535-(1/1200)*SYSTEM_OSC)%256;//计算TL1应装入的初值(10ms的初装值)
  TH1 = Sound_Temp_TH1;
  TL1 = Sound_Temp_TL1;

  TMOD |= 0x11;
  ET0  = 1;
  ET1  = 0;
  TR0  = 0;
  TR1  = 0;
  EA   = 1;
}

/********************************************************************************************
* 函数名称:Timer0_Server_Beep()
* 功    能:定时器0中断服务程序,产生音符
* 入口参数:无
* 出口参数:无
*********************************************************************************************/
void Timer0_Server_Beep(void) interrupt 1
{
  BEEP = !BEEP;	                                 // 取反蜂鸣器控制引脚

  TH0 = Sound_Temp_TH0;
  TL0 = Sound_Temp_TL0;
}

/********************************************************************************************
* 函数名称:MusicPlay()
* 功    能:音乐播放
* 入口参数:Sound,     曲谱编码表名(要播放的乐曲指针)
*           Signature,	调号(0~11),是指乐曲升多少个半音演奏
*           Octachord, 升降八度(1~3),1:降八度;2:不升不降;3:升八度
*           Speed,     演奏速度(1~12000),值越大速度越快
* 出口参数:无
*********************************************************************************************/
void MusicPlay(uint8 *Sound,uint8 Signature,uint8 Octachord,uint16 Speed)
{
  uint16 NewFreTab[12];                          // 定义新的频率表
  uint8  i,j;
  uint16 Point,LDiv,LDiv0,LDiv1,LDiv2,LDiv4,CurrentFre,Temp_T,SoundLength;
  uint8  Tone,Length,SL,SH,SM,SLen,XG,FD;

  /* 根据调号和升降八度来生成新的频率表 */
  for(i=0;i<12;i++)
    {
	  j = i + Signature;
	  if(j>11)
	   {
	     j = j-12;
		 NewFreTab[i] = FreTab[j]*2;  
	   }
      else
	  	NewFreTab[i] = FreTab[j];
	  
	  if(Octachord == 1)
	     NewFreTab[i]>>=2;
	  else if(Octachord == 3)
	         NewFreTab[i]<<=2;
	}

  /* 计算歌曲长度 */
  SoundLength = 0;
  while(Sound[SoundLength] != 0x00) {SoundLength+=2;}

  /* 读出第一个音符及它的音长*/
  Point  = 0;
  Tone   = Sound[Point];
  Length = Sound[Point+1];

  LDiv0 = 12000/Speed;                           // 算出1分音符的长度
  LDiv4 = LDiv0/4;                               // 算出4分音符的长度
  LDiv4 = LDiv4-LDiv4*SOUND_SPACE;               // 算出普通音最长间隔标准

  TR0 = 0;
  TR1 = 1;

  while(Point < SoundLength)
      {
	    SL = Tone%10;                            // 算出音符
		SM = Tone/10%10;                         // 算出高低音
		SH = Tone/100;                           // 算出是否升半音

		CurrentFre = NewFreTab[SignTab[SL-1]+SH];// 查出对应音符的频率

		if(SL!=0)
		 {
		   if(SM==1) CurrentFre>>=2;             // 低音
		   if(SM==3) CurrentFre<<=2;             // 高音

		   /* 计算定时器0的初值并装入 */
		   Temp_T = 65536-(50000/CurrentFre)*10/(12000000/SYSTEM_OSC);
		   Sound_Temp_TH0 = Temp_T/256;
		   Sound_Temp_TL0 = Temp_T%256;
		   TH0 = Sound_Temp_TH0;
		   TL0 = Sound_Temp_TL0+12;	             // 加12是对中断延时的补偿
	     }
        
		SLen = LengthTab[Length%10];             // 算出是几分音符
		XG   = Length/10%10;                     // 算出音符类型(0:普通;1:连音;2:顿音)
	
		FD   = Length/100;
		LDiv = LDiv0/SLen;                       // 算出连音音符演奏的长度
		if(FD==1) LDiv = LDiv + LDiv/2;
		if(XG!=1)
		  if(XG==0)	                             // 算出普通音符的演奏长度
		    if(SLen<=4)
			  LDiv1 = LDiv - LDiv4;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -