键盘电子乐器
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
基于AT89S51键盘电子乐器的设计专业班级:
设计者:
指导老师:
设计时间:
一、设计目的:键盘电子乐器
二、功能要求:
利用单片机AT89C51端口作为键盘接口,设计一个具有2个八度音阶的键盘乐器,音阶键不少于16个,采用扫描方式管理键盘,音域
范围自行定义。也可播放1-3首音乐三、方案论证:
系统框图设计如图所示:
四、系统硬件设计:
系统硬件设计如图2所示:
图2 系统硬件设计
五、软件设计:
(1)弹奏程序流程图如图3所示:
图3流程图(2)播放歌曲程序流程图如图4
图4 流程图(2)程序:
/***** 文件名:
键盘电子乐器.c*****/
#include
#include
#define uchar unsigned char
#define uint unsigned int
uchar Count;
void Play_Song(uchar i);
sbit ge=P3^0; //歌曲开关按键
sbit Speak =P3^7; //扬声器控制脚
uint FreqTemp;
unsigned int code Freqtab[] = { //定时半周期的初始值64021,64103,64260,64400, //低音3 4 5 6
64524,64580,64684,64777, //低音7,中音1 2 3
64820,64898,64968,65030, //中音4 5 6 7
65058,65110,65157,65178 //高音1 2 3 4
};
//关于半周期的初始值与频率的关系,可见:
/************************************************************* * 函数功能: 用扫描法读P1 外接4×4 键盘
* 函数返回: 按下键:返回0~15、如无键按下:返回16
**************************************************************/ 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
}
/************************************************************** * 函数功能:按键数码管显示
* 输入: k (键盘数值)
***************************************************************/ void Display(uchar k) //数码管显示
{ if(k<8)
P2 =0xC7 ;
else
P2=0x89 ;
}
void mmkey(void)
{ uchar Key_Value = 16, Key_Temp1, Key_Temp2;//读出的键值TMOD = 0x01; //T0定时方式1
ET1 = 1; //允许T1中断
EX1 = 1; //允许外部中断INT1中断允许
EA = 1; //开总中断
while(1)
{ if(ge==0)
Play_Song(0); //Play_Song(0)为祝你平安Play_Song(1)为路边的野花你不要采TR1 = 0; //暂不发音
Key_Temp1 = Keyscan(); //读入按键
if(Key_Temp1 != 16) //有键按下
{ Display(Key_Value); //显示键值、延时消抖
Key_Temp2 = Keyscan(); //再读一次
if (Key_Temp1 == Key_Temp2)//两次相等
{ Key_Value = Key_Temp1; //就确认下来
FreqTemp = Freqtab[Key_Value]; //根据键值,取出定时半周期的初始值
Display(Key_Value); //显示
TR1 = 1; //启动定时器,发音
while (Keyscan() < 16); //等待释放
Speak = 0; //停止发音
}
}
}
}
void T1_INT(void) interrupt 3
{ TL1 = FreqTemp; //载入定时半周期的初始值
TH1 = FreqTemp >> 8;
Speak = ~Speak; //发音
}
/*以下数组是音符编码*/
unsigned char code SONG[] ={ //祝你平安
0x26,0x20,0x20,0x20,0x20,0x20,0x26,0x10,0x20,0x10,0x20,0x80,0x26,0x20,0x30,0x20,
0x30,0x20,0x39,0x10,0x30,0x10,0x30,0x80,0x26,0x20,0x20,0x20,0x20,0x20,0x1c,0x20,
0x20,0x80,0x2b,0x20,0x26,0x20,0x20,0x20,0x2b,0x10,0x26,0x10,0x2b,0x80,0x26,0x20,
0x30,0x20,0x30,0x20,0x39,0x10,0x26,0x10,0x26,0x60,0x40,0x10,0x39,0x10,0x26,0x20,
0x30,0x20,0x30,0x20,0x39,0x10,0x26,0x10,0x26,0x80,0x26,0x20,0x2b,0x10,0x2b,0x10,
0x2b,0x20,0x30,0x10,0x39,0x10,0x26,0x10,0x2b,0x10,0x2b,0x20,0x2b,0x40,0x40,0x20,
0x20,0x10,0x20,0x10,0x2b,0x10,0x26,0x30,0x30,0x80,0x18,0x20,0x18,0x20,0x26,0x20,
0x20,0x20,0x20,0x40,0x26,0x20,0x2b,0x20,0x30,0x20,0x30,0x20,0x1c,0x20,0x20,0x20,
0x20,0x80,0x1c,0x20,0x1c,0x20,0x1c,0x20,0x30,0x20,0x30,0x60,0x39,0x10,0x30,0x10,
0x20,0x20,0x2b,0x10,0x26,0x10,0x2b,0x10,0x26,0x10,0x26,0x10,0x2b,0x10,0x2b,0x80,
0x18,0x20,0x18,0x20,0x26,0x20,0x20,0x20,0x20,0x60,0x26,0x10,0x2b,0x20,0x30,0x20,
0x30,0x20,0x1c,0x20,0x20,0x20,0x20,0x80,0x26,0x20,0x30,0x10,0x30,0x10,0x30,0x20,
0x39,0x20,0x26,0x10,0x2b,0x10,0x2b,0x20,0x2b,0x40,0x40,0x10,0x40,0x10,0x20,0x10,
0x20,0x10,0x2b,0x10,0x26,0x30,0x30,0x80,0x00,
//路边的野华不要采
0x20,0x40,0x1C,0x10,0x18,0x10,0x20,0x10,0x1C,0x10,0x18,0x40,0x1C,0x20,0x20,0x20,
0x1C,0x20,0x18,0x20,0x20,0x80,0xFF,0x20,0x30,0x1C,0x10,0x18,0x20,0x15,0x20,0x1C,
0x20,0x20,0x20,0x26,0x40,0x20,0x20,0x2B,0x20,0x26,0x20,0x20,0x20,0x30,0x80,0xFF,
0x20,0x20,0x1C,0x10,0x18,0x10,0x20,0x20,0x26,0x20,0x2B,0x20,0x30,0x20,0x2B,0x40,
0x20,0x20,0x1C,0x10,0x18,0x10,0x20,0x20,0x26,0x20,0x2B,0x20,0x30,0x20,0x2B,0x40,