单片机电子琴程序
- 格式:doc
- 大小:19.00 KB
- 文档页数:5
#include<reg51.h>#include<absacc.h>#include<stdio.h>#include<math.h>#define uchar unsigned char#define uint unsigned intuchar STH0; //定时器计数初值uchar STL0;bit FY=0; //放乐曲时FY=1,电子琴弹奏时FY=0uchar Song_Index=0,Tone_Index=0; //放音乐的参数uchar k,key;sbit SPK=P3^7;sbit LED1=P1^0;sbit LED2=P1^1;uchar code DSY_CODE[]={0x3f,0x06,0x5b,0x4f,0x66,0x6f,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79 ,0x71};uchar code Song[][50]={{1,2,3,5,7,8,4,3,4,3,4,5,4,6,3,4,5},{5,5,3,5,4,2,4,5,7,4,2,10,10,10,2,1,2,1,2,10,10},{5,5,10,9,8,5,5,5,5,10,9,8,6,6,6,11,12,9,6,8-1},{13,14,13,12,12,10,12,13,14,15,14,14},{6,6,11,10,9,12,12,12,12,13,12,11,9,8,10,10,10,-1},{9,13,13,13,13,8,13,13,13,13,14,15,14,13,13,14,12,13},};uchar code Len[][50]={{1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,2,2,2,1,2,2,1,2,2},{1,1,1,1,1,1,2,1,1,1,2,2,1,1,1,1,-1},{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1},{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1},{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1},{1,1,2,0,1,1,2,0,1,1,1,1,1,1,1,1,1,1,1},{1,1,1,1,1,1,1,1,2,0,1,2,1,2,1,2,1,2,1,2},{2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1},}; //音符与计数值对应表uint code tab[]={0,63628,63835,64021,64103,64260,64400,64524,64580,64684,64777,64820,64898,64968,65030,65058,65110,65157,65178,65217,65252,65283};void delay1(uint ms) //播放歌曲时实现节拍的延时函数{uchar t;while(ms--) for(t=0;t<120;t++);}//键消抖延时函数void delay(void){uchar i;for(i=300;i>0;i--);}//键扫描函数uchar getkey(void){uchar scancode,tmpcode;if((P0&0xf0)==0xf0)return(0);scancode=0xfe;while((scancode&0x10)!=0){P0=scancode; //输入行扫描码if((P0&0xf0)!=0xf0) //本行有键按下{tmpcode=(P0&0xf0)|0x0f;return((~scancode)+~(tmpcode));}else scancode=(scancode<<1)|0x01;}}//外部中断0void EX0_INT() interrupt 0{FY=0;LED1=1;LED2=0;}//外部中断1,这里是播放按键void EX1_INT() interrupt 2{FY=1;LED1=0;LED2=1;}//定时器0中断服务子程序void time0_int(void) interrupt 1 using 0{TH0=STH0;TL0=STL0;SPK=!SPK;P2=DSY_CODE[k];void main(void){LED1=1;LED2=0;P2=0x3f;IE=0x87;TMOD=0x01;IT0=1;IT1=1;while(1){P0=0xf0;if((P0&0xf0)!=0xf0){delay();if((P0=0xf0)!=0xf0){key=getkey();switch(key){case 0x11:k=0;break;case 0x21:k=1;break;case 0x41:k=2;break;case 0x81:k=3;break;case 0x12:k=4;break;case 0x22:k=5;break;case 0x42:k=6;break;case 0x82:k=7;break;case 0x14:k=8;break;case 0x24:k=9;break;case 0x44:k=10;break;case 0x84:k=11;break;case 0x18:k=12;break;case 0x28:k=13;break;case 0x48:k=14;break;case 0x88:k=15;break;default:break;}if(FY==0){STH0=tab[k]/256;STL0=tab[k]%256;TR0=1;while((P0&0xf0)!=0xf0);TR0=0;}else{while(FY==1){if(Song[k][Tone_Index]==-1)Tone_Index=0;STH0=(tab[Song[k][Tone_Index]])/256;STL0=(tab[Song[k][Tone_Index]])%256;P2=DSY_CODE[Song[k][Tone_Index]];TR0=1;delay1(300*Len[k][Tone_Index]);Tone_Index++;TR0=0;}}}}}}关于“世上只有妈妈好”的单片机音乐演奏程序2009-11-22 21:45单片机演奏一个音符,是通过引脚,周期性的输出一个特定频率的方波。
随着科技的飞速发展,单片机技术已成为现代电子技术的重要分支。
为了更好地学习和掌握单片机编程及应用,我们设计并实现了一款基于单片机的简易电子琴。
本实验旨在通过设计一个简易电子琴,让学生深入了解单片机的原理和应用,提高动手实践能力。
二、实验目的1. 掌握单片机的基本原理和编程方法。
2. 学会使用定时器、中断、键盘扫描等技术。
3. 了解电子琴的工作原理和制作方法。
4. 培养学生的创新意识和团队协作能力。
三、实验原理本实验采用STC12C5A32S2单片机作为核心控制单元,通过定时器产生方波信号,驱动蜂鸣器发出不同频率的声音,实现电子琴的演奏功能。
具体原理如下:1. 单片机原理:STC12C5A32S2单片机是一款高性能、低功耗的单片机,具有丰富的片上资源,如定时器、中断、串口等。
2. 定时器:定时器用于产生固定频率的方波信号,驱动蜂鸣器发出不同频率的声音。
通过调整定时器的计数值,可以改变方波信号的频率,从而改变音调。
3. 中断:中断技术用于实现按键扫描功能。
当按键被按下时,单片机响应中断,读取按键状态,并产生相应的音调。
4. 键盘扫描:键盘扫描技术用于检测按键状态。
通过扫描键盘矩阵,可以判断哪个按键被按下,并产生相应的音调。
四、实验内容1. 硬件设计:主要包括单片机、蜂鸣器、键盘、电阻、电容等元器件。
将元器件按照电路图连接,形成电子琴的硬件电路。
2. 软件设计:主要包括主程序、定时器中断服务程序、按键扫描程序等。
通过Keil C编程,实现电子琴的演奏功能。
3. 调试与测试:对电子琴进行调试和测试,确保其能够正常工作。
1. 搭建电路:按照电路图连接元器件,形成电子琴的硬件电路。
2. 编写程序:使用Keil C编写主程序、定时器中断服务程序、按键扫描程序等。
3. 编译程序:将编写好的程序编译成HEX文件。
4. 烧录程序:将编译好的HEX文件烧录到单片机中。
5. 调试与测试:使用万用表测试电路是否正常工作,并对程序进行调试,确保电子琴能够正常演奏。
#include "ht66f018.h"//同一首歌unsigned char const Music_Same[]={ 0x0F,0x01, 0x15,0x02, 0x16,0x02, 0x17,0x66, 0x18,0x03,0x17,0x02, 0x15,0x02, 0x16,0x01, 0x15,0x02, 0x10,0x02,0x15,0x00, 0x0F,0x01, 0x15,0x02, 0x16,0x02, 0x17,0x02,0x17,0x03, 0x18,0x03, 0x19,0x02, 0x15,0x02, 0x18,0x66,0x17,0x03, 0x19,0x02, 0x16,0x03, 0x17,0x03, 0x16,0x00,0x17,0x01, 0x19,0x02, 0x1B,0x02, 0x1B,0x70, 0x1A,0x03,0x1A,0x01, 0x19,0x02, 0x19,0x03, 0x1A,0x03, 0x1B,0x02,0x1A,0x0D, 0x19,0x03, 0x17,0x00, 0x18,0x66, 0x18,0x03,0x19,0x02, 0x1A,0x02, 0x19,0x0C, 0x18,0x0D, 0x17,0x03,0x16,0x01, 0x11,0x02, 0x11,0x03, 0x10,0x03, 0x0F,0x0C,0x10,0x02, 0x15,0x00, 0x1F,0x01, 0x1A,0x01, 0x18,0x66,0x19,0x03, 0x1A,0x01, 0x1B,0x02, 0x1B,0x03, 0x1B,0x03,0x1B,0x0C, 0x1A,0x0D, 0x19,0x03, 0x17,0x00, 0x1F,0x01,0x1A,0x01, 0x18,0x66, 0x19,0x03, 0x1A,0x01, 0x10,0x02,0x10,0x03, 0x10,0x03, 0x1A,0x0C, 0x18,0x0D, 0x17,0x03,0x16,0x00, 0x0F,0x01, 0x15,0x02, 0x16,0x02, 0x17,0x70,0x18,0x03, 0x17,0x02, 0x15,0x03, 0x15,0x03, 0x16,0x66,0x16,0x03, 0x16,0x02, 0x16,0x03, 0x15,0x03, 0x10,0x02,0x10,0x01, 0x11,0x01, 0x11,0x66, 0x10,0x03, 0x0F,0x0C,0x1A,0x02, 0x19,0x02, 0x16,0x03, 0x16,0x03, 0x18,0x66,0x18,0x03, 0x18,0x02, 0x17,0x03, 0x16,0x03, 0x19,0x00,0x00,0x00 };//两只蝴蝶unsigned char const Music_Two[] ={ 0x17,0x03, 0x16,0x03, 0x17,0x01, 0x16,0x03, 0x17,0x03,0x16,0x03, 0x15,0x01, 0x10,0x03, 0x15,0x03, 0x16,0x02,0x16,0x0D, 0x17,0x03, 0x16,0x03, 0x15,0x03, 0x10,0x03,0x10,0x0E, 0x15,0x04, 0x0F,0x01, 0x17,0x03, 0x16,0x03,0x17,0x01, 0x16,0x03, 0x17,0x03, 0x16,0x03, 0x15,0x01,0x10,0x03, 0x15,0x03, 0x16,0x02, 0x16,0x0D, 0x17,0x03,0x16,0x03, 0x15,0x03, 0x10,0x03, 0x15,0x03, 0x16,0x01,0x17,0x03, 0x16,0x03, 0x17,0x01, 0x16,0x03, 0x17,0x03,0x16,0x03, 0x15,0x01, 0x10,0x03, 0x15,0x03, 0x16,0x02,0x16,0x0D, 0x17,0x03, 0x16,0x03, 0x15,0x03, 0x10,0x03,0x10,0x0E, 0x15,0x04, 0x0F,0x01, 0x17,0x03, 0x19,0x03,0x19,0x01, 0x19,0x03, 0x1A,0x03, 0x19,0x03, 0x17,0x01,0x16,0x03, 0x16,0x03, 0x16,0x02, 0x16,0x0D, 0x17,0x03,0x16,0x03, 0x15,0x03, 0x10,0x03, 0x10,0x0D, 0x15,0x00,0x19,0x03, 0x19,0x03, 0x1A,0x03, 0x1F,0x03, 0x1B,0x03,0x1B,0x03, 0x1A,0x03, 0x17,0x0D, 0x16,0x03, 0x16,0x03,0x16,0x0D, 0x17,0x01, 0x17,0x03, 0x17,0x03, 0x19,0x03,0x1A,0x02, 0x1A,0x02, 0x10,0x03, 0x17,0x0D, 0x16,0x03,0x16,0x01, 0x17,0x03, 0x19,0x03, 0x19,0x03, 0x17,0x03,0x19,0x02, 0x1F,0x02, 0x1B,0x03, 0x1A,0x03, 0x1A,0x0E,0x1B,0x04, 0x17,0x02, 0x1A,0x03, 0x1A,0x03, 0x1A,0x0E,0x1B,0x04, 0x1A,0x03, 0x19,0x03, 0x17,0x03, 0x16,0x03,0x19,0x03,0x19,0x03, 0x1A,0x03, 0x1F,0x03, 0x1B,0x03, 0x1B,0x03,0x1A,0x03, 0x17,0x0D, 0x16,0x03, 0x16,0x03, 0x16,0x03,0x17,0x01, 0x17,0x03, 0x17,0x03, 0x19,0x03, 0x1A,0x02,0x1A,0x02, 0x10,0x03, 0x17,0x0D, 0x16,0x03, 0x16,0x01,0x17,0x03, 0x19,0x03, 0x19,0x03, 0x17,0x03, 0x19,0x03,0x1F,0x02, 0x1B,0x03, 0x1A,0x03, 0x1A,0x0E, 0x1B,0x04,0x17,0x02, 0x1A,0x03, 0x1A,0x03, 0x1A,0x0E, 0x1B,0x04,0x17,0x16, 0x1A,0x03, 0x1A,0x03, 0x1A,0x0E, 0x1B,0x04,0x1A,0x03, 0x19,0x03, 0x17,0x03, 0x16,0x03, 0x0F,0x02,0x10,0x03, 0x15,0x00, 0x00,0x00 };//挥着翅膀的女孩unsigned char const Music_Girl[]={ 0x17,0x02, 0x17,0x03, 0x18,0x03, 0x19,0x02, 0x15,0x03,0x16,0x03, 0x17,0x03, 0x17,0x03, 0x17,0x03, 0x18,0x03,0x19,0x02, 0x16,0x03, 0x17,0x03, 0x18,0x02, 0x18,0x03,0x17,0x03, 0x15,0x02, 0x18,0x03, 0x17,0x03, 0x18,0x02,0x10,0x03, 0x15,0x03, 0x16,0x02, 0x15,0x03, 0x16,0x03,0x17,0x02, 0x17,0x03, 0x18,0x03, 0x19,0x02, 0x1A,0x03,0x1B,0x03, 0x1F,0x03, 0x1F,0x03, 0x17,0x03, 0x18,0x03,0x19,0x02, 0x16,0x03, 0x17,0x03, 0x18,0x03, 0x17,0x03,0x18,0x03, 0x1F,0x03, 0x1F,0x02, 0x16,0x03, 0x17,0x03,0x18,0x03, 0x17,0x03, 0x18,0x03, 0x20,0x03, 0x20,0x02,0x1F,0x03, 0x1B,0x03, 0x1F,0x66, 0x20,0x03, 0x21,0x03,0x1F,0x03,0x1B,0x03, 0x19,0x03, 0x19,0x03, 0x15,0x03, 0x1A,0x66,0x1A,0x03, 0x19,0x03, 0x15,0x03, 0x15,0x03, 0x17,0x03,0x16,0x66, 0x17,0x04, 0x18,0x04, 0x18,0x03, 0x19,0x03,0x1F,0x03, 0x1B,0x03, 0x1F,0x66, 0x20,0x03, 0x21,0x03,0x20,0x03, 0x1F,0x03, 0x1B,0x03, 0x1F,0x66, 0x1F,0x03,0x1B,0x03, 0x19,0x03, 0x19,0x03, 0x15,0x03, 0x1A,0x66,0x1A,0x03, 0x19,0x03, 0x19,0x03, 0x1F,0x03, 0x1B,0x03,0x1F,0x00, 0x1A,0x03, 0x1A,0x03, 0x1A,0x03, 0x1B,0x03,0x1B,0x03, 0x1A,0x03, 0x19,0x03, 0x19,0x02, 0x17,0x03,0x15,0x17, 0x15,0x03, 0x16,0x03, 0x17,0x03, 0x18,0x03,0x17,0x04, 0x18,0x0E, 0x18,0x03, 0x17,0x04, 0x18,0x0E,0x18,0x66, 0x17,0x03, 0x18,0x03, 0x17,0x03, 0x18,0x03,0x20,0x03, 0x20,0x02, 0x1F,0x03, 0x1B,0x03, 0x1F,0x66,0x20,0x03, 0x21,0x03, 0x20,0x03, 0x1F,0x03, 0x1B,0x03,0x1F,0x66, 0x1F,0x04, 0x1B,0x0E, 0x1B,0x03, 0x19,0x03,0x19,0x03, 0x15,0x03, 0x1A,0x66, 0x1A,0x03, 0x19,0x03,0x15,0x03, 0x15,0x03, 0x17,0x03, 0x16,0x66, 0x17,0x04,0x18,0x04, 0x18,0x03, 0x19,0x03, 0x1F,0x03, 0x1B,0x03,0x1F,0x66, 0x20,0x03, 0x21,0x03, 0x20,0x03, 0x1F,0x03,0x1B,0x03, 0x1F,0x66, 0x1F,0x03, 0x1B,0x03, 0x19,0x03,0x19,0x03, 0x15,0x03, 0x1A,0x66, 0x1A,0x03, 0x19,0x03,0x18,0x02,0x18,0x03, 0x1A,0x03, 0x19,0x0D, 0x15,0x03, 0x15,0x02,0x18,0x66, 0x16,0x02, 0x17,0x02, 0x15,0x00, 0x00,0x00};unsigned char const Music_sd[]={ 0x0F,0x03, 0x0F,0x03, 0x17,0x03, 0x16,0x03, 0x15,0x03,0x0F,0x02, 0x0F,0x03, 0x0F,0x03, 0x0F,0x03, 0x17,0x03,0x16,0x03, 0x15,0x03, 0x10,0x02, 0x10,0x03, 0x10,0x03,0x18,0x03, 0x17,0x03, 0x16,0x03, 0x10,0x02, 0x10,0x03,0x19,0x03, 0x19,0x03, 0x18,0x03, 0x16,0x03, 0x17,0x02,0x15,0x03, 0x0F,0x03, 0x0F,0x03, 0x17,0x03, 0x16,0x03,0x15,0x03, 0x0F,0x02, 0x0F,0x03, 0x0F,0x03, 0x17,0x03,0x16,0x03, 0x15,0x03, 0x10,0x02, 0x10,0x03, 0x10,0x03,0x18,0x03, 0x17,0x03, 0x16,0x03, 0x19,0x03, 0x19,0x03,0x19,0x03, 0x19,0x03, 0x1A,0x03, 0x19,0x03, 0x18,0x03,0x16,0x03, 0x15,0x16, 0x17,0x03, 0x17,0x03, 0x17,0x02,0x17,0x03, 0x17,0x03, 0x17,0x02, 0x17,0x03, 0x19,0x03,0x15,0x03, 0x16,0x04, 0x17,0x01, 0x18,0x03, 0x18,0x03,0x18,0x03, 0x18,0x04, 0x18,0x03, 0x17,0x03, 0x17,0x03,0x17,0x04, 0x17,0x04, 0x17,0x03, 0x16,0x03, 0x16,0x03,0x15,0x03, 0x16,0x03, 0x19,0x02, 0x19,0x03, 0x19,0x03,0x18,0x03, 0x16,0x03, 0x15,0x02, 0x00,0x00 }; unsigned char const Music_lzlh[]={ 0x15,0x03, 0x16,0x03, 0x17,0x03, 0x15,0x03, 0x15,0x03,0x18,0x03,0x19,0x02, 0x17,0x03, 0x18,0x03, 0x19,0x02, 0x19,0x03,0x1A,0x03, 0x19,0x03, 0x18,0x03, 0x17,0x02, 0x15,0x02,0x19,0x03, 0x1A,0x03, 0x19,0x03, 0x18,0x03, 0x17,0x02,0x15,0x02, 0x16,0x02, 0x0F,0x02, 0x15,0x16, 0x16,0x02,0x0F,0x02, 0x15,0x16, 0x00,0x00 };unsigned char const Music_fk[]={ 0x15,0x03, 0x10,0x03, 0x11,0x03, 0x15,0x66, 0x15,0x03,0x11,0x03, 0x15,0x03, 0x17,0x03, 0x17,0x03, 0x15,0x03,0x11,0x03, 0x10,0x03, 0x10,0x03, 0x10,0x66, 0x10,0x7A,0x15,0x03, 0x10,0x03, 0x11,0x03, 0x15,0x03, 0x10,0x03,0x11,0x03, 0x15,0x03, 0x11,0x03, 0x15,0x03, 0x17,0x03,0x17,0x03, 0x11,0x03, 0x11,0x03, 0x10,0x03, 0x15,0x03,0x10,0x66, 0x10,0x7A, 0x15,0x03, 0x16,0x03, 0x17,0x03,0x15,0x03, 0x16,0x03, 0x17,0x03, 0x19,0x03, 0x18,0x03,0x17,0x03, 0x15,0x03, 0x16,0x03, 0x17,0x66, 0x17,0x03,0x16,0x03, 0x15,0x03, 0x11,0x03, 0x15,0x03, 0x16,0x03,0x10,0x66, 0x10,0x02, 0x15,0x03, 0x16,0x03, 0x17,0x03,0x15,0x03, 0x16,0x03, 0x17,0x03, 0x19,0x03, 0x1A,0x03,0x17,0x03, 0x15,0x03, 0x16,0x03, 0x17,0x03, 0x17,0x03,0x1A,0x03, 0x16,0x03, 0x16,0x03, 0x15,0x03, 0x16,0x03,0x16,0x03, 0x15,0x03, 0x10,0x17, 0x17,0x03, 0x17,0x03,0x16,0x03, 0x17,0x03, 0x1F,0x66, 0x1F,0x66, 0x1B,0x66,0x17,0x03, 0x16,0x03, 0x17,0x03, 0x1A,0x03,0x19,0x03,0x17,0x03, 0x1A,0x03, 0x19,0x03, 0x17,0x03, 0x15,0x03,0x15,0x03, 0x15,0x03, 0x15,0x03, 0x16,0x03, 0x17,0x03,0x17,0x03, 0x17,0x03, 0x17,0x03, 0x17,0x03, 0x18,0x03,0x17,0x03, 0x15,0x66, 0x15,0x03, 0x11,0x03, 0x15,0x03,0x1A,0x03, 0x1A,0x03, 0x1A,0x03, 0x1A,0x03, 0x19,0x03,0x1A,0x03, 0x1B,0x7A, 0x00,0x00 };void KeyScan();void play_while();void Play(unsigned char *Sound,unsigned char Signature,unsigned Octachord,unsigned int Speed);#define u8 unsigned char#define u16 unsigned int#define u32 unsigned long#define WaitStatus 0 //按键过程的状态#define PressStatus 1#define ReleaseStatus 2#define BeepIO _pb4#define KEY1 _pb3#define KEY2 _pa7#define KEY3 _pa6#define KEY4 _pa5#define KEY5 _pa4#define KEY6 _pb2#define KEY7 _pb1#define KEY8 _pb0#define LED1 _pb5#define LED2 _pb6#define LED3 _pa3#define LED4 _pa1#define LED5 _pa0#define LED6 _pc2#define LED7 _pc1#define LED8 _pc0typedef struct{u16 count ;u8 name;u8 enable;}Timer;u8 KeyStatus=0,KeyPress=0,keyval=0;u8 mu_st=0;u8 music_en=0xff;Timer mytimer;#define true 1#define false 0const u16 fout[3][7]={{15289,13621,12135,11454,10204,9091,8099},{7645,6811,6068,5727,5102,4545,4050},{3822,3405,3034,2864,2551,2273,2025},};#define SOUND_SPACE 4/5 //定义普通音符演奏的长度分率,//每4分音符间隔unsigned int const FreTab[12] = { 262,277,294,311,330,349,369,392,415,440,466,494 }; //原始频率表unsigned char const SignTab[7] = { 0,2,4,5,7,9,11 };//1~7在频率表中的位置unsigned char const LengthTab[7]= { 1,2,4,8,16,32,64 };unsigned int NewFreTab[12]; //新的频率表unsigned int Point,LDiv,LDiv0,LDiv1,LDiv2,LDiv4,CurrentFre,SoundLength;unsigned char Tone,Length;unsigned char *Sound_bak;unsigned char start=0;void LED(u8 data){_pc0=data;_pc1=data>>1;_pc2=data>>2;_pa0=data>>3;_pa1=data>>4;_pa3=data>>5;_pb6=data>>6;_pb5=data>>7;}void LED3_8(u8 data){switch(data){case 0:LED(~0x01);break;case 1:LED(~0x02);break;case 2:LED(~0x04);break;case 3:LED(~0x08);break;case 4:LED(~0x10);break;case 5:LED(~0x20);break;case 6:LED(~0x40);break;case 7:LED(~0x80);break;}}void delayms(u16 i){u16 j;while(i--){for(j=0;j<220;j++){asm("nop");asm("nop");asm("nop");}}}void fchange(u16 f){_tm2al=f&0xff;_tm2ah=f>>8;}void main(){u8 worksta=1;_wdtc=0xa8;_acerl=0x00;_pcc=0x00;_pbc5=0;_pbc6=0;_csel=0;_cos=1;_acerl=0x00;_pbc|=0x0f;_pbc4=0;_pac=0xf0;_pac2=1;_papu2=1;_pbc|=0x0f;_pbpu|=0x0f;_pac|=0xf0;_papu|=0xf0;//ctm_tm2c0=0x10;_tm2c1=0xc1;_tm2al=0;_tm2ah=0>>8;_t2on=1;_mf1e=1;_t2ae=1;//stm_tm0c0=0x00;_tm0c1=0xc1;_tm0al=20000;_tm0ah=20000>>8;_mf0e=1;_t0ae=1;_t0on=1;_pawu2=1;_emi=1;while(1){KeyScan();if(KeyPress){KeyPress=0;if(keyval==1){start=1;worksta=2;music_en=0xff;switch(mu_st){case 0:Play(Music_sd,0,3,50);break;case 1:Play(Music_Two,0,3,50);break;case 2:Play(Music_Girl,0,3,50);break;case 3:Play(Music_Same,0,3,50);break;case 4:Play(Music_lzlh,0,3,50);break;case 5:Play(Music_fk,0,3,50);break;case 6:Point=SoundLength;worksta=2;break;}if(++mu_st==7)mu_st=0;}}switch(worksta){case 1:if(KEY1){LED1=1;}else{LED1=0;fchange(fout[0][1]);}if(KEY2){LED2=1;}else{LED2=0;fchange(fout[0][2]);}if(KEY3){LED3=1;}else{LED3=0;fchange(fout[0][3]);}if(KEY4){LED4=1;}else{LED4=0;fchange(fout[0][4]);}if(KEY5){LED5=1;}else{LED5=0;fchange(fout[0][5]);}if(KEY6){LED6=1;}else{LED6=0;fchange(fout[0][6]);}if(KEY7){LED7=1;}else{LED7=0;fchange(fout[0][7]);}if(KEY1 && KEY2 && KEY3 && KEY4 && KEY5 && KEY6 &&KEY7 )fchange(0);break;case 2: play_while();if(music_en==0)worksta=1;break;}}}DEFINE_ISR(tbase0,0x0c){_t0af=0;if(mytimer.enable==true){mytimer.count--;if(mytimer.count==0)mytimer.enable=false;}}DEFINE_ISR(t2,0x10){_t2af=0;BeepIO=~BeepIO;}void KeyScan(){switch(KeyStatus){case WaitStatus: //等待状态if(_pa2==0 )KeyStatus=PressStatus;break;case PressStatus: //按下状态if(_pa2==0 ){if(_pa2==0)keyval=1;KeyPress=1;KeyStatus=ReleaseStatus;}else{KeyStatus=WaitStatus;}break;case ReleaseStatus: //等待释放状态if(_pa2==0 ){}else{KeyStatus=WaitStatus;}break;}}//************************************************************************** void Play(unsigned char *Sound,unsigned char Signature,unsigned Octachord,unsigned int Speed) {unsigned char i,j;Sound_bak=Sound;for(i=0;i<12;i++) // 根据调号及升降八度来生成新的频率表{j = i + Signature;if(j > 11){j = j-12;NewFreTab[i] = FreTab[j]*2;}elseNewFreTab[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分音符的长度(几个10ms)LDiv4 = LDiv0/4; // 算出4分音符的长度LDiv4 = LDiv4-LDiv4*SOUND_SPACE; // 普通音最长间隔标准}void play_while(){u8 SL,SH,SM,SLen,XG,FD;if(start==1 &&(Point < SoundLength)){SL=Tone%10; //计算出音符LED3_8(SL);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; //高音fchange(4000000/CurrentFre);}SLen=LengthTab[Length%10]; //算出是几分音符XG=Length/10%10; //算出音符类型(0普通1连音2顿音)FD=Length/100;LDiv=LDiv0/SLen; //算出连音音符演奏的长度(多少个10ms)if (FD==1)LDiv=LDiv+LDiv/2;if(XG!=1)if(XG==0) //算出普通音符的演奏长度if (SLen<=4)LDiv1=LDiv-LDiv4;elseLDiv1=LDiv*SOUND_SPACE;elseLDiv1=LDiv/2; //算出顿音的演奏长度elseLDiv1=LDiv;if(SL==0) LDiv1=0;LDiv2=LDiv-LDiv1; //算出不发音的长度=1;if (SL!=0)//c{mytimer.count=LDiv1;mytimer.enable=true;}start=0;}if(==1 && mytimer.enable==false){=2;//zif(LDiv2!=0){fchange(0);BeepIO=1;mytimer.count=LDiv2;mytimer.enable=true;}}if(==2 && mytimer.enable==false){Point+=2; //cTone=Sound_bak[Point];Length=Sound_bak[Point+1];start=1;}if(Point >=SoundLength){fchange(0);BeepIO = 1;start=0;music_en=0;}}。
基于51单片机的电子琴完整版#include<reg52.h>#include <intrins.h>#define uint unsigned int#define uchar unsigned charsbit feng = P0^7; // 蜂鸣器uint FTemp;uint code tab[] = { //定时半周期的初始值64021,64103,64260,64400, //低音3 4 5 664524,64580,64684,64777, //低音7,中音1 2 364820,64898,64968,65030, //中音4 5 6 765058,65110,65157,65178}; //高音1 2 3 4//用扫描法读P1 外接4×4 键盘uchar Keyscan(void){uchar i, j, temp, Buffer[4] = {0xfe, 0xfd, 0xfb, 0xf7};for(j = 0; j < 4; j++) //循环四次,扫描四行{P1 = Buffer[j]; //在低四位分别输出一个低电平_nop_();temp = 0x80; //计划先读出P1.7位for(i = 0; i < 4; i++) //循环四次,检查四列{if(!(P1& temp)) //从高四位,截取1位{return (i + j * 4); //返回取得的按键值}temp >>= 1; //换右边一位}}return 16; //没有键按下就返回16}void Main(void){uchar Key_Value = 16, Key_Temp1, Key_Temp2;//读出的键值 TMOD = 0x01; //T0定时方式1ET0 = 1; //允许T0中断EX0 = 1; //允许INT0中断EA = 1;//开总中断while(1){TR0 = 0; //T0工作停,暂不发音Key_Temp1 = Keyscan(); //第一次读入按键if(Key_Temp1 != 16){ //有键按下Key_Temp2 = Keyscan(); //再读一次if (Key_Temp1 == Key_Temp2) //两次相等{Key_Value = Key_Temp1; //就确认下来FTemp = tab[Key_Value]; //根据键值,取出定时半周期的初始值TR0 = 1; //启动定时器T0,发音while (Keyscan() < 16); //等待释放feng = 1; //停止发音}}}}//========================================================= =====void T0_INT(void) interrupt 1{TL0 = FTemp; //载入定时半周期的初始值TH0 = FTemp >> 8;feng = ~feng; //发音。
基于单片机的电子琴设计一、引言二、总体设计方案(一)设计目标设计一款基于单片机的电子琴,能够实现基本的音符演奏、音色切换、节奏控制等功能,并且具有良好的音质和稳定性。
(二)系统组成本电子琴系统主要由单片机控制模块、键盘输入模块、音频输出模块、显示模块和电源模块等部分组成。
1、单片机控制模块选用 STM32 系列单片机作为控制核心,负责处理键盘输入信号、生成音频信号、控制显示等功能。
2、键盘输入模块采用矩阵键盘,通过扫描键盘获取用户的按键操作,将其转换为对应的音符编码发送给单片机。
3、音频输出模块使用DAC 芯片将单片机生成的数字音频信号转换为模拟音频信号,再通过放大器和扬声器输出声音。
4、显示模块采用液晶显示屏,用于显示当前的演奏状态、音色选择、节奏模式等信息。
5、电源模块为整个系统提供稳定的电源供应,可采用电池供电或外接电源适配器。
三、硬件设计(一)单片机最小系统STM32 单片机的最小系统包括时钟电路、复位电路和电源电路。
时钟电路为单片机提供工作时钟,复位电路用于系统初始化,电源电路为单片机提供稳定的电源。
(二)键盘电路矩阵键盘由行线和列线组成,通过逐行扫描的方式检测按键状态。
将键盘的行线和列线分别连接到单片机的 GPIO 引脚,通过编程实现键盘扫描和按键识别。
(三)音频输出电路选用高性能的 DAC 芯片,如 PCM1794,将单片机输出的数字音频信号转换为模拟音频信号。
为了提高音频输出的质量,还需要添加放大器和滤波电路,以增强信号的功率和去除噪声。
(四)显示电路液晶显示屏通过 SPI 接口或 I2C 接口与单片机连接,单片机通过发送指令和数据来控制显示屏的显示内容。
(五)电源电路根据系统的工作电压和电流需求,选择合适的电源芯片,如LM7805 等,将输入电源转换为所需的电压,并通过滤波电容等元件提高电源的稳定性。
四、软件设计(一)主程序流程主程序首先进行系统初始化,包括单片机初始化、键盘初始化、音频输出初始化、显示初始化等。
单片机电子琴程序(共3页) -本页仅作为预览文档封面,使用时请删除本页-;*******************************************************; 简易电子琴实验说明;实验目的: 1.掌握蜂鸣器的使用; 2.掌握蜂鸣器的不同发音的方法;实验内容: 1.通过单片机,令1-7号键由低到高发出1-7的音阶K1 BIT ;按键1K2 BIT ;按键2K3 BIT ;按键3K4 BIT ;按键4K5 BIT ;按键5K6 BIT ;按键6K7 BIT ;按键7Buzzer BIT ;蜂鸣器M1 EQU 17M2 EQU 16M3 EQU 15M4 EQU 14M5 EQU 13M6 EQU 12M7 EQU 11ORG 0000HLJMP STARTORG 0100HSTART: MOV SP,#60HMAIN: MOV P1,#0FFH ;P1口初始化LCALL Demo ;播放一段演示音乐MAIN_1: JB K1,MAIN_2 ;判断1号键是否按下,否则检测2号键LCALL Sound1 ;发音子程序MAIN_2: JB K2,MAIN_3 ;判断2号键是否按下,否则检测3号键LCALL Sound2 ;发音子程序MAIN_3: JB K3,MAIN_4 ;判断2号键是否按下,否则检测4号键LCALL Sound3 ;发音子程序MAIN_4: JB K4,MAIN_5 ;判断4号键是否按下,否则检测5号键LCALL Sound4 ;发音子程序MAIN_5: JB K5,MAIN_6 ;判断5号键是否按下,否则检测6号键LCALL Sound5 ;发音子程序MAIN_6: JB K6,MAIN_7 ;判断6号键是否按下,否则检测7号键LCALL Sound6 ;发音子程序MAIN_7: JB K7,MAIN_73 ;判断7号键是否按下,否则跳回检测1号键LCALL Sound7 ;发音子程序MAIN_73: SJMP MAIN_1 ;返回从1号键开始扫描;播放演示音乐Demo: MOV DPTR,#MusicDemo_1: CLR AMOVC A,@A+DPTRINC DPTRJZ Demo_RetLCALL SoundMCU ;放音子程序JMP Demo_1Demo_Ret: RET;乐曲:),0-结果标志Music: DB M1,M2,M3,M4,M5,M6,M7,M7,M7,M6,M5,M4,M3,M2,M1 DB M1,M2,M1,M2,M3,M2,M3,M4,M3,M4,M5,M4,M5,M6,M5DB M6,M7,M6,M7,M7,M6,M6,M6,0;程序控制发音SoundMCU: MOV R5,#40H ;控制放音时间MOV R7,AACALL TimeMOV R6,ASoundMCU_0: PUSH 06HSoundMCU_1: ACALL MusicalScaleDJNZ R6,SoundMCU_1POP 06HDJNZ R5,SoundMCU_0RET;计算时长Time: MOV B,#0FFHXCH A,BDIV ABXCH A,BCJNE A,#8,$+3JC Time_1INC BTime_1: XCH A,BRETMusicalScale: MOV A,R7MusicalScale1: CLR Buzzer ;1号键发音LCALL Delay ;延时DJNZ ACC,MusicalScale1MOV A,R7MusicalScale2: SETB BuzzerLCALL Delay ;延时DJNZ ACC,MusicalScale2RET;1号键发音Sound1: MOV R7,#M1 ;发音频率,越大频率越低Sound1_1: ACALL MusicalScaleJNB K1,Sound1_1RET;2号键发音Sound2: MOV R7,#M2 ;发音频率,越大频率越低Sound2_1: ACALL MusicalScaleJNB K2,Sound2_1RET;3号键发音Sound3: MOV R7,#M3Sound3_1: ACALL MusicalScaleJNB K3,Sound3_1RET;4号键发音Sound4: MOV R7,#M4Sound4_1: ACALL MusicalScaleJNB K4,Sound4_1RET;5号键发音Sound5: MOV R7,#M5Sound5_1: ACALL MusicalScaleJNB K5,Sound5_1RET;6号键发音Sound6: MOV R7,#M6Sound6_1: ACALL MusicalScaleJNB K6,Sound6_1RET;7号键发音Sound7: MOV R7,#M7 ;发音频率,越大频率越低Sound7_1: ACALL MusicalScaleJNB K7,Sound7_1RET;延时Delay: NOPRETEND。
单片机实验报告电子琴单片机实验报告电子琴引言:电子琴是一种流行的乐器,它通过电子元件产生声音,具有丰富的音色和音效。
在本次实验中,我们使用单片机来设计和制作一个简单的电子琴,通过按键触发不同的音调,实现基本的音乐演奏功能。
本文将介绍电子琴的原理、设计过程和实验结果。
一、原理电子琴的原理是基于音频合成技术,通过控制不同频率的声音波形来产生不同的音调。
而单片机作为电子琴的控制核心,负责接收按键信号,并通过输出引脚控制声音的发声。
具体来说,单片机通过读取按键的状态,判断按键是否按下,并根据按键的不同触发相应的音调发声。
二、设计过程1. 硬件设计在硬件设计方面,我们需要准备以下元件:单片机、按键、蜂鸣器、电阻、电容等。
首先,将按键连接到单片机的输入引脚上,以便检测按键的状态。
然后,将蜂鸣器连接到单片机的输出引脚上,以便通过控制引脚输出高低电平来实现声音的发声。
最后,根据需要添加电阻和电容等元件,以保证电路的稳定性和正确性。
2. 软件设计在软件设计方面,我们需要使用单片机的编程语言来实现电子琴的功能。
首先,我们需要设置单片机的输入引脚和输出引脚,并定义按键的状态和蜂鸣器的控制信号。
然后,我们需要编写程序来实现按键的检测和音调的控制。
具体来说,当按键按下时,单片机会读取按键的状态,并根据不同的按键触发不同的音调,同时控制蜂鸣器的输出信号,以实现声音的发声。
三、实验结果在实验过程中,我们成功地设计和制作了一个简单的电子琴。
通过按下不同的按键,我们可以听到不同的音调发声,从而演奏出简单的音乐。
实验结果表明,我们设计的电子琴具有良好的音效和音色,能够满足基本的音乐演奏需求。
结论:通过本次实验,我们深入了解了电子琴的原理和设计过程,并成功地制作了一个简单的电子琴。
通过单片机的控制,我们可以实现按键触发不同音调的发声,从而演奏出简单的音乐。
电子琴作为一种流行的乐器,具有广泛的应用和发展前景。
通过不断的学习和实践,我们相信可以设计出更加复杂和高级的电子琴,为音乐爱好者提供更多的乐器选择和音乐表达方式。
#include<reg51.h>sbit beer=P3^3;int num,count;int code lab[]={61719,62435,62506,62679,62985,63263,63512,63628,63835,64021,64103,64260,64400,64524,64580,64684,64777,64820,64898,64968,65030}; int code Song[]={0x12,50,0x12,50,0x12,100,0x12,50,0x12,50,0x12,100,0x10,50,0x12,50,0x13,15,0x12,25,0x10,25,0x0f,75,0x10,75,0x12,50,0x12,75,0x10,75,0x12,75,0x10,37,0x0f,37,0x0e,75,0x10,75,0x0f,150,0x10,100,0x10,100,0x0f,200,0x0c,100,0x0e,100,0x0f,300,0x00,0x00};void init() //计数器终端初始化{num=0;TMOD=0x11;TH0=0xff;TL0=0xff;TH1=0xD8; //装初值TL1=0xEF;EA=1;ET0=1;ET1=1;}void delay(int z) //延时子程序{int x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}void inter() interrupt 1 //计数器1{TH0=lab[num]/256;TL0=lab[num]%256;beer=!beer;}void timer1() interrupt 3 //计数器2{TH1=0xD8; //装初值TL1=0xEF;count++;}void Play_Song() //放歌子程序{unsigned char Temp2;unsigned int Addr;count = 0;while(1){num = Song[Addr];Addr++;TH0=lab[num]/256;TL0=lab[num]%256;if ( num == 0xFF ) //休止符{Temp2 = Song[Addr++];TR1 = 0;delay(Temp2);}else if ( num == 0x00 ) //歌曲结束符{return;}else{Temp2 = Song[Addr++];TR1 = 1;delay(1.1*Temp2);}}}void sound(unsigned char a) //按键发声子程序{switch(a){case 0xfe: num=14; break;case 0xfd: num=15; break;case 0xfb: num=16; break;case 0xf7: num=17; break;case 0xef: num=18; break;case 0xdf: num=19; break;case 0xbf: num=20; break;case 0x7f: num=7; break;}if(num==7)Play_Song();TH0=lab[num]/256;TL0=lab[num]%256;while(P2!=0xff){}}void main() //主程序{init();P2=0xff;while(1){if(P2!=0xff) //第一次判断是否有按键按下{delay(5); //消抖if(P2!=0xff)//确认是否有按键按下{TR0=1;sound(P2);}TR0=0;}}}。
#include <reg51.h>#define uchar unsigned char#define uint unsigned int#define disp_Off 0x3e#define disp_On 0x3f#define page_Add 0xb8 //页#define col_Add 0x40 //列#define start_Line 0xC0 //行//以下是C调中音的音频宏定义#define Z1 523 //将"Z1"宏定义为中音"1"的频率523Hz #define Z2 587 //将"Z2"宏定义为中音"2"的频率587Hz #define Z3 659 //将"Z3"宏定义为中音"3"的频率659Hz #define Z4 698 //将"Z4"宏定义为中音"4"的频率698Hz #define Z5 784 //将"Z5"宏定义为中音"5"的频率784Hz #define Z6 880 //将"Z6"宏定义为中音"6"的频率880Hz #define Z7 987 //将"Z7"宏定义为中音"7"的频率523H //以下是C调高音的音频宏定义#define H1 1046 //将"H1"宏定义为高音"1"的频率1046Hz #define H2 1174 //将"H2"宏定义为高音"2"的频率1174Hz #define H3 1318 //将"H3"宏定义为高音"3"的频率1318Hz #define H4 1396 //将"H4"宏定义为高音"4"的频率1396Hz #define H5 1567 //将"H5"宏定义为高音"5"的频率1567Hz #define H6 1760 //将"H6"宏定义为高音"6"的频率1760Hz #define H7 1975 //将"H7"宏定义为高音"7"的频率1975Hz//液晶显示器的端口定义sbit cs1=P2^1 ; //片选1sbit cs2=P2^2 ; //片选2sbit res=P2^3 ; //复位信号sbit rs=P2^4 ; //数据/指令选择sbit rw=P2^5 ; //读/写选择sbit en=P2^6 ; //读/写使能sbit key2=P2^7 ; //定义功能键key2,按下后开始播放音乐sbit sound=P2^0; //定义音频输出端sbit key1=P3^7 ; //定义功能键key1,按下后键入电子琴状态//矩阵键盘的定义端口sbit P14=P1^4; //将P14位定义为P1.4引脚sbit P15=P1^5; //将P15位定义为P1.5引脚sbit P16=P1^6; //将P16位定义为P1.6引脚sbit P17=P1^7; //将P17位定义为P1.7引脚//定义led端口sbit d0=P3^0;sbit d1=P3^1;sbit d2=P3^2;sbit d3=P3^3;sbit d4=P3^4;sbit d5=P3^5;sbit d6=P3^6;uint C,ff,k,num; //c为初值,ff为频率uchar keyval; //定义变量储存按键值//数码管显示数组uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//以下是《天空之城》简谱uint code f[]={Z6,Z7,/**/H1,Z7,H1,H3,/**/Z7,Z3,Z3,/**/Z6,Z5,Z6,H1,/**/Z5,Z3,Z3, /**/Z4,Z3,Z4,H1,Z3,H1,H1,H1,/**/Z7,Z4,Z4,Z7,/**/Z7,Z6,Z7,/**/H1,Z7,H1,H3,/**/Z7,Z3,Z3,/**/Z6,Z5,Z6,H1, Z5,Z3,/**/Z4,H1,Z7,H1,/**/H2,H2,H2,H1,/**/H1,Z6,Z7,Z5,/**/Z6,H1,H2,/**/H3,H2,H3,H5, H2,Z5,Z5,/**/H1,Z7,H1,H3,/**/H3,/**/Z6,H1,Z7,H2,/**/H1,Z5,Z5,/**/H4,H3,H2,H1,H3, /**/Z3,H3,/**/H6,H5,H5, /**/H3,H2,H1,H1,/**/H2,H1,H2,H5,/**/H3,H3,H6,H5, /**/H3,H2,H1,H1,/**/H2,H1,H2,Z7,/**/Z6,Z6,Z7,/**/Z6,0xff}; //以0xff作为音符的结束标志//以下是简谱中每个音符的节拍//"4"对应4个延时单位,"2"对应2个延时单位,"1"对应1个延时单位uchar code JP[ ]={4,4,/**/12,4,8,8,/**/20,4,4,/**/12,4,8,8,/**/20,4,4,/**/12,4,4,12,20,4,4,4,/**/12,4,8,8,/**/20,4,4,/**/12,4,8,8,/**/20,4,4,/**/12,4,8,8,32,4,/**/8,4,6,8,/**/4,4,4,16,/**/8,4,6,8,/**/24,4,4,/**/12,4,8,8,24,4,4,/**/4,4,8,8,/**/32,/**/4,8,8,6,/**/12,4,16,/**/8,8,8,8,30,/**/20,8,/**/16,8,8,/**/4,4,16,8,/**/8,4,4,8,/**/20,8,16,16,/**/4,20,8,/**/8,4,4,8,/**/20,4,4,/**/32,};//定义"正(0) 在(1) 播(2) 放(3) :(4)"数组uchar code hz1[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x02,0xC2,0x02,0x02,0x02,0xFE,0x82,0x82,0x82,0x82,0x82,0x02,0x00,0x00,0x40,0x40,0x40,0x7F,0x40,0x40,0x40,0x7F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,/*"正",0*///正0x08,0x08,0x88,0xC8,0x38,0x0C,0x0B,0x08,0x08,0xE8,0x08,0x08,0x08,0x08,0x08,0x00,0x02,0x01,0x00,0xFF,0x40,0x41,0x41,0x41,0x41,0x7F,0x41,0x41,0x41,0x41,0x40,0x00,/*"在",1*///在0x10,0x10,0xFF,0x10,0x90,0x82,0x56,0x3A,0x12,0x7F,0x11,0x39,0x55,0x90,0x80,0x00,0x42,0x82,0x7F,0x01,0x00,0x00,0xFF,0x49,0x49,0x7F,0x49,0x49,0xFF,0x00,0x00,0x00,/*"播",2*///播0x08,0x08,0xF9,0x4A,0x48,0xC8,0x48,0x20,0xD8,0x17,0x10,0x10,0xF0,0x10,0x10,0x00,0x40,0x30,0x0F,0x20,0x40,0x3F,0x80,0x40,0x21,0x16,0x08,0x16,0x21,0x40,0x80,0x00,/*"放",3*///放0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*":",4*///:0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,};//定义"《(0) 天(1) 空(2) 之(3) 城(4) 》(5)"数组uchar code hz2[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x40,0x20,0x90,0x48,0x24,0x12,0x09,0x04,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x04,0x09,0x12,0x24,0x48,0x10,0x20,0x00,0x00,/*"《",0*///《0x40,0x40,0x42,0x42,0x42,0x42,0x42,0xFE,0x42,0x42,0x42,0x42,0x42,0x40,0x40,0x00,0x80,0x80,0x40,0x20,0x10,0x0C,0x03,0x00,0x03,0x0C,0x10,0x20,0x40,0x80,0x80,0x00,/*"天",1*///天0x10,0x0C,0x44,0x24,0x14,0x04,0x05,0x06,0x04,0x04,0x14,0x24,0x44,0x14,0x0C,0x00,0x00,0x40,0x40,0x41,0x41,0x41,0x41,0x7F,0x41,0x41,0x41,0x41,0x40,0x40,0x00,0x00,/*"空",2*///空0x00,0x10,0x10,0x10,0x10,0x10,0x11,0x16,0x10,0x90,0x50,0x30,0x10,0x00,0x00,0x00,0x00,0x40,0x20,0x10,0x10,0x28,0x44,0x42,0x41,0x40,0x40,0x40,0x40,0x40,0x40,0x00,/*"之",3*///之0x20,0x20,0xFF,0x20,0x20,0xF8,0x88,0x88,0x88,0x08,0xFF,0x08,0x09,0xCA,0x08,0x00,0x10,0x30,0x1F,0x88,0x68,0x1F,0x10,0x20,0x9F,0x40,0x27,0x18,0x26,0x41,0xF0,0x00,/*"城",4*///城0x00,0x00,0x02,0x04,0x09,0x12,0x24,0x48,0x90,0x20,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x10,0x48,0x24,0x12,0x09,0x04,0x02,0x01,0x00,0x00,0x00,0x00,0x00,/*"》",5*///》0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/************************************************函数功能:1个延时单位,延时200ms,用于节拍延时*************************************************/void delayjp(){unsigned char i,j;for(i=0;i<100;i++)for(j=0;j<250;j++);}/*************************************************函数功能:用于LCD显示延时程序**************************************************/void delaylcd(uchar x){int d;uchar y;for(y=0;y<x;y++)for(d=0;d<10;d++);}/*********************************************函数功能:一般延时函数**********************************************/void delayms(uint x){uint i,j;for(i=x;i>0;i--)for(j=110;j>0;j--);}/*********************************************函数功能:数码管显示函数**********************************************/void display(uchar key){uchar key1 ;key1=key-1 ;P0=table[key1];}/*******************************************函数功能:输出音频、输出数码管显示函数******************************************/void output(void){display(keyval);C=(46083/ff)*10; //计算定时常数,c为定时常数TH1=(8192-C)/32; //可证明这是13位计数器TH0高8位的赋初值方法TL1=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初值方法TR1=1 ; //开定时T0delayms(200) ; //延时200ms,播放音频TR1=0 ; //关闭定时器sound=~sound ; //关闭蜂鸣器keyval=0xff ; //播放按键音频后,将按键值更改,停止播放}/********************************************************函数功能:当播放音乐时使对应音符的LED灯亮*********************************************************/void opled(uint num){if((num==523)|(num==1046))d0=0;if((num==587)|(num==1174))d1=0;if((num==659)|(num==1318))d2=0;if((num==698)|(num==1396))d3=0;if((num==784)|(num==1567))d4=0;if((num==880)|(num==1760))d5=0;if((num==987)|(num==1975))d6=0;}/*************************************************函数功能:进行矩阵键盘扫描,判断键位**************************************************/void keyscan(void){P1=0xf0; //所有行线置为低电平“0”,所有列线置为高电平“1”if((P1&0xf0)!=0xf0) //列线中有一位为低电平“0”,说明有键按下{delayms(10); //延时一段时间、软件消抖if((P1&0xf0)!=0xf0) //确实有键按下{P1=0xfe; //第一行置为低电平“0”(P1.0输出低电平“0”)if(P14==0) //如果检测到接P1.4引脚的列线为低电平“0”{ keyval=1; //可判断是S1键被按下while(!(P1==0xfe));}if(P15==0) //如果检测到接P1.5引脚的列线为低电平“0”{keyval=2; //可判断是S2键被按下while(!(P1==0xfe));}if(P16==0) //如果检测到接P1.6引脚的列线为低电平“0”{keyval=3; //可判断是S3键被按下while(!(P1==0xfe));}if(P17==0) //如果检测到接P1.7引脚的列线为低电平“0”{ keyval=4; //可判断是S4键被按下while(!(P1==0xfe));}P1=0xfd; //第二行置为低电平“0”(P1.1输出低电平“0”)if(P14==0) //如果检测到接P1.4引脚的列线为低电平“0”{ keyval=5; //可判断是S5键被按下while(!(P1==0xfd));}if(P15==0) //如果检测到接P1.5引脚的列线为低电平“0”{ keyval=6; //可判断是S6键被按下while(!(P1==0xfd));}if(P16==0) //如果检测到接P1.6引脚的列线为低电平“0”{ keyval=7; //可判断是S7键被按下while(!(P1==0xfd));}if(P17==0) //如果检测到接P1.7引脚的列线为低电平“0”{ keyval=8; //可判断是S8键被按下while(!(P1==0xfd));}P1=0xfb; //第三行置为低电平“0”(P1.2输出低电平“0”)if(P14==0) //如果检测到接P1.4引脚的列线为低电平“0”{keyval=9; //可判断是S9键被按下while(!(P1==0xfb));}if(P15==0) //如果检测到接P1.5引脚的列线为低电平“0”{ keyval=10; //可判断是S10键被按下while(!(P1==0xfb)); }if(P16==0) //如果检测到接P1.6引脚的列线为低电平“0”{keyval=11; //可判断是S11键被按下while(!(P1==0xfb));}if(P17==0) //如果检测到接P1.7引脚的列线为低电平“0”{keyval=12; //可判断是S12键被按下while(!(P1==0xfb));}P1=0xf7; //第四行置为低电平“0”(P1.3输出低电平“0”)if(P14==0) //如果检测到接P1.4引脚的列线为低电平“0”{keyval=13; //可判断是S13键被按下while(!(P1==0xf7));}if(P15==0) //如果检测到接P1.5引脚的列线为低电平“0”{keyval=14; //可判断是S14键被按下while(!(P1==0xf7));}if(P16==0) //如果检测到接P1.6引脚的列线为低电平“0”{ keyval=15; //可判断是S15键被按下while(!(P1==0xf7));}if(P17==0) //如果检测到接P1.7引脚的列线为低电平“0”{keyval=16; //可判断是S16键被按下while(!(P1==0xf7));}}}}/*********************************************函数功能:检查LCD是否忙**********************************************/void checkstate(){uchar dat,DATA; //状态信息(判断是否忙)rs=0; // 数据\指令选择rw=1; //R/W="H" ,E="H"数据被读到DB7∽DB0do{DATA=0x00;en=1; //EN下降源delaylcd(1); //延时dat=DATA;en=0;dat=0x80 & dat; //仅当第7位为0时才可操作(判别busy信号) }while(!(dat==0x00));}/**********************************************函数功能:写命令到LCD程序***********************************************/void write_com(uchar cmdcode){checkstate(); //检测LCD是否忙rs=0;rw=0;P0=cmdcode;delaylcd(1);en=1;delaylcd(1);en=0;}/************************************************函数功能:写数据到LCD程序*************************************************/void write_data(uchar Dispdata){checkstate(); //检测LCD是否忙rs=1;rw=0;P0=Dispdata;delaylcd(1);en=1;delaylcd(1);en=0;}/*******************************************函数功能:LCD初始化程序********************************************/void init_lcd(){delaylcd(1);cs1=1; //刚开始关闭两屏cs2=1;delaylcd(1);write_com(disp_Off); //写初始化命令write_com(page_Add+0);write_com(start_Line+0);write_com(col_Add+0);write_com(disp_On);}/********************************************函数功能:清屏函数*********************************************/void clr_scr(){uchar j,k;cs1=0; //左、右屏均开显示cs2=0;write_com(page_Add+0);write_com(col_Add+0);for(k=0;k<8;k++) //控制页数0-7,共8页{write_com(page_Add+k); //每页每页进行写for(j=0;j<64;j++) //每页最多可写32个中文文字或64个ASCII字符{write_com(col_Add+j);write_data(0x00); //控制列数0-63,共64列,写点内容,列地址自动加1 }}}/**********************************************函数功能:LCD一行一行写入显示数据***********************************************/Disp(uchar page,uchar column, uchar code *word){uchar i;cs1=0;cs2=1;write_com(0xb8+page);write_com(0x40+column);for(i=0;i<16;i++)write_data(word[i]);for(i=32;i<48;i++)write_data(word[i]);for(i=64;i<80;i++)write_data(word[i]);for(i=96;i<112;i++)write_data(word[i]);cs1=1;cs2=0;write_com(0xb8+page);write_com(0x40);for(i=128;i<144;i++)write_data(word[i]);for(i=160;i<176;i++)write_data(word[i]);for(i=192;i<208;i++)write_data(word[i]);for(i=224;i<240;i++)write_data(word[i]);cs1=0;cs2=1;write_com(0xb8+page+1);write_com(0x40+column);for(i=16;i<32;i++)write_data(word[i]);for(i=48;i<64;i++)write_data(word[i]);for(i=80;i<96;i++)write_data(word[i]);for(i=112;i<128;i++)write_data(word[i]);cs1=1;cs2=0;write_com(0xb8+page+1);write_com(0x40);for(i=144;i<160;i++)write_data(word[i]);for(i=176;i<192;i++)write_data(word[i]);for(i=208;i<224;i++)write_data(word[i]);for(i=240;i<250;i++)write_data(word[i]);}/******************************************函数功能:程序主函数,进行功能选择*******************************************/void main(){uchar ii,jj; //ii确定音频数组元素,jj控制节拍数EA=1; //开总中断ET0=1; //定时器T0中断允许ET1=1; //定时器T1中断允许TMOD=0x00; //使用定时器T0、T1的模式0(13位计数器) P0=0; //开始使数码管不显示if(key2==0) //功能键key2按下,用于显示12864{delayms(10); //延时去抖if(key2==0) //功能键key2确实按下{P0=0;init_lcd();clr_scr();k=0;while(1){for(k=0xc0;k<0xff;k=k+16){Disp(2,0,hz1);Disp(4,0,hz2);}ii=0; //从第1个音符f[0]开始播放while(f[ii]!=0xff) //只要没有读到结束标志就继续播放{C=460830/f[ii]; //确定初值TH0=(8192-C)/32; //可证明这是13位计数器TH0高8位的赋初值方法 5TL0=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初值方法TR0=1; //启动定时器T0num=f[ii];opled(num);for(jj=0;jj<JP[ii];jj++) //控制节拍数delayjp(); //延时1个节拍单位TR0=0; //关闭定时器T0P3=0xff;ii++; //播放下一个音符}}}}if(key1==0) //功能键key1按下{delayms(10); //延时去抖if(key1==0) //功能键key1确实按下{cs1=1;cs2=1;P0=0xff; //使数码管全亮while(1) //无限循环{keyscan();switch(keyval){case 1:ff=Z1; //如果第1个键按下,将中音1的频率赋给ffoutput(); //转去计算定时常数,输出音频和数字break;case 2:ff=Z2; //如果第2个键按下,将中音2的频率赋给ffoutput(); //转去计算定时常数,输出音频和数字break;case 3:ff=Z3; //如果第3个键按下,将中音3的频率赋给ffoutput(); //转去计算定时常数,输出音频和数字break;case 4:ff=Z4; //如果第4个键按下,将中音4的频率赋给ffoutput(); //转去计算定时常数,输出音频和数字break;case 5:ff=Z5; //如果第5个键按下,将中音5的频率赋给ffoutput(); //转去计算定时常数,输出音频和数字break;case 6:ff=Z6; //如果第6个键按下,将中音6的频率赋给ffoutput(); //转去计算定时常数,输出音频和数字break;case 7:ff=Z7; //如果第7个键按下,将中音7的频率赋给ffoutput(); //转去计算定时常数,输出音频和数字break;case 8:ff=H1; //如果第8个键按下,将高音1的频率赋给ffoutput(); //转去计算定时常数,输出音频和数字break;case 9:ff=H2; //如果第9个键按下,将高音2的频率赋给ffoutput(); //转去计算定时常数,输出音频和数字break;case 10:ff=H3; //如果第10个键按下,将高音3的频率赋给ffoutput(); //转去计算定时常数,输出音频和数字break;case 11:ff=H4; //如果第11个键按下,将高音4的频率赋给ffoutput(); //转去计算定时常数,输出音频和数字break;case 12:ff=H5; //如果第12个键按下,将高音5的频率赋给ffoutput(); //转去计算定时常数,输出音频和数字break;case 13:ff=H6; //如果第13个键按下,将高音6的频率赋给ffoutput(); //转去计算定时常数,输出音频和数字break;case 14:ff=H7; //如果第14个键按下,将高音7的频率赋给ffoutput(); //转去计算定时常数,输出音频和数字break;case 15:ff=H1; //如果第15个键按下,将高音1的频率赋给ffoutput(); //转去计算定时常数,输出音频和数字break;case 16:ff=H2; //如果第16个键按下,将高音2的频率赋给ffoutput(); //转去计算定时常数,输出音频和数字break;}}}}}/************************************************************函数功能:定时器T0的中断服务,使P2.0引脚输出音频方波播放音乐**************************************************************/void Time0() interrupt 1 using 1{sound=!sound; //将P2.0引脚输出电平取反,形成方波TH0=(8192-C)/32; //可证明这是13位计数器TH0高8位的赋初值方法TL0=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初值方法}/************************************************************函数功能:定时器T1的中断服务,使P2.0引脚输出音频方波输出音符**************************************************************/void Time1() interrupt 3 using 1{TH1=(8192-C)/32; //可证明这是13位计数器TH0高8位的赋初值方法TL1=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初值方法sound=!sound; //将P2.0引脚取反,输出音频方波}。
目录目录 0一、设计内容 (1)二、方案讨论 (1)三、电路原理图 (2)四、程序设计 (5)五、电子琴发声原理 (8)六、调试结果 (8)七、电子琴程序 (9)八、参考文献 (17)一、设计内容(一)设计题目:电子琴演奏(二)目的要求1)使用4×4矩阵式键盘设计出16个音符,随意弹奏。
2)用功能键可转换成3首不同的歌曲演奏。
二、方案讨论(一)方案一:用4×4矩阵式键盘控制16个音符,用三个独立按键作为功能键,实现三首不同歌曲的演奏。
方案二:通过一个开关控制4×4矩阵式键盘的功能转换,同时控制16个音符和歌曲的演奏。
方案一虽然用的按键相对较多,但是整体结构简单明了,便于理解和编程,而且音符和歌曲两部分不易产生干扰;方案二结构紧凑,电路简单,但程序较为繁琐,易产生干扰。
故采用第二种方案。
(二)方案图(三)面板布置图(四)设计任务1)电路结构设计在PROTEUS中绘制电子琴各部分的电路,能量流要正确。
2)软件设计用汇编语言编写程序,实现电子琴的功能3)调试仿真将编译生成的.hex文件导入芯片,进行仿真。
三、电路原理图(一)时钟电路(二)复位电路(三)功放驱动电路及LM386(四)4×4矩阵式键盘电路(五)三个控制自动音乐播放的独立按键电路(六)整体电路(二)16音阶程序框图(三)T0中断服务程序框图(四)自动音乐播放程序框图YYNN返回五、电子琴发声原理一首音乐是许多不同的音阶组成的,而每个音阶对应着不同的频率,这样我们就可以利用不同的频率的组合,即可构成我们所想要的音乐了,当然对于单片机来产生不同的频率非常方便,我们可以利用单片机的定时/计数器T0来产生这样方波频率信号,因此,我们只要把一首歌曲的音阶对应频率关系弄正确即可。
现在以单片机12MHZ晶振为例,例出高中低音符与单片机计数T0相关的计数值如下表所示:音符频率(HZ)简谱码(T值)音符频率(HZ)简谱码(T值)低1 DO 262 63628 # 4 FA# 740 64860#1 DO# 277 63731 中 5 SO 784 64898低2 RE 294 63835 # 5 SO# 831 64934#2 RE# 311 63928 中 6 LA 880 64968低 3 M 330 64021 # 6 932 64994低 4 FA 349 64103 中 7 SI 988 65030# 4 FA# 370 64185 高 1 DO 1046 65058低 5 SO 392 64260 # 1 DO# 1109 65085# 5 SO# 415 64331 高 2 RE 1175 65110低 6 LA 440 64400 # 2 RE# 1245 65134# 6 466 64463 高 3 M 1318 65157低 7 SI 494 64524 高 4 FA 1397 65178中 1 DO 523 64580 # 4 FA# 1480 65198# 1 DO# 554 64633 高 5 SO 1568 65217中 2 RE 587 64684 # 5 SO# 1661 65235# 2 RE# 622 64732 高 6 LA 1760 65252中 3 M 659 64777 # 6 1865 65268中 4 FA 698 64820 高 7 SI 1967 65283六、调试结果在Keil软件中进行了程序的编写、调试以及编译,软件显示程序没有错误。
此程序是51单片机c语言编写的电子琴+音乐播放器,当用杜邦线将P1^0管脚接地时,单片机就会放出《世上只有妈妈好》,将P1^1 管脚接地时单片机就播放《祝你生日快乐》,两者为高电平时进入电子钢琴模式,利用16个矩阵键盘发出相应的哆、瑞、米、发、索。
此文档的乐谱是借鉴别人的,因为本人是音乐白痴!这是我第一次发表,我希望能帮到有需要的人啦........#include <reg52.h>#define uchar unsigned char#define uint unsigned intsbit beep=P2^3; //定义蜂鸣器sbit music=P1^0; //music为低电平播放《世上只有妈妈好》(工作模式为音乐播放器),music1为低电平时播放祝你生日快乐,music、music1都为高电平时(工作模式为电子钢琴)sbit music1=P1^1;uchar timer0h,timer0l,time,key,flag; //flag==0时为电子钢琴模式,flag==1时为音乐播放器uchar code yuepu[]={ 6,2,3,5,2,1, 3,2,2, 5,2,2, 1,3,2, 6,2,1, 5,2,1, 6,2,4,3,2,2, 5,2,1, 6,2,1, 5,2,2, 3,2,2, 1,2,1, 6,1,1, 5,2,1, 3,2,1, 2,2,4, 2,2,3, 3,2,1, 5,2,2, 5,2,1,6,2,1, 3,2,2, 2,2,2, 1,2,4, 5,2,3, 3,2,1, 2,2,1, 1,2,1, 6,1,1, 1,2,1, 5,1,6, 0,0,0 }; //世上只有妈妈好乐谱uchar code yuepu1[]={5,1,1, 5,1,1, 6,1,2, 5,1,2, 1,2,2, 7,1,4,5,1,1, 5,1,1, 6,1,2, 5,1,2, 2,2,2, 1,2,4,5,1,1, 5,1,1, 5,2,2, 3,2,2, 1,2,2, 7,1,2, 6,1,2,4,2,1, 4,2,1, 3,2,2, 1,2,2, 2,2,2, 1,2,4};//祝你生日快乐乐谱uchar code TH_0[]={0xF2,0xF3,0xF5,0xF5,0xF6,0xF7,0xF8,0xF9,0xF9,0xFA,0xFA,0xFB,0xFB,0xFC,0xFC,0xFC,0xFD,0xFD,0xFD,0xFD,0xFE, // 28个音阶高八位频率表装进定时器高八位0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF,} ;uchar code TL_0[]={0x42,0xC1,0x17,0xB6,0xD0,0xD1,0xB6,0x21,0xE1,0x8C,0xD8,0x68,0xE9,0x5B,0x8F, // 28个音阶低八位频率表装进定时器低八位0xEE,0x44, 0x6B,0xB4,0xF4,0x2D,0x47,0x77,0xA2,0xB6,0xDA,0xFA,0x16,};void delay(uchar t){uchar t1;unsigned long t2;for(t1=0;t1<t;t1++) //延时半拍函数,控制音乐节奏{for(t2=0;t2<8000;t2++){ ; }}}void song(){TH0=timer0h;TL0=timer0l; // 唱歌程序TR0=1;delay(time); //延时,让此音节播放的长短TR0=0; //关定时器,为下个音节响做准备}void delayms(uint x){uint i,j; //去抖延时for(i=x;i>0;i--)for(j=110;j>0;j--);}void keyscan() //检测十六个发出音乐按键函数{ uchar temp;P3=0xfe;temp=P3;temp=0xf0&temp;if(temp!=0x0f){ delayms(10); //检测第一行按键temp=P3 ;temp=temp&0xf0;if(temp!=0xf0){temp=P3;switch(temp){case 0xee: key=0;break;case 0xde: key=1;break;case 0xbe: key=2;break;case 0x7e: key=3;break;}TH0=TH_0[key]; //将按下的键对应发出此频率声音的初值装入TL0=TL_0[key];TR0=1; //打开定时器0while(temp!=0xf0) //一直按下就一直发声{temp=P3;temp=temp&0xf0;}TR0=0; //松手时关闭定时器0,不能发声beep=1;//使蜂鸣器置高关闭,预防在进入中断取反时将它置低打开}}P3=0xfd;temp=P3;temp=0xf0&temp;if(temp!=0x0f) // 检测第二行按键{ delayms(10);temp=P3 ;temp=temp&0xf0;if(temp!=0xf0){temp=P3;switch(temp){case 0xed: key=4;break;case 0xdd: key=5;break;case 0xbd: key=6;break;case 0x7d: key=7;break;}TH0=TH_0[key]; //将按下的键对应发出此频率声音的初值装入TL0=TL_0[key];定时器0while(temp!=0xf0) //一直按下就一直发声{temp=P3;temp=temp&0xf0;}TR0=0; //松手时关闭定时器0,不能发声beep=1; //使蜂鸣器置高关闭,预防在进入中断取反时将它置低打开}}P3=0xfb;temp=P3;temp=0xf0&temp;if(temp!=0x0f){ delayms(10);temp=P3 ;temp=temp&0xf0;if(temp!=0xf0){temp=P3;switch(temp){case 0xeb: key=8;break;case 0xdb: key=9;break;case 0xbb: key=10;break;case 0x7b: key=11;break;}TH0=TH_0[key]; //将按下的键对应发出此频率声音的初值装入TL0=TL_0[key];TR0=1; //打开定时器0while(temp!=0xf0) //一直按下就一直发声{temp=P3;temp=temp&0xf0;}手时关闭定时器0,不能发声beep=1; //使蜂鸣器置高关闭,预防在进入中断取反时将它置低打开}}P3=0xf7;temp=P3;temp=0xf0&temp;if(temp!=0x0f){ delayms(10);temp=P3 ;temp=temp&0xf0;if(temp!=0xf0){temp=P3;switch(temp){case 0xe7: key=12;break;case 0xd7: key=13;break;case 0xb7: key=14;break;case 0x77: key=15;break;}TH0=TH_0[key]; //将按下的键对应发出此频率声音的初值装入TL0=TL_0[key];TR0=1; //打开定时器0while(temp!=0xf0) //一直按下就一直发声{temp=P3;temp=temp&0xf0;}TR0=0; //松手时关闭定时器0,不能发声beep=1; //使蜂鸣器置高关闭,预防在进入中断取反时将它置低打开}}}void main(){uchar k,i;TMOD=1;EA=1;ET0=1;while(1){if(music&&music1) //当两个都为高电平时没有放音乐,扫描键盘{ flag=0;keyscan();}if(!music) //当P1^0管脚为低电平时,播放《世上只有妈妈好》{ flag=1;i=0;while(i<100) //音乐数组长度,唱完从头再来{if(music) //在播放音乐时P1^0为高电平时退出播放此歌曲{ beep=1; //使蜂鸣器置高关闭,预防在进入中断取反时将它置低打开break;}k=yuepu[i]+7*yuepu[i+1]-1;timer0h=TH_0[k]; // 把对应的音乐频率放进定时器0timer0l=TL_0[k];time=yuepu[i+2]; //音乐节拍i+=3;song();}}if(!music1) // music为低电平时,播放《祝你生日快乐》{ flag=1;i=0;while(i<75) //乐谱的长度{if(music1){beep=1;break;}k=yuepu1[i]+7*yuepu1[i+1]-1;timer0h=TH_0[k];timer0l=TL_0[k];time=yuepu1[i+2];i+=3;song();}}}}void time0() interrupt 1{if(flag==0){beep=!beep; //电子琴模式时进入此语句TH0=TH_0[key];TL0=TL_0[key];}else{ beep=!beep;TH0=timer0h; //音乐播放器模式进入此语句TL0=timer0l;}}。
基于51单片机的电子琴设计课程设计单片机原理》课程设计前言本课程设计旨在通过基于51单片机的电子琴设计,加深学生对单片机原理的理解和应用。
在本设计中,我们将介绍电子琴的设计要求、所用设备及软件以及总体设计方案。
随后,我们将详细介绍系统硬件设计中琴键控制电路、音频功放电路、时钟-复位电路和LED显示电路的设计。
第1章基于51单片机的电子琴设计1.1 电子琴的设计要求在电子琴的设计中,我们需要考虑琴键数量、音频输出质量、电源电压和外部接口等因素。
在本设计中,我们将采用25个琴键,保证音频输出质量和电源电压稳定,并提供外部接口以便于扩展和调试。
1.2 电子琴设计所用设备及软件在本设计中,我们将使用51单片机、琴键、音频功放、时钟、LED显示器等设备,并使用Keil C51编译器进行软件开发。
1.3 总体设计方案在总体设计方案中,我们将采用按键扫描方式实现琴键控制,使用PWM技术实现音频输出,使用外部晶振提供时钟信号,并使用LED显示器显示琴键状态。
第2章系统硬件设计2.1 琴键控制电路在琴键控制电路中,我们将采用矩阵按键扫描方式,通过51单片机的IO口进行扫描和检测。
同时,我们还将使用电容式触摸开关来实现琴键的触发。
2.2 音频功放电路在音频功放电路中,我们将采用TDA7297芯片作为功放,通过PWM技术实现音频输出,并通过滤波电路滤除杂音和谐波。
2.3 时钟-复位电路在时钟-复位电路中,我们将采用12MHz晶振作为时钟源,并使用复位电路确保系统在上电时能够正确运行。
2.4 LED显示电路在LED显示电路中,我们将采用MAX7219芯片实现LED点阵显示,并通过SPI接口与51单片机进行通信。
同时,我们还将使用CD4511芯片实现数码管显示琴键状态。
通过本课程设计,我们可以深入理解单片机原理的应用,掌握电子琴的设计和制作技术,提高自身的实践能力和创新能力。
2.5 整体电路本章将介绍电子琴的整体电路设计。
单片机电子琴程序+详细注解#include#include#include#includesbit lie0=P2^3;sbit lie1=P2^2;sbit lie2=P2^1;sbit lie3=P2^0;sbit PWM1=P2^6;unsigned char temp;unsigned char key;unsigned char STH0,STL0;unsigned char jishi=0;unsigned char n=0; //n为节拍常数变量unsigned char a[7]={00,59,19,3,4,8,10}; //设置时间的初始值unsigned char b[7]; //将所更新的时间放入数组b中/***********1s延时程序***********/void delay1s(void){unsigned char i,k;for(k=100;k>0;k--)for(i=100;i>0;i--);}/**************************************************//******************定时器0中断*******************/void TIMER0(void) interrupt 1{TH0=STH0;TL0=STL0;PWM1=~PWM1;}/*************************************************//******************定时器1中断*******************/void int0() interrupt 3 //采用中断3 控制节拍节拍延时{ TH1=0xd8;TL1=0xef;n--;}/**************************************************//****************频率延时程序*******************/void delay (unsigned char m) //控制频率延时{unsigned i=3*m;while(--i);}/************************************************//***************************毫秒延时子程序**************************/void delayms(unsigned char a){while(--a); //采用while(--a) 不要采用while(a--);}/************************************************************** *****//**************************设置1-8曲调值*************************/unsigned int code tab[]={0xfc43,0xfd08,0,0,0xfd20,0xfd32,0,0,0xfd81,0xfdc7,0,0,0xfe05,0xfe21,0,0,};/************************************************************** *//**************以下对应数码管0-f**************************/ unsigned char code table[]={0x03,0x9f,0x25,0x0d,0x99,0x49,0x41,0x1f,0x01,0x09,0x11,0xc1,0x63,0x85,0x61,0x71,0xff};/************************************************************** *//*********************第一首音乐老男孩***************************/unsigned char code music_tab_1[]={/*1*/0x20,0x20,0x20,0x10,0x20,0x10,0x20,0x20,0x20,0x20,0x20,0x20,0x1c,0x20,0x20,0x20,0x24,0x20,0x26,0x20,0x1c,0x20,0x19,0x20,0x18,0x10,0x19,0x10,0x20,0x30,0x01,0x20,0x20,0x10,0x20,0x10,0x1c,0x20,0x30,0x20,0x30,0x20,0x2b,0x20,0x26,0x20,0x20,0x20,0x01,0x20,0x20,0x20,0x24,0x20,0x20,0x20,0x26,0x10,0x2b,0x20,0x30,0x10,0x2b,0x60,/*2*/0x20,0x20,0x20,0x10,0x20,0x10,0x20,0x20,0x20,0x20,0x20,0x20,0x1c,0x20,0x20,0x20,0x24,0x20,0x26,0x20,0x1c,0x20,0x19,0x20,0x18,0x10,0x19,0x10,0x20,0x30,0x01,0x20,0x20,0x10,0x20,0x10,0x1c,0x20,0x30,0x20,0x30,0x20,0x2b,0x20,0x26,0x20,0x20,0x20,0x01,0x20,0x20,0x20,0x24,0x20,0x20,0x20,0x26,0x10,0x2b,0x20,0x30,0x10, 0x2b,0x60,//11767112377550x30,0x40,0x18,0x20,0x19,0x20,0x1c,0x20,0x19,0x10, 0x18,0x10,0x18,0x20,0x2b,0x20,0x13,0x20,0x19,0x20,0x19,0x20,0x20,0x10,0x20,0x10,//632211170x1c,0x20,0x13,0x10,0x15,0x10,0x15,0x20,0x18,0x20, 0x18,0x40,0x18,0x20,0x19,0x20,//67112377550x1c,0x20,0x19,0x10,0x18,0x10,0x18,0x20,0x15,0x20, 0x13,0x20,0x19,0x20,0x19,0x20,0x20,0x10,0x20,0x10, //6322110x1c,0x20,0x13,0x10,0x15,0x10,0x15,0x20,0x18,0x20, 0x18,0x60,//000000x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x60, //1155555 5777550x18,0x10,0x18,0x10,0x10,0x20,0x10,0x10,0x10,0x10, 0x10,0x20,0x10,0x20,0x10,0x20,0x19,0x10,0x19,0x10,0x19,0x20,0x20,0x10,0x20,0x10,//555565111120x10,0x20,0x10,0x10,0x10,0x10,0x10,0x20,0x0e,0x20, 0x10,0x20,0x18,0x10,0x18,0x10,0x18,0x20,0x18,0x10, 0x15,0x10,//32443324430x13,0x20,0x15,0x10,0x12,0x10,0x12,0x20,0x13,0x20, 0x13,0x20,0x15,0x10,0x12,0x10,0x12,0x20,0x13,0x20, //324430x13,0x20,0x15,0x10,0x12,0x10,0x12,0x20,0x13,0x20,//55110x10,0x40,0x10,0x20,0x18,0x10,0x18,0x10,//555555777550x10,0x20,0x10,0x10,0x10,0x10,0x10,0x20,0x10,0x20,0x10,0x20,0x19,0x10,0x19,0x10,0x19,0x20,0x20,0x10, 0x20,0x10, //555565111120x10,0x20,0x10,0x10,0x10,0x10,0x10,0x20,0x0e,0x20,0x10,0x20,0x18,0x10,0x18,0x10,0x18,0x20,0x18,0x10, 0x15,0x10, //32443321710x13,0x20,0x15,0x10,0x12,0x10,0x12,0x20,0x13,0x20,0x13,0x20,0x15,0x10,0x18,0x10,0x18,0x20,0x19,0x10, 0x18,0x60, 0x01,0x40,0x01,0x40,//第二次/*3*/0x20,0x20,0x1c,0x20,0x20,0x20,0x24,0x20,0x26,0x20,0x1c,0x20,0x19,0x20,0x18,0x10,0x19,0x10,0x20,0x30,0x01,0x20,0x20,0x10,0x20,0x10,0x1c,0x20,0x30,0x20,0x30,0x20,0x2b,0x20,0x26,0x20,0x20,0x20,0x01,0x20,0x20,0x20,0x24,0x20,0x20,0x20,0x26,0x10,0x2b,0x20,0x30,0x10,0x2b,0x60,/*4*/0x20,0x20,0x20,0x10,0x20,0x10,0x20,0x20,0x20,0x20,0x20,0x20,0x1c,0x20,0x20,0x20,0x24,0x20,0x26,0x20,0x1c,0x20,0x19,0x20,0x18,0x10,0x19,0x10,0x20,0x30,0x01,0x20,0x20,0x10,0x20,0x10,0x1c,0x20,0x30,0x20,0x30,0x20,0x2b,0x20,0x26,0x20,0x20,0x20,0x01,0x20,0x20,0x20,0x24,0x20,0x20,0x20,0x26,0x10,0x2b,0x20,0x30,0x10,0x2b,0x60,//11767112377550x30,0x40,0x18,0x20,0x19,0x20,0x1c,0x20,0x19,0x10,0x18,0x10,0x18,0x20,0x2b,0x20,0x13,0x20,0x19,0x20,0x19,0x20,0x20,0x10,0x20,0x10,//632211170x1c,0x20,0x13,0x10,0x15,0x10,0x15,0x20,0x18,0x20,0x18,0x40,0x18,0x20,0x19,0x20,//67112377550x1c,0x20,0x19,0x10,0x18,0x10,0x18,0x20,0x15,0x20,0x13,0x20,0x19,0x20,0x19,0x20,0x20,0x10,0x20,0x10, //6322110x1c,0x20,0x13,0x10,0x15,0x10,0x15,0x20,0x18,0x20,0x18,0x60,//335350x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x60,//1155555 5777550x18,0x10,0x18,0x10,0x10,0x20,0x10,0x10,0x10,0x10,0x19,0x20,0x20,0x10,0x20,0x10,//555565111120x10,0x20,0x10,0x10,0x10,0x10,0x10,0x20,0x0e,0x20,0x10,0x20,0x18,0x10,0x18,0x10,0x18,0x20,0x18,0x10, 0x15,0x10, //32443324430x13,0x20,0x15,0x10,0x12,0x10,0x12,0x20,0x13,0x20,0x13,0x20,0x15,0x10,0x12,0x10,0x12,0x20,0x13,0x20, //324430x13,0x20,0x15,0x10,0x12,0x10,0x12,0x20,0x13,0x20,//55110x10,0x40,0x10,0x20,0x18,0x10,0x18,0x10,//555555777550x10,0x20,0x10,0x10,0x10,0x10,0x10,0x20,0x10,0x20,0x10,0x20,0x19,0x10,0x19,0x10,0x19,0x20,0x20,0x10, 0x20,0x10, //555565111120x10,0x20,0x10,0x10,0x10,0x10,0x10,0x20,0x0e,0x20,0x10,0x20,0x18,0x10,0x18,0x10,0x18,0x20,0x18,0x10, 0x15,0x10, //32443321710x13,0x20,0x15,0x10,0x12,0x10,0x12,0x20,0x13,0x20,0x13,0x20,0x15,0x10,0x18,0x10,0x18,0x20,0x19,0x10, 0x18,0x60, 0x01,0x40,0x01,0x40,//结尾//3217121334233420x13,0x20,0x15,0x20,0x18,0x30,0x19,0x10,0x18,0x10,0x15,0x 10,0x18,0x40,0x13,0x40,0x13,0x40,0x12,0x40,0x15,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x60,0x00};/************************************************************** *******//*******************第二首音乐机器猫**************************/unsigned char code music_tab_2[]={0x40,0x20,0x39,0x10,0x30,0x20,0x26, 0x10,0x1c, 0x20,0x26, 0x20,0x20, 0x40,0x20,0x20,0x1c,0x10,0x20, 0x20,0x26, 0x10,0x24, 0x20,0x26, 0x10,0x2b ,0x40,0x39, 0x20,0x2b, 0x10,0x2b ,0x20,0x24,0x10,0x19 ,0x20,0x19 ,0x10,0x1c ,0x20, 0x20,0x10,0x24,0x40,0x24, 0x20,0x26, 0x20,0x39, 0x40,0x33,0x40,0x30,0x40,0x2b ,0x40,0x40, 0x20,0x39 ,0x10,0x30, 0x20,0x26, 0x10,0x1c, 0x20,0x26 ,0x20,0x20 ,0x40,0x20, 0x20,0x1c, 0x10,0x20,0x20,0x26, 0x10,0x24,0x20,0x26, 0x10,0x2b, 0x40,0x39, 0x20,0x2b, 0x10,0x2b,0x20,0x24, 0x10,0x19 ,0x20,0x19, 0x10,0x1c ,0x20,0x20, 0x10,0x24, 0x40,0x24, 0x20,0x26, 0x20,0x33,0x40,0x2b,0x40,0x30, 0x40,0x1c, 0x40,0x1c, 0x20,0x20, 0x20,0x24, 0x20,0x20, 0x10,0x1c, 0x10,0x20, 0x40,0x2b, 0x20,0x26, 0x10,0x24 ,0x20,0x2b, 0x10,0x20, 0x40,0x1c ,0x40,0x20 ,0x40,0x24, 0x40,0x2b, 0x40,0x19, 0x20,0x1c, 0x10,0x20, 0x20,0x1c, 0x10,0x20, 0x20,0x24, 0x20,0x20 ,0x20,0x1c, 0x20,0x26, 0x40,0x2b, 0x20,0x30 ,0x40,0xff};/************************************************************** **************** //*******************以下为主函数部分**************************/void main(void){unsigned char p,m; //m为频率常数变量unsigned char i=0;TMOD=0x11; //设置定时器模式都为模式1IE=0x8a; //中断使能TH1=0xd8;TL1=0xef;P2=0xa0;P3=0x0f;I2CCON=0xE8;SetTime(a); //设置时间SwitchRTC(1);LCDInitialize(); //液晶初始化while(1){P1=0xf0;P2=0xbf;lie0=0; //扫描第一列以下以此类推temp=P1;temp=temp & 0x0f;if (temp!=0x0f){delay1s(); //去键盘抖动temp=P1;temp=temp & 0x0f;if(temp!=0x0f){temp=P1;temp=temp & 0x0f;switch (temp){case 0x0e:key=0;break;case 0x0d:key=4;break;case 0x0b:key=8;break;case 0x07:key=12;break;}P0=table[key]; STH0=tab[key]/256; STL0=tab[key]%256; TR0=1;temp=temp&0x0f; while(temp!=0x0f) {temp=P1;temp=temp&0x0f; }TR0=0;}}P1=0xf0;P2=0xbf;lie1=0;temp=P1;temp=temp & 0x0f; if (temp!=0x0f) {delay1s();temp=P1;temp=temp & 0x0f; if (temp!=0x0f) {temp=P1;temp=temp & 0x0f; switch(temp){case 0x0e:key=1;break;case 0x0d:key=5;break;case 0x0b:key=9;break;case 0x07:key=13;break;}P0=table[key]; STH0=tab[key]/256; STL0=tab[key]%256; TR0=1;temp=temp&0x0f; while(temp!=0x0f) {temp=P1;temp=temp&0x0f; }TR0=0;}}P1=0xf0;P2=0xbf;lie2=0;temp=P1;temp=temp & 0x0f; if (temp!=0x0f) {delay1s();temp=P1;temp=temp & 0x0f; if (temp!=0x0f) {temp=P1;temp=temp & 0x0f; switch(temp){case 0x0e:key=2;break;case 0x0d:key=6;break;case 0x0b:key=10;break;case 0x07:key=14;break;}P0=table[key];}P1=0xf0;P2=0xbf;lie3=0;temp=P1;temp=temp & 0x0f; if (temp!=0x0f) {delay1s();temp=P1;temp=temp & 0x0f; if (temp!=0x0f) {temp=P1;temp=temp & 0x0f; switch(temp){case 0x0e:key=3;break;case 0x0d:key=7;break;case 0x0b:key=11;break;case 0x07:key=15;break;P0=table[key];}}switch(key){case 0,4,8,12,1,5,9,13,8,7,10,11,15:break;case 2:{play_1:{a_1: p=music_tab_1[i];if(p==0x00) { i=0, delayms(1000); goto play_1;} //如果碰到结束符,延时1秒,回到开始再来一遍else if(p==0xff) { i=i+1;delayms(100),TR1=0; goto a_1;} //若碰到休止符,延时100ms,继续取下一音符else {m=music_tab_1[i++], n=music_tab_1[i++];} //取频率常数和节拍常数TR1=1;//开定时器1while(n!=0) PWM1=~PWM1,delay(m); //等待节拍完成, 通过P1口输出音频TR1=0;//关定时器1}break;}case 6:{play_2:{a_2: p=music_tab_2[i];if(p==0x00) { i=0, delayms(1000); goto play_2;} //如果碰到结束符,延时1秒,回到开始再来一遍else if(p==0xff) { i=i+1;delayms(100),TR1=0; goto a_2;} //若碰到休止符,延时100ms,继续取下一音符else {m=music_tab_2[i++], n=music_tab_2[i++];} //取频率常数和节拍常数TR1=1; //开定时器1while(n!=0) PWM1=~PWM1,delay(m); //等待节拍完成, 通过P1口输出音频TR1=0; //关定时器1}break;}case 3:{jishi=1; break;}default:break;}if(jishi==1){ReadTime(b); //读取此刻时间LCDPrintNumber(0,1,2,b[0]);//LCDPrintString(3,1,1,"-");LCDPrintNumber(4,1,2,b[1]);//LCDPrintString(6,1,1,":");LCDPrintNumber(7,1,2,b[2]);//LCDPrintString(9,1,1," ");LCDPrintNumber(10,1,2,b[4]);//LCDPrintString(12,1,,1," ");LCDPrintNumber(13,1,2,b[5]);//LCDPrintString(15,1," ");LCDPrintString(0,0,"HuNan University!"); }}}。
基于单片机的电子琴设计资料电子琴是一种电子乐器,通过电子回路和单片机控制,可以模拟出多种乐器的声音。
下面是一个基于单片机的电子琴设计资料,包括硬件设计和软件编程。
硬件设计:1.材料准备:选择一个适当大小的键盘,通常有8个到16个键位,每个键位可以连接到一个按钮开关。
2.连接按钮开关:将按钮开关连接到单片机的GPIO引脚上,通过读取引脚状态来检测按键的按下与释放。
3.音频输出:将单片机的数字音频输出连接到扬声器上,以发出相应的声音。
4.电源供应:提供适当的电源电压和电流给单片机和其他电子元件使用。
软件编程:1.初始化:在程序开始时,初始化单片机的GPIO引脚以及其他必要的外设,设置合适的时钟频率和中断设置。
2.按键扫描:通过循环遍历GPIO引脚,检测按钮开关的状态。
当检测到按键按下时,记录下按键对应的音符。
3.声音发生器:根据按键记录的音符,生成相应的音频信号。
可以使用一组预设的音符频率和振幅值,或者使用数学公式生成声音波形。
4.声音输出:将生成的音频信号发送到数字音频输出引脚,输出到扬声器上。
5.多音同步:为了更好的音乐体验,可以通过增加多音同步功能,使得按下多个按键时可以同时发出多个音符。
设计注意事项:1.硬件连接:确保正确连接按钮开关、声音输出和电源供应等元件,避免短路或其他电路问题。
2.音频信号处理:可以通过数字信号处理(DSP)算法对音频信号进行增强、滤波等处理,提高音质和音效。
3.功耗优化:在编程时,可以考虑使用低功耗模式以延长电子琴的电池寿命。
4.隔音材质:适当在琴身上加入隔音材质,减少按键和扬声器震动传递到外部的噪音。
总结:基于单片机的电子琴设计包括硬件连接和软件编程两个方面,硬件连接主要涉及键盘、按钮开关、扬声器和电源供应等元件的连接,软件编程则负责按键扫描、音频发生和音频输出等功能。
在设计过程中需注意硬件连接的正确性和优化声音效果,使得电子琴能够发出优美的音乐。
;******************************************************* ; 简易电子琴实验说明
;实验目的: 1.掌握蜂鸣器的使用
; 2.掌握蜂鸣器的不同发音的方法
;实验内容: 1.通过单片机,令1-7号键由低到高发出1-7的音阶K1 BIT ;按键1
K2 BIT ;按键2
K3 BIT ;按键3
K4 BIT ;按键4
K5 BIT ;按键5
K6 BIT ;按键6
K7 BIT ;按键7
Buzzer BIT ;蜂鸣器
M1 EQU 17
M2 EQU 16
M3 EQU 15
M4 EQU 14
M5 EQU 13
M6 EQU 12
M7 EQU 11
ORG 0000H
LJMP START
ORG 0100H
START: MOV SP,#60H
MAIN: MOV P1,#0FFH ;P1口初始化
LCALL Demo ;播放一段演示音乐
MAIN_1: JB K1,MAIN_2 ;判断1号键是否按下,否则检测2号键LCALL Sound1 ;发音子程序
MAIN_2: JB K2,MAIN_3 ;判断2号键是否按下,否则检测3号键LCALL Sound2 ;发音子程序
MAIN_3: JB K3,MAIN_4 ;判断2号键是否按下,否则检测4号键LCALL Sound3 ;发音子程序
MAIN_4: JB K4,MAIN_5 ;判断4号键是否按下,否则检测5号键LCALL Sound4 ;发音子程序
MAIN_5: JB K5,MAIN_6 ;判断5号键是否按下,否则检测6号键LCALL Sound5 ;发音子程序
MAIN_6: JB K6,MAIN_7 ;判断6号键是否按下,否则检测7号键LCALL Sound6 ;发音子程序
MAIN_7: JB K7,MAIN_73 ;判断7号键是否按下,否则跳回检测1号键LCALL Sound7 ;发音子程序
MAIN_73: SJMP MAIN_1 ;返回从1号键开始扫描
;播放演示音乐
Demo: MOV DPTR,#Music
Demo_1: CLR A
MOVC A,@A+DPTR
INC DPTR
JZ Demo_Ret
LCALL SoundMCU ;放音子程序
JMP Demo_1
Demo_Ret: RET
;乐曲:),0-结果标志
Music: DB M1,M2,M3,M4,M5,M6,M7,M7,M7,M6,M5,M4,M3,M2,M1 DB M1,M2,M1,M2,M3,M2,M3,M4,M3,M4,M5,M4,M5,M6,M5
DB M6,M7,M6,M7,M7,M6,M6,M6,0
;程序控制发音
SoundMCU: MOV R5,#40H ;控制放音时间
MOV R7,A
ACALL Time
MOV R6,A
SoundMCU_0: PUSH 06H
SoundMCU_1: ACALL MusicalScale
DJNZ R6,SoundMCU_1
POP 06H
DJNZ R5,SoundMCU_0
RET
;计算时长
Time: MOV B,#0FFH
XCH A,B
DIV AB
XCH A,B
CJNE A,#8,$+3
JC Time_1
INC B
Time_1: XCH A,B
RET
MusicalScale: MOV A,R7
MusicalScale1: CLR Buzzer ;1号键发音
LCALL Delay ;延时
DJNZ ACC,MusicalScale1
MOV A,R7
MusicalScale2: SETB Buzzer
LCALL Delay ;延时
DJNZ ACC,MusicalScale2
RET
;1号键发音
Sound1: MOV R7,#M1 ;发音频率,越大频率越低Sound1_1: ACALL MusicalScale
JNB K1,Sound1_1
RET
;2号键发音
Sound2: MOV R7,#M2 ;发音频率,越大频率越低Sound2_1: ACALL MusicalScale
JNB K2,Sound2_1
RET
;3号键发音
Sound3: MOV R7,#M3
Sound3_1: ACALL MusicalScale
JNB K3,Sound3_1
RET
;4号键发音
Sound4: MOV R7,#M4
Sound4_1: ACALL MusicalScale
JNB K4,Sound4_1
RET
;5号键发音
Sound5: MOV R7,#M5
Sound5_1: ACALL MusicalScale
JNB K5,Sound5_1
RET
;6号键发音
Sound6: MOV R7,#M6
Sound6_1: ACALL MusicalScale
JNB K6,Sound6_1
RET
;7号键发音
Sound7: MOV R7,#M7 ;发音频率,越大频率越低Sound7_1: ACALL MusicalScale
JNB K7,Sound7_1
RET
;延时
Delay: NOP
RET
END。