C51模拟I2C,音乐播放(记忆)

#include <reg52.h>
#include <intrins.h>


#define	SA	(1 << 7)	
#define	SB	(1 << 6)	
#define	SC	(1 << 5)	
#define	SD	(1 << 4)	
#define	SE	(1 << 3)	
#define	SF	(1 << 2)	
#define	SG	(1 << 1)
#define	SH	(1 << 0)

typedef unsigned char uchar;
typedef unsigned int uint;


//led
const uchar LEDData[] =
{
	SA |SB |SC | SD |SE |SF,		//0
	SB |SC,						//01
	SA |SB |SG | SE | SD,			//02
	SA |SB |SC | SD | SG,			//03
	SB |SF | SG | SC,				//04
	SA |SF | SG |SC  | SD,		//05
	SA |SC |SD | SE | SG | SF,		//06
	SA | SB|SC,					//07
	SA |SB |SC | SD | SE | SF | SG,//08
	SA |SB |SC|SD | SF | SG	,	//09
	0,							//mask - 10	
	SG,							//minus - 11	
	SA |SB | SE | SF | SG			//P - 12			
};

sbit	music_note		= 	P0	^	0;
sbit	music_beat		=	P0	^	1;
sbit	music_time		=	P0	^	2;
sbit	starting_up		=	P0	^	3;


//music
sbit  speaker=P0 ^ 4;  
uchar byteTH0,byteTL0,smg_num,step,mutex;
// 小星星句子,三个一组,第一个表示音符,第二个表示音阶,第三个表示延时长度(单位约等于0.1s)
code uchar music[]={      
 1,2,2, 1,2,2, 5,2,2, 5,2,2, 6,2,2, 6,2,2, 5,2,4,
 4,2,2, 4,2,2, 3,2,2, 3,2,2, 2,2,2, 2,2,2, 1,2,4,
 5,2,2, 5,2,2, 4,2,2, 4,2,2, 3,2,2, 3,2,2, 2,2,4,
 5,2,2, 5,2,2, 4,2,2, 4,2,2, 3,2,2, 3,2,2, 2,2,4,
 1,2,2, 1,2,2, 5,2,2, 5,2,2, 6,2,2,  6,2,2, 5,2,4,
 4,2,2, 4,2,2, 3,2,2, 3,2,2, 2,2,2, 2,2,2, 1,2,4 };

//定时器计时初值,高八位,代表不同音符的频率
code uchar FREQH[]={
 0xF2,0xF3,0xF5,0xF5,0xF6,0xF7,0xF8, 
 0xF9,0xF9,0xFA,0xFA,0xFB,0xFB,0xFC,
 0xFC,0xFC,0xFD,0xFD,0xFD,0xFD,0xFE,
 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF,} ;

//定时器计时初值,低八位,代表不同音符的频率
code uchar FREQL[]={
 0x42,0xC1,0x17,0xB6,0xD0,0xD1,0xB6,
 0x21,0xE1,0x8C,0xD8,0x68,0xE9,0x5B,
 0x8F,0xEE,0x44, 0x6B,0xB4,0xF4,0x2D, 
 0x47,0x77,0xA2,0xB6,0xDA,0xFA,0x16,};


//i2c
void delay();
void start();
void stop();
void ack();
void no_ack();
void i2c_write_byte(uchar dat);
uchar i2c_read_byte();
void init_i2c();
void delay_long();
void write_byte(uchar add, uchar dat);
uchar read_byte(uchar add);
void total_shutdown();

//music
void song_beat(uchar duration);
void delay_music(unsigned char t);
void init_music();//设定定时/计数器工作在方式1,16位模式,计数溢出就产生中断,数码管显示音符
void song();
void music_show();


sbit sda = P0 ^ 5;
sbit scl = P0 ^ 6;


void main()
{

	//total_shutdown();
	/////////////////////////////////////////
	song();

}

											  

//定时器0的中断服务程序,蜂鸣器反向,设定新的定时时间,启动定时,数码管显示音符
void timer0() interrupt 1
{
	TR0=0;
	speaker=!speaker;	
	P2 = ~LEDData[music[step]];
	music_note = !music_note;
   	/*
	P2 = 0x55;
	music_beat = !music_beat;
	 */
	TH0 = byteTH0;
	TL0 = byteTL0;
	TR0=1;
}



void delay_music(uchar t)
{
	uint i;
	uchar j=80;
	for(i=0; i<t*100; i++)
		while(j--);
    TR0=0;
}

void song_beat(uchar duration)
{
	TH0 = byteTH0;
	TL0 = byteTL0;
	TR0 = 1;
	delay_music(duration);                       
}

//设定定时/计数器0工作在方式1,16位模式,计数溢出就产生中断
void init_music()
{
	TMOD |= 0x01;
	EA=1;
	ET0=1;
}

void song()
{
	uchar dura,index;
	init_music();
	while(1)
    {
		//step=0;  
		step = read_byte(10);
		while(step<126)
		{
			//在该音符音阶下需要鸣唱的时间
			index = music[step] + 7 * music[step+1] - 1;
			byteTH0 = FREQH[index];
		    byteTL0 = FREQL[index];
			//
		    dura = music[step+2];
		    step += 3;
		    song_beat(dura);
			if(step >= 126)
			{
				step = 0;
			}
			//i2c读写之间需要一点时间间隔
			write_byte(10,step);
		}
		delay_music(10);
	} 	
}

void delay()
{
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}

void start()
{
	sda = 1;
	delay();
	scl = 1;
	delay();
	sda = 0;
	delay();
}

void stop()
{
	sda = 0;
	delay();
	scl = 1;
	delay();
	sda = 1;
	delay();
}

void ack()
{
	uchar i;
	scl = 1;
	delay();
	while(sda == 1 && i < 200)
	{
		i++;
	}
	scl = 0;
	delay();
}

void no_ack()
{
	sda = 1;
	delay();
	scl = 1;
	delay();
	scl = 0;
	delay();
}


void i2c_write_byte(uchar dat)
{
	uchar i;
	scl = 0;
	for(i = 0; i < 8; i++)	
	{
		if(dat & 0x80)
		{
			sda = 1;
		}
		else
		{
			sda = 0;
		}
		dat = dat << 1;
		delay();
		scl = 1;
		delay();
		scl = 0;
		delay();
	}
	sda = 1;
	delay();
}

uchar i2c_read_byte()
{
	uchar i,dat;
	scl = 0;
	delay();
	sda = 1;
	delay();
	for(i = 0; i < 8; i++)
	{
		scl = 1;
		delay();
		dat = dat << 1;
		if(sda == 1)
		{
			dat++;
		}
		scl = 0;
		delay();
	}
	return dat;	
}

void init_i2c()
{
	sda = 1;
	scl = 1;
}


void delay_long()
{
	uint i = 10000;
	while(i--);
}

void write_byte(uchar add, uchar dat)
{
	init_i2c();
	start();
	i2c_write_byte(0xa0);	
	ack();
	i2c_write_byte(add);
	ack();
	i2c_write_byte(dat);
	ack();
	stop();	
}

uchar read_byte(uchar add)
{
	uchar dat;
	init_i2c();
	start();
	i2c_write_byte(0xa0);
	ack();
	i2c_write_byte(add);
	ack();
	start();
	i2c_write_byte(0xa1);
	ack();
	dat = i2c_read_byte();
	no_ack();
	stop();
	return dat;
}


void total_shutdown()
{
	uchar count;
	count = read_byte(10);
	starting_up = 0;
	P2 = ~LEDData[count];
	count++;
	if(count == 10)
		count = 0;
	write_byte(10,count);	
}
posted @ 2010-12-13 21:31  Cranny  阅读(325)  评论(0编辑  收藏  举报