#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); }