- #include <reg52.h>
- #define SONG 4 // 歌曲的数量
- #define LED_PORT P3
- #define uchar unsigned char // 以后unsigned char就可以用uchar代替
- #define uint unsigned int // 以后unsigned int 就可以用uint 代替
- #define ulong unsigned long // 以后unsigned long就可以用ulong代替
- sbit Key1_P = P1^0; // 弹奏键1的管脚
- sbit Key2_P = P1^1; // 弹奏键2的管脚
- sbit Key3_P = P1^2; // 弹奏键3的管脚
- sbit Key4_P = P1^3; // 弹奏键4的管脚
- sbit Key5_P = P1^4; // 弹奏键5的管脚
- sbit Key6_P = P1^5; // 弹奏键6的管脚
- sbit Key7_P = P1^6; // 弹奏键7的管脚
- //sbit Key8_P = P1^7; // 弹奏键8的管脚
- sbit Key9_P = P2^0; // 播放内置歌曲的按键管脚
- sbit Key10_P = P2^1; // 开始/停止录制
- sbit Key11_P = P2^2; // 播放录制的歌曲
- sbit Beep_P = P2^4; // 扬声器管脚
- sbit Led_P = P2^7; // 录歌指示灯
- sbit Key_Set1 = P2^3; //设置音区按键1
- sbit Key_Set2 = P2^5; //设置音区按键2
- sbit Key_Set3 = P2^6; //设置音区按键3
- uchar gTone=0; // gTone代表当前要播放的音调
- uchar gPlayStatus; // gPlayStatus代表当前的播放状态,0是停止,1是播放
- uchar gSong; // gSong代表当前播放到第几首歌
- uchar ledflag=0; //流水灯的标志位
- uchar yinquflag=1; //音区选择 1:第一组 2:第二组 3:第三组 默认第一组
- /* 定时器初值 低1 低2 低3 低4 低5 低6 低7 中1 中2 中3 中4 中5 中6 中7 高1 高2 高3 高4 高5 高6 高7 */
- uchar code ArrTL0[]={ 0X8B,0X5B,0X14,0X66,0X03,0X8F,0X0B,0X43,0XAB,0X08,0X33,0X81,0XC7,0X05,0X21,0X55,0X84,0X99,0XC0,0XE3,0X02};
- uchar code ArrTH0[]={ 0XF8,0XF9,0XFA,0XFA,0XFB,0XFB,0XFC,0XFC,0XFC,0XFD,0XFD,0XFD,0XFD,0XFE,0XFE,0XFE,0XFE,0XFE,0XFE,0XFE,0XFF};
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
-
- /* 数码管的显示值 1 2 3 4 5 6 7 */
- uchar code ArrDig[]={ 0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8};
- /* 《水手》的乐谱 */
- uchar code Music1[]={
- 5,4, 9,2, 8,2, 9,4, 8,2, 9,2,
- 10,3, 11,1, 10,2, 8,2, 9,8, 9,1,
- 10,2, 10,1, 9,1, 8,2, 7,1, 7,1, 8,2, 7,1, 7,1, 8,2, 9,2,
- 7,2, 6,2, 5,2, 7,2, 6,8,
- 5,4, 9,2, 8,2, 9,4, 8,2, 9,2,
- 10,2, 10,1, 11,1, 9,2, 8,2, 9,8,
- 10,3, 9,1, 8,2, 7,2, 8,2, 8,1, 7,1, 8,2, 8,1, 9,1,
- 6,2, 6,2, 5,2, 4,2, 5,8,
- 8,3, 8,1, 8,2, 8,2, 10,2, 10,1, 9,1, 8,2, 7,1, 7,1,
- 9,3, 8,1, 7,2, 8,1, 7,1, 5,8,
- 8,3, 8,1, 8,2, 8,2, 8,2, 8,1, 8,1, 8,2, 7,1, 8,1,
- 9,2, 9,2, 9,1, 8,1, 7,1, 8,1, 9,8,
- 8,3, 8,1, 8,2, 8,2, 10,2, 9,2, 8,2, 8,2,
- 9,2, 8,2, 7,2, 8,1, 7,1, 5,7, 5,1,
- 8,3, 8,1, 8,2, 8,1, 8,1, 8,2, 8,2, 7,2, 8,2,
- 9,2, 9,2, 8,2, 7,2, 9,4, 9,2, 11,2,
- 12,4, 11,4, 9,4, 8,2, 7,2,
- 8,2, 9,1, 8,1, 7,2, 6,2, 5,4, 5,2, 6,2,
- 7,4, 7,2, 9,2, 8,4, 6,1, 5,1, 4,2,
- 5,3, 5,1, 7,2, 8,2, 9,4, 9,2, 11,2,
- 12,4, 11,4, 9,4, 8,2, 7,2,
- 8,2, 9,1, 8,1, 7,2, 6,2, 5,4, 5,2, 6,2,
- 7,4, 7,2, 9,2, 8,4, 7,2, 6,2, 5,12
- };
- /* 《挥着翅膀的女孩》的乐谱 */
- uchar code Music2[]={
- 9,4, 9,2, 10,2, 11,4, 7,2, 8,2,
- 9,2, 9,2, 9,2, 10,2, 11,4, 8,2, 9,2,
- 10,4, 10,2, 9,2, 7,4, 10,2, 9,2,
- 10,4, 5,2, 7,2, 8,4, 7,2, 8,2,
- 9,4, 9,2, 10,2, 11,4, 12,2, 13,2,
- 14,2, 14,2, 9,2, 10,2, 11,4, 8,2, 9,2,
- 10,2, 9,2, 10,2, 14,2, 14,4, 8,2, 9,2,
- 10,2, 9,2, 10,2, 15,2, 15,4, 14,2, 13,2,
- 14,6, 15,2, 16,2, 15,2, 14,2, 13,2,
- 14,6, 14,2, 13,2, 11,2, 11,2, 7,2,
- 12,6, 12,2, 11,2, 7,2, 7,2, 9,2,
- 8,6, 9,1, 10,1, 10,2, 11,2, 14,2, 13,2,
- 14,6, 15,2, 16,2, 15,2, 14,2, 13,2,
- 14,6, 14,2, 13,2, 11,2, 11,2, 7,2,
- 12,6, 12,2, 11,2, 11,2, 14,2, 13,2,
- 14,16
- };
- /* 《茉莉花》的乐谱 */
- uchar code Music3[]={
- 9,4, 9,2, 11,2, 12,2, 14,2, 14,2, 12,2,
- 11,4, 11,2, 12,2, 11,8,
- 9,4, 9,2, 11,2, 12,2, 14,2, 14,2, 12,2,
- 11,4, 11,2, 12,2, 11,8,
- 11,4, 11,4, 11,4, 9,2, 11,2,
- 12,4, 12,4, 11,8,
- 9,4, 8,2, 9,2, 11,4, 9,2, 8,2,
- 7,4, 7,2, 8,2, 7,8,
- 9,2, 8,2, 7,2, 9,2, 8,6, 9,2,
- 11,4, 12,2, 14,2, 11,8,
- 8,4, 9,2, 11,2, 8,2, 9,2, 7,2, 5,2,
- 4,8, 5,4, 7,4,
- 8,6, 9,2, 7,2, 8,2, 7,2, 5,2,
- 4,12
- };
- /* 《欢乐颂》的乐谱 */
- uchar code Music4[]={
- 9,2, 9,2, 10,2, 11,2,
- 11,2, 10,2, 9,2, 8,2,
- 7,2, 7,2, 8,2, 9,2,
- 9,3, 8,1, 8,4,
- 9,2, 9,2, 10,2, 11,2,
- 11,2, 10,2, 9,2, 8,2,
- 7,2, 7,2, 8,2, 9,2,
- 8,3, 7,1, 7,4,
- 8,2, 8,2, 9,2, 7,2,
- 8,2, 9,1, 10,1, 9,2, 7,2,
- 8,2, 9,1, 10,1, 9,2, 8,2,
- 7,2, 8,2, 4,2, 9,2,
- 9,2, 9,2, 10,2, 11,2,
- 11,2, 10,2, 9,2, 10,1, 8,1,
- 7,2, 7,2, 8,2, 9,2,
- 8,3, 7,1, 7,4
- } ;
- /*********************************************************/
- // 毫秒级的延时函数,time是要延时的毫秒数
- /*********************************************************/
- void DelayMs(uint time)
- {
- uint i,j;
- for(i=0;i<time;i++)
- for(j=0;j<112;j++);
- }
- /*********************************************************/
- // 发出指定音调及其节拍的声音,tone代表音调,beat代表节拍
- /*********************************************************/
- void PlayTone(uchar tone,float beat)
- {
- int i;
- P0=ArrDig[tone%7]; // 数码管显示当前音调值
- gTone=tone; // 将音调值赋给全局变量gTone
- TH0 = ArrTH0[tone]; // 装入定时器TH0的初值
- TL0 = ArrTL0[tone]; // 装入定时器TL0的初值
- TR0=1; // 启动定时器
- for(i=0;i<beat;i++)
- {
- DelayMs(200);
- }
- TR0=0; // 停止定时器
- P0=0xff; // 关闭数码管显示
- Beep_P=1;
- }
- /*********************************************************/
- // 播放内置的音乐
- // arr[]是要播放的乐谱数组,num是数组里面的元素个数
- /*********************************************************/
- void PlayMusic(uchar music[],uint num)
- {
- uint i=0;
- while(i<num)
- {
- if(gPlayStatus==1) // 判断播放状态是否为播放还是暂停
- {
- PlayTone(music[i],music[i+1]); // 开始演奏一个节拍
- i+=2; // 进入下一个节拍,因为每2个数为1组,所以每次要加2
- if(i==num) // 判断歌曲是否播放完了
- {
- gPlayStatus=0; // 播放完了的话,则把播放状态改为暂停,否则会循环播放
- }
- }
-
- if(Key9_P==0) // 下一曲
- {
- DelayMs(10); // 消除按键按下的抖动
- while(!Key9_P); // 等待按键释放
- DelayMs(10); // 消除按键松开的抖动
- gSong++; // 把当前播放到第几首歌的变量gSong加1,即切到下一曲
- if(gSong>SONG) // 如果gSong为SONG,说明到后面的尽头了,则转为第一首
- gSong=1;
- break;
- }
- }
- }
- /*********************************************************/
- /*********************************************************************
- : FlashLed1
- *********************************************************************/
- void FlashLed1(void)
- {
- LED_PORT = 0x55; //
- DelayMs(200);
-
- LED_PORT = 0xaa; //
- DelayMs(200);
- }
- /*********************************************************************
- : FlashLed2
- *********************************************************************/
- void FlashLed2(void)
- {
- unsigned char i = 0;
- for (i=0; i<7; i++)
- {
- LED_PORT = (0xff & ~(1<<i));
- DelayMs(200);
- }
- }
- /*********************************************************************
- : FlashLed3
- *********************************************************************/
- void FlashLed3(void)
- {
- LED_PORT = 0xff; //
- DelayMs(200);
-
- LED_PORT = 0x00; //
- DelayMs(200);
- }
- /*********************************************************************
- : FlashLed4
- *********************************************************************/
- void FlashLed4(void)
- {
- unsigned char i = 0;
- for (i=0; i<7; i++)
- {
- LED_PORT =i;
- DelayMs(200);
- }
- }
- /*********************************************************************
- : FlashLed5
- *********************************************************************/
- void FlashLed5(void)
- {
- unsigned char i = 0;
- for (i=0; i<7; i++)
- {
- LED_PORT = (0xff & (1<<i));
- DelayMs(200);
- }
- }
- /*********************************************************************
- : FlashLed6
- *********************************************************************/
- void FlashLed6(void)
- {
- unsigned char i = 0;
- for (i=0; i<7; i++)
- {
- LED_PORT = (0xff & ~(1<<6-i));
- DelayMs(200);
- }
- }
- /*********************************************************************
- : FlashLed7
- *********************************************************************/
- void FlashLed7(void)
- {
- LED_PORT = 0x0f; //
- DelayMs(200);
-
- LED_PORT = 0xf0; //
- DelayMs(200);
- }
- void LED_PLAY(uchar num)
- {
- switch(num)
- {
- case(0x01):FlashLed1();break;
- case(0x02):FlashLed2();break;
- case(0x03):FlashLed3();break;
- case(0x04):FlashLed4();break;
- case(0x05):FlashLed5();break;
- case(0x06):FlashLed6();break;
- case(0x07):FlashLed7();break;
- }
- }
- /*********************************************************/
- // 定时器初始化函数
- /*********************************************************/
- void TimerInit()
- {
- TMOD=1; // 定时器0,工作方式1
- TH0=0; // 装定时器TH0的初值
- TL0=0; // 装定时器TL0的初值
- ET0=1; // 开启定时器0中断
- EA=1; // 开启总中断
- }
- /*********************************************************/
- // 弹奏键扫描函数
- /*********************************************************/
- uchar KeyScanf()
- {
- if(Key_Set1==0) // 按键被按下 P2^3
- yinquflag=1; //音区1
- if(Key_Set2==0) // 按键被按下 P2^5
- yinquflag=2; //音区2
- if(Key_Set3==0) // 按键被按下 P2^6
- yinquflag=3; //音区3
- if(Key1_P==0) // 按键1被按下,返回1
- return 1;
- if(Key2_P==0) // 按键2被按下,返回2
- return 2;
- if(Key3_P==0) // 按键3被按下,返回3
- return 3;
- if(Key4_P==0) // 按键4被按下,返回4
- return 4;
- if(Key5_P==0) // 按键5被按下,返回5
- return 5;
- if(Key6_P==0) // 按键6被按下,返回6
- return 6;
- if(Key7_P==0) // 按键7被按下,返回7
- return 7;
- // if(Key8_P==0) // 按键8被按下,返回8
- // return 8;
-
- return 0; // 8个按键都没被按下,返回0
- }
- /*********************************************************/
- // 主函数,程序从这里开始执行
- /*********************************************************/
- void main()
- {
- uchar i; // 循环变量
- uchar ret; // 用于保存音调键函数的返回值
- uchar count; // 用于记录当前录制了多少个音调
- uchar record[99]={0}; // 存储录制歌曲的数组
- TimerInit();
- gSong=0; // 上电默认第一首歌
- gPlayStatus=0; // 上电默认是0停止状态(1为播放状态)
- while(1)
- {
- if(gPlayStatus==1) // 如果处于播放状态,则判断是哪一首歌曲需要播放
- {
- switch(gSong)
- {
- case 1 : PlayMusic(Music1,sizeof(Music1)); break;
- case 2 : PlayMusic(Music2,sizeof(Music2)); break;
- case 3 : PlayMusic(Music3,sizeof(Music3)); break;
- case 4 : PlayMusic(Music4,sizeof(Music4)); break;
- default: break;
- }
- }
-
- /*播放内置的音乐*/
- if(Key9_P==0) // 开始播放
- {
- DelayMs(10); // 消除按键按下的抖动
- while(!Key9_P); // 等待按键释放
- DelayMs(10); // 消除按键松开的抖动
- gSong++; // 把当前播放到第几首歌的变量gSong加1,即切到下一曲
- if(gSong>SONG) // 如果gSong为SONG,说明到后面的尽头了,则转为第一首
- gSong=1;
- gPlayStatus=1; // 播放状态改为1,即播放
-
- }
-
- /*开始/停止 录制按键的处理*/
- if(Key10_P==0)
- {
- Led_P=~Led_P; // 录歌指示灯状态切换
- if(Led_P==0) // 如果是切换为录歌状态
- {
- count=0; // 清零记录按键值计数,从新开始计数
- }
- DelayMs(10); // 消除按键按下的抖动
- while(!Key10_P); // 等待按键释放
- DelayMs(10); // 消除按键松开的抖动
- }
-
- /*播放录制的音乐*/
- if(Key11_P==0)
- {
- for(i=0;i<count;i++)
- {
- PlayTone(record[i],2); // 播放该音调
- DelayMs(50); // 每播放一个音调,停顿50毫秒
- }
- DelayMs(10); // 消除按键按下的抖动
- while(!Key11_P); // 等待按键释放
- DelayMs(10); // 消除按键松开的抖动
- }
-
- /* 8个弹奏按键的扫描 */
- ret=KeyScanf(); // 获取8个按键的扫描结果
- if(ret!=0) // 如果有按键按下去了
- {
- ledflag=ret; //给流水灯赋值
- P3=(0xff)^ledflag;
- P0=ArrDig[(ret-1)%7]; // 数码管显示当前音调值
- TH0 = ArrTH0[ret]; // 装入定时器TH0的初值
- TL0 = ArrTL0[ret]; // 装入定时器TL0的初值
- gTone=ret;
- if(Led_P==0) // 如果是录音状态,则把弹奏值记录下来
- {
- record[count]=gTone; // 记录当前弹奏的按键值
- count++; // 准备记录下一个
- }
- TR0=1; // 启动定时器,播放弹奏的音符
- DelayMs(20); // 去除按键按下的抖动
- while(KeyScanf()); // 等待按键释放
- DelayMs(70); // 按键释放之后,再播放70毫秒,达到余音的效果
- TR0=0; // 停止定时器
- P0=0xff; // 关闭数码管显示
- P3=0xff; // 关闭led
- Beep_P=1; // 关闭定时器,停止弹奏音符的播放
- }
- // LED_PLAY(ledflag);
- }
- }
-
- /*********************************************************/
- // 功能:定时器0中断处理函数
- /*********************************************************/
- void time0() interrupt 1
- {
- Beep_P=!Beep_P; // 将控制扬声器的管脚取反
- if(yinquflag ==1)
- {
- TH0=ArrTH0[gTone]; // 重装定时器TH0的初值
- TL0=ArrTL0[gTone]; // 重装定时器TL0的初值
- }
- else if(yinquflag ==2)
- {
- TH0=ArrTH0[gTone+5]; // 重装定时器TH0的初值
- TL0=ArrTL0[gTone+5]; // 重装定时器TL0的初值
- }
- else if(yinquflag ==3)
- {
- TH0=ArrTH0[gTone+10]; // 重装定时器TH0的初值
- TL0=ArrTL0[gTone+10]; // 重装定时器TL0的初值
- }
- }
复制代码
全部资料51hei下载地址:
电子琴终结版.rar
(108.31 KB, 下载次数: 72)
|