51单片机实验,电子琴
实验是可播放音乐可演奏的电子琴。可分别播放内部存储的三首歌曲,或者通过按键弹奏音乐。屏幕在弹奏音乐时显示姓名学号,在播放音乐时显示歌曲名字。
原理图
实验代码
- #include<reg51.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- #define LCDPORT P0
- sbit BEEP = P3 ^ 7;//把p3接口用BEEP表示,下同
- sbit BEEP1 = P3 ^ 0; //???
- sbit BEEP2 = P3 ^ 4;
- sbit LCDE = P2 ^ 2;
- sbit LCDRW = P2 ^ 1;
- sbit LCDRS = P2 ^ 0;
- sbit BCD1= P2 ^ 5;
- sbit BCD2 = P2 ^ 6;
- sbit BCD3 = P2 ^ 7;
- sbit BCD4 = P2 ^ 8;
- uchar KeyNo; //???
- //???
- unsigned char code name[] = " zhaeng";//定义数组,名字
- unsigned char code num[] = " 211691";//定义数组,学号
- unsigned char code tab1[] = “PLAYING MUSIC IS”;//定义数组显示歌曲
- unsigned char code tab2[] = “TWO TIGER”;//歌曲名字,下同
- unsigned char code tab3[] = “THE TONE IS”;
- unsigned char code tab4[] = “TWO BUFFER”;
- uint code Tone_Delay_Table1[] =//定义音符延时表,用于按键播放音乐
- { 64021,64103,64260,64400,64524,64580,64684,64777,
- 64820,64898,64968,65030,65058,65110,65157,65178 };
- uint code Tone_Delay_Table[] =//定义音符延时表,用于播放音乐
- { 62018,62401,62491,62895,63184,63441,63506,
- 63773,63965,64137,64215,64360,64488,64603,
- 64654,64751,64836,64876,64948,65012,65067,65535 };
- uchar code Song1_Tone[] =//歌曲一的音调
- { 13,0,13,1,13,2,13,0,13,0,13,1,13,2,13,0,13,2,13,3,
- 13,4,13,13,13,2,13,3,13,4,13,13,13,4,5,4,3,2,13,0,
- 13,4,5,4,3,2,13,0,13,2,13,11,13,0,13,13,2,13,11,13,0,13,13,0xFF };
- uchar code Song1_Time[] =//歌曲一的时间,下同
- { 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,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,0xFF };
- uchar code Song2_Tone[] = {
- 13,0,0,4,4,5,5,4,13,3,3,2,2,1,1,0,13,4,4,3,3,2,2,1,13,4,4,3,3,2,2,1,0xFF };
- uchar code Song2_Time[] = {
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0xFF };
- uchar code Song3_Tone[] = {
- 13,2,2,3,4,4,3,2,1,0,0,1,2,2,1,1,13,2,2,3,4,4,3,2,1,0,0,1,2,1,13,0,0,13,1,1,2,0,1,3,2,0,1,3,2,1,0,1,12,13,0xFF };
- uchar code Song3_Time[] = {
- 3,3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0xFF };
- uchar Song_Index = 0, Tone_Index = 0;//音乐片段索引,音符索引
- uchar* Song_Tone_Pointer, * Song_Time_Pointer;//音符指针和延时指针
- uchar tool = 0;//工具人
- uchar* trans = &tool;//定义指针,用于匹配歌曲和屏幕显示
- uchar i = 0;
- void DelayMS(uint ms)//音乐播放的延时
- {
-
uchar t;
-
while (ms--) for (t = 0; t < 120; t++);
- }
- //*****************
- void Delay()//屏幕显示的延时
- {
-
uint uiCount;
-
for (uiCount = 0; uiCount < 250; uiCount++);
- }
- void WriteCMD(uchar Command)//屏幕显示部分已经讲过
- {
-
Delay();
-
LCDE = 1;
-
LCDRS = 0;
-
LCDRW = 0;
-
LCDPORT = Command;
-
Delay();
-
LCDE = 0;
- }
- void WriteData(uchar dat)
- {
-
Delay();
-
LCDE = 1;
-
LCDRS = 1;
-
LCDRW = 0;
-
LCDPORT = dat;
-
LCDE = 0;
- }
- void inicry()
- {
-
LCDRW = 0;
-
LCDE = 0;
-
WriteCMD(0x38);
-
WriteCMD(0x0f);
-
WriteCMD(0x07);
-
WriteCMD(0x01);
- }
- void mydelay(int x)
- {
-
int i, y;
-
for (i = x; i > 0; i--)
-
for (y = 255; y > 0; y--);
- }
- void Key_Press() interrupt 0//外部中断控制的音乐切换
- {
-
TR0 = 0;/*定时器开始和启动的标志,
-
任何时刻,当TR0/TR1为1时,T0/T1定时器计数;
-
当TR0/TR1为0时,T0 定时器停止计数。*/
-
Song_Index = (Song_Index + 1) % 3;//切换到下一个音乐,因为只有3首
-
switch (Song_Index)//通过switch case来选择音乐
-
{
-
case 0: Song_Tone_Pointer = Song1_Tone;
-
Song_Time_Pointer = Song1_Time;
-
*trans = 0;//屏幕与歌曲的匹配
-
break;
-
case 1: Song_Tone_Pointer = Song2_Tone;
-
Song_Time_Pointer = Song2_Time;
-
*trans = 1;
-
break;
-
case 2: Song_Tone_Pointer = Song3_Tone;
-
Song_Time_Pointer = Song3_Time;
-
*trans = 2;
-
break;
-
}
-
i = 0;//从另一个音乐第0个音符开始
-
TR0 = 1;//定时器开始。作用是让外部中断的优先级更高
- }
- //–通过T0定时器控制播放
- void Timer0_Play_Music() interrupt 1
- {
-
BEEP2 = 0xFF;//判断是模式1还是2
-
if (BEEP2 != 0XFF)
-
{
-
TH0 = Tone_Delay_Table[Tone_Index] / 256;
-
TL0 = Tone_Delay_Table[Tone_Index] % 256;
-
BEEP = ~BEEP;对应不同的播放器
-
}
-
else
-
{
-
TH0 = Tone_Delay_Table1[KeyNo] / 256;
-
TL0 = Tone_Delay_Table1[KeyNo] % 256;
-
BEEP1 = ~BEEP1;
-
}
- }
- //————————————————
- //键盘矩阵扫描
- //---------------------------------------------------------------------------------------------------
- void Keys_Scan()
- {
-
uchar Tmp, k;
-
//高四位置0,放入四行
-
P1 = 0x0F;//p18对应的最高位,p10对应的最低位
-
DelayMS(2);
-
//按键后,00001111变成0000xxxx。x中有1个0,3个1
-
//下面的异或操作,讲0变成1,将1变成0
-
Tmp = P1 ^ 0x0F;
-
//相同的变0,不同的变1
-
//判断按键发生在0-3的哪一列
-
switch (Tmp)
-
{
-
case 1:k = 0; break;
-
case 2:k = 1; break;
-
case 4:k = 2; break;
-
case 8:k = 3; break;
-
default:return; //没有按键按下
-
}
-
//低四位置0,放入四列
-
P1 = 0XF0;
-
DelayMS(2);
-
//按键后,11110000变成xxxx0000。x中有1个0,3个1
-
//下面的操作会将高四位移动到低四位,并将唯一的0变为1
-
Tmp = (P1 >> 4) ^ 0X0F;//>>:是整数位操作运算符中的右移运算符
-
//对0-3行分别赋初始值,0,4,8,12
-
switch (Tmp)
-
{
-
case 1:k += 0; break;
-
case 2:k += 4; break;
-
case 4:k += 8; break;
-
case 8:k += 12; break;
-
default:return;
-
}
-
KeyNo = k;//这个时候的k就是按键的名字
- }
- //---------------------------------------------------------------------------------------------------
- //---------------------------------------------------------------------------------------------------
- /*void Play_Tone() interrupt 1
- {
-
TH0 = Tone_Delay_Table1[KeyNo] / 256;
-
TL0 = Tone_Delay_Table1[KeyNo] % 256;
-
BEEP1 = ~BEEP1;
- }*/
- //-------------------------------------------------------------------------------
- void main()
- {
-
uchar y, x, z;
-
TMOD = 0x01;//定时器均工作在模式一(片内部的寄存器)
-
IP = 0x01;//INT0设为高优先级
-
IE = 0x83;//允许INT0和T0中断
-
TR0 = 0;//定时器停止
-
Song_Tone_Pointer = Song1_Tone;//给指针指向1
-
Song_Tone_Pointer = Song1_Time;//
-
inicry();//屏幕初始化
-
while (1)
-
{
-
BEEP2 = 0xFF;//选定模式1还是2
-
if (BEEP2 != 0XFF)//模式1,播放音乐,BEEP2按下了
-
{
-
BCD1 = 1; BCD2 = 0; BCD3 = 0; BCD4 = 0;
-
WriteCMD(0x80);/*这个是1602的程序bai,每行16个显示单元,
-
第一行地址du从0x80~0x80+16,第二行0xc0~0xc0+16*/
-
for (y = 0; y < 16; y++)
-
{
-
WriteData(tab1[y]);//写这首歌是啥这句话
-
mydelay(5);
-
}
-
//Tone_Index = Song_Tone_Pointer[i];//判断是第几个音符
-
if (tool == 0)//是第一首歌,进行的屏幕操作
-
{
-
WriteCMD(0x80 + 0x40);
-
for (z = 0; z < 9; z++)
-
{
-
WriteData(tab2[z]);
-
mydelay(5);
-
}
-
}
-
if (tool == 1)
-
{
-
WriteCMD(0x80 + 0x40);
-
for (z = 0; z < 10; z++)
-
{
-
WriteData(tab3[z]);
-
mydelay(5);
-
}
-
}
-
if (tool == 2)
-
{
-
WriteCMD(0x80 + 0x40);
-
for (z = 0; z < 10; z++)
-
{
-
WriteData(tab4[z]);
-
mydelay(5);
-
}
-
}
-
Tone_Index = Song_Tone_Pointer[i];//判断是第几个音符
-
if (Tone_Index == 0xFF)//到结束了,最后一个字符了
-
{
-
i = 0;//从第一个字符开始
-
DelayMS(2000);//每首歌播放完之后停顿一会
-
continue;//继续播放
-
}
-
TR0 = 1;//定时器工作
-
DelayMS(Song_Time_Pointer[Tone_Index] * 240);//延时,每个时间段乘以240
-
TR0 = 0;//定时器开始。通过T0来控制频率。延时的时间段就是定时器响的时间段
-
i++;//字符向后走
-
}
-
else//模式2
-
{
-
BCD1 = 0; BCD2 = 1; BCD3 = 0; BCD4 = 0;
-
P1 = 0XF0;//设定初值,判断是否扫描
-
/*p1端口接一组按键,如果按键中有一个或者多个按下时,即使P1被赋值,也会改变*/
-
if (P1 != 0XF0)//有按键按下,p1是不等于这个的
-
{
-
Keys_Scan();
-
TR0 = 1; // 启用定时器,根据KeyNo发音
-
}
-
else
-
{
-
TR0 = 0;//没有按键按下,停止发音
-
}
-
DelayMS(2);
-
WriteCMD(0x80);//下面是写名字和学号
-
for (y = 0; y < 13; y++)
-
{
-
WriteData(name[y]);
-
mydelay(10);
-
}
-
mydelay(5);
-
WriteCMD(0x80 + 0x40);
-
for (z = 0; z < 14; z++)
-
{
-
WriteData(num[z]);
-
mydelay(10);
-
}
-
mydelay(5);
-
for (x = 0; x < 19; x++)
-
{
-
WriteCMD(0x18);
-
mydelay(5);
-
}
-
mydelay(5);
-
}
-
}
- }