单片机课程设计简易电子琴设计.docx
《单片机课程设计简易电子琴设计.docx》由会员分享,可在线阅读,更多相关《单片机课程设计简易电子琴设计.docx(19页珍藏版)》请在冰豆网上搜索。
![单片机课程设计简易电子琴设计.docx](https://file1.bdocx.com/fileroot1/2022-12/12/e2958a31-7ea9-431a-8aaa-f50c7ff9b58f/e2958a31-7ea9-431a-8aaa-f50c7ff9b58f1.gif)
单片机课程设计简易电子琴设计
单片机课程设计--简易电子琴设计
郑州轻工业学院
计算机与通信工程学院
单片机与接口技术课程设计总结报告
设计题目:
简易电子琴设计
学生姓名:
毛二松
系别:
计算机与通信工程学院
专业:
电子信息科学与技术
班级:
09-01
学号:
540907020127
指导教师:
韩雪琴杨永双
2011年12月26日
简易电子琴设计
电子琴概述
这次设计的电子琴与市场上的电子琴相比虽然音色逊了一点,但是其物美价廉,功能强大,携带方便,深受大家喜欢。
此次课程设计的电子琴是有4*4矩阵键盘来实现发音,其中4个键是功能键,剩下的12键实现真正的发音。
此外在电子琴的功能上又加上了音乐播放功能、选择歌曲、暂停以及录音回放功能,使电子琴变得更强大。
让电子琴不再是简单的弹出音调简单的电子琴,而是一个功能齐全的电子琴。
本设计功能
1.通过矩阵键盘能够弹出美妙的音乐。
2.通过功能切换,能够切换到音乐播放器功能
3.能够把弹出的音乐录制下来,并且还能够回放出来。
本设计的仿真图
引脚描述:
矩阵键盘接的是P3口,显示部分的段控制口接的是P0口,位控制口接的是P2.0、P2.1、P2.2、P2.4、P2.5,蜂鸣器接的P2.3口。
各种功能键如图所示。
设计的流程图
我负责的模块
主程序:
也就是本程序的整体构造、功能构造。
主程序程序:
voidmain()
{
init();//初始化
while
(1)
{
keyscan();//调用键盘扫描
display();//显示
if(key_function==1)//如果选择音乐播放
{
switch(count)
{
case1:
play(music1,music1_L);break;//播放第一首
case2:
play(music2,music2_L);break;//播放第二首
case3:
play(music3,music3_L);break;//播放第三首
}
}
else//否则选择为电子琴
{
if(key_record==2)//判断是否回放
replay(record,record_L);
}
}
}
录音功能。
录音程序和键盘扫描再一个模块中。
功能描述:
它能够把你所弹的音调、按下键盘的时间即音长以及键与键之间的时间给记录下来,它完全模拟了现实中电子琴的功能,功能之强大。
时间的记录是利用定时器1实现的。
定时器0是产生一定频率的方波,使蜂鸣器发出不同的音调。
本功能程序:
voidkeyscan()//键盘扫描:
线反转法
{
ucharh,l;//h:
行l:
列
if(key_record==1&&flag==0)//记录键与键之间的时间
{
TH1=(65536-5000)/256;
TL1=(65536-5000)%256;
TR1=1;
flag=1;
}
P3=0xf0;//列全置低电平,行全置高电平
h=P3&0xf0;
while(h!
=0xf0)//若有键按下则行会出现低电平
{
delay(10);//按键去抖
P3=0xf0;//列全置低电平,行全置高电平
h=P3&0xf0;
while(h!
=0xf0)
{
if(key_record==1)//如果有按键按下,则把按键前的时间记录下来
{
TR1=0;//关闭计时
record_L[b]=a;//把按键前的时间记录下来
a=0;//时间次数清零
b++;//下标加一
}
h=P3&0xf0;//读入行值
P3=0x0f;//电平反转
l=P3&0x0f;//读入列值
k=h+l;
switch(k)
{
case0xee:
temp=0;key_function++;
if(key_function==2)
key_function=0;
break;//功能选择按钮
case0xed:
temp=0;count++;next_flag=1;
if(count==4)
count=1;
break;//选曲按钮
case0xeb:
temp=0;key_record++;
if(key_record==3)
key_record=0;
break;//录音、回放、返回
case0xe7:
temp=0;pause++;
if(pause==2)
pause=0;
break;//
case0xde:
temp=6;break;//6
case0xdd:
temp=7;break;//7
case0xdb:
temp=11;break;//11
case0xd7:
temp=12;break;//12
case0xbe:
temp=13;break;//13
case0xbd:
temp=14;break;//14
case0xbb:
temp=15;break;//15
case0xb7:
temp=16;break;//16
case0x7e:
temp=17;break;//17
case0x7d:
temp=21;break;//21
case0x7b:
temp=22;break;//22
case0x77:
temp=23;break;//23
}
display();//显示
if(key_record==1&&temp!
=0)//录音时,如果有按键按下且不是功能键
{
record[j]=8;//先把按键前的初始值记下
record[j+1]=temp;//再把此按键的值记下
j=j+2;//下标值加2
TH1=(65536-5000)/256;//装初始值
TL1=(65536-5000)%256;
TR1=1;//启动定时
}
if(temp!
=0)//如果不是功能按键则发出声音
{
TH0=table[temp]/256;
TL0=table[temp]%256;
TR0=1;
}
while(h!
=0xf0)//检查按键是否弹起
{
P3=0xf0;//列全置低电平,行全置高电平
h=P3&0xf0;
}
TR0=0;//弹起后关闭定时
if(key_record==1&&temp!
=0)//录音时,如果有按键按下且不是功能键
{
TR1=0;//关闭计时
record_L[b]=a;//把按键的时间记下
a=0;//时间次数清零
flag=0;
b++;
}
}
}
BUZZER=1;//把蜂鸣器关闭
}
回放功能:
就是把录的音给回放出来
源程序:
voidreplay(uint*Song,uint*Song_L)//回放功能
{
uinti;
for(i=0;i{
temp=Song[i];//把音谱频率赋给n
m=Song_L[i];//把音长赋给m
if(temp==8)//如果此时播放的是键与键之间的空隙时间
{
TR0=0;//定时关闭即不发出声音
BUZZER=1;//关闭蜂鸣器
temp=Song[i-1];
}
else//否则
{
TH0=table[temp]/256;
TL0=table[temp]%256;
TR0=1;
}
delay1(m/2);
}
j=0;a=0;b=0;//把录音清除
TR0=0;//关闭定时
BUZZER=1;//把蜂鸣器关闭
}
实验总结
经过这次课程设计,我真正学会了如何使用单片机,懂得了仿真和用真实的单片机板子实现本功能的差别,仿真毕竟不是真实的现象,有时候仿真能实现,但是把程序下载到板子上后现象可能不是你所想的那样。
做这个设计给我最大的感触就是当一个模块实现了,但是当把各个模块结合到一块后就会变得有点复杂。
当然刚开始做这个程序时,要从实现简单的功能入手,然后一点点把功能做大做强。
在做这个设计时我也遇到了很多问题:
比如,做录音、回放功能的时候,记录键与键之间的时间的设置时,记录的时间很短,原因就是当没有键按下的时候,程序会一直进行键盘扫描,而且每次都会重新进行定时初始值设置,我们希望的现象是定时初始值设置一次就够了,如果每次都重新设置定时器初始值,那么记录的时间就会不准确。
所以这时就要设置一个标志,开始时标志变量为0,如果是第一次设置,则设置完后就令这个标志变量置1,下次循环的时候,程序就不会进行重新设置定时初始值了。
所以这个标志位再程序设计的时候显得很重要。
1和0是二进制数,有时它不仅仅是一个数值,它也可以是代表一件事,1代表这件事做了,0则相反。
标志变量就像是一个站岗放哨的人,只有这个人同意了,你才能进入。
所以当我做这个课程设计所遇到的问题以及我如何解决的过程,我感觉这个过程是如此的美妙,我丝毫感觉不到这是一件痛苦的事情,反而觉得这是一件让人上瘾的趣事。
每当遇到的问题解决了,我都把他们当做是一笔财富。
我觉得我们学习的不仅是单片机本门课的知识,而且是学习获得知识的方法。
授之鱼不如授之渔,这句话也体现了方法的重要性。
7、参考文献
[1]张毅刚彭喜来.《单片机原理与应用设计》[M].电子工业出版社,2011
[2]张毅刚.《MCS-51单片机应用设计》(第二版).哈尔滨大学出版社,2002
8、附录
本课程设计的源程序:
一个.c文件,两个.h文件
主程序源程序:
#include
#include
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
voidinit()//初始化程序
{
TMOD=0X11;//定时器0、1都设为工作方式1
EA=1;//总中断打开
ET0=1;//允许T0定时
ET1=1;//允许T1定时
}
voidmain()
{
init();//初始化
while
(1)
{
keyscan();//调用键盘扫描
display();//显示
if(key_function==1)//如果选择音乐播放
{
switch(count)
{
case1:
play(music1,music1_L);break;
case2:
play(music2,music2_L);break;
case3:
play(music3,music3_L);break;
}
}
else//否则选择为电子琴
{
if(key_record==2)//判断是否回放
replay(record,record_L);
}
}
}
voidT0_time()interrupt1//用于音乐播放器定时产生音调
{
TH0=table[temp]/256;
TL0=table[temp]%256;
BUZZER=!
BUZZER;
}
voidtimer1()interrupt3//用于电子琴录音计时
{
TH1=(65536-10000)/256;
TL1=(65536-10000)%256;
a++;
}
keyscan.h—键盘扫描源程序(录音、显示程序也在里面)
#defineucharunsignedchar
#defineuintunsignedint
uintrecord_replay();//录音/回放
voiddisplay();
sbitBUZZER=P2^3;
//sbitkey3=P2^4;
sbitw1=P2^0;
sbitw2=P2^1;
sbitw3=P2^2;
sbitw5=P2^4;
sbitw6=P2^5;
sbitdula=P2^6;
sbitwela=P2^7;
ucharj,a,b,flag,count=1;
ucharkey_function,key_record,next_flag;
uintrecord[20],record_L[20];//存储回放的音调
ucharn,m,k,temp,pause;
ucharcodeled[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//0-f
uintcodetable[]={0,63628,63835,64021,64103,64260,64400,64524,0,0,
0,64580,64684,64777,64820,64898,64968,65030,0,0,
0,65058,65110,65157,65178,65217,65252,65283,0,0};//每个音符的简谱码(T值)
voiddelay1(uintj)
{
while(j--)
{
uintx;
for(x=125;x>0;x--);
display();
}
}
voiddelay(uinta)//1ms延时
{
uintx;
while(a--)
{
for(x=0;x<125;x++);
}
}
voiddisplay()
{
dula=1;
P0=led[key_function];
dula=0;
wela=1;
P0=0xfe;//数码管第一位亮
wela=0;
delay
(2);
dula=1;
P0=led[count];
dula=0;
wela=1;
P0=0xfd;//数码管第二位亮
delay
(2);
dula=1;
P0=led[key_record];
dula=0;
wela=1;
P0=0xfb;//数码管第三位亮
wela=0;
delay
(2);
dula=1;
P0=led[temp/10];
dula=0;
wela=0;
P0=0xef;//数码管第四位亮
wela=1;
delay
(2);
dula=1;
P0=led[temp%10];
dula=0;
wela=0;
P0=0xdf;//数码管第五位亮
wela=1;
delay
(2);
}
voidkeyscan()//键盘扫描:
线反转法
{
ucharh,l;//h:
行l:
列
if(key_record==1&&flag==0)//记录键与键之间的时间
{
TH1=(65536-5000)/256;
TL1=(65536-5000)%256;
TR1=1;
flag=1;
}
P3=0xf0;//列全置低电平,行全置高电平
h=P3&0xf0;
while(h!
=0xf0)//若有键按下则行会出现低电平
{
delay(10);//按键去抖
P3=0xf0;//列全置低电平,行全置高电平
h=P3&0xf0;
while(h!
=0xf0)
{
if(key_record==1)//如果有按键按下,则把按键前的时间记录下来
{
TR1=0;//关闭计时
record_L[b]=a;//把按键前的时间记录下来
a=0;//时间次数清零
b++;//下标加一
}
h=P3&0xf0;//读入行值
P3=0x0f;//电平反转
l=P3&0x0f;//读入列值
k=h+l;
switch(k)
{
case0xee:
temp=0;key_function++;
if(key_function==2)
key_function=0;
break;//功能选择按钮
case0xed:
temp=0;count++;next_flag=1;
if(count==4)
count=1;
break;//选曲按钮
case0xeb:
temp=0;key_record++;
if(key_record==3)
key_record=0;
break;//录音、回放、返回
case0xe7:
temp=0;pause++;
if(pause==2)
pause=0;
break;//
case0xde:
temp=6;break;//6
case0xdd:
temp=7;break;//7
case0xdb:
temp=11;break;//11
case0xd7:
temp=12;break;//12
case0xbe:
temp=13;break;//13
case0xbd:
temp=14;break;//14
case0xbb:
temp=15;break;//15
case0xb7:
temp=16;break;//16
case0x7e:
temp=17;break;//17
case0x7d:
temp=21;break;//21
case0x7b:
temp=22;break;//22
case0x77:
temp=23;break;//23
}
display();//显示
if(key_record==1&&temp!
=0)//录音时,如果有按键按下且不是功能键
{
record[j]=8;//先把按键前的初始值记下
record[j+1]=temp;//再把此按键的值记下
j=j+2;//下标值加2
TH1=(65536-5000)/256;//装初始值
TL1=(65536-5000)%256;
TR1=1;//启动定时
}
if(temp!
=0)//如果不是功能按键则发出声音
{
TH0=table[temp]/256;
TL0=table[temp]%256;
TR0=1;
}
while(h!
=0xf0)//检查按键是否弹起
{
P3=0xf0;//列全置低电平,行全置高电平
h=P3&0xf0;
}
TR0=0;//弹起后关闭定时
if(key_record==1&&temp!
=0)//录音时,如果有按键按下且不是功能键
{
TR1=0;//关闭计时
record_L[b]=a;//把按键的时间记下
a=0;//时间次数清零
flag=0;
b++;
}
}
}
BUZZER=1;//把蜂鸣器关闭
}
play_music.h—音乐播放源程序(回放功能也在里面)
#defineuintunsignedint
#defineucharunsignedchar
voidplay(uint*Sound,uint*Sound_L);//音乐播放
//第一首音乐:
一分钱
uintcodemusic1[]={15,21,16,21,15,13,15,12,13,15,8,
13,15,16,21,15,16,15,13,15,11,13,12,8,
13,12,11,12,13,16,15,13,15,16,8,
15,21,16,15,13,15,12,15,12,13,12,11,
0x0};//音调
uintcodemusic1_L[]={4,4,2,2,4,2,2,2,2,4,4,
2,2,2,2,2,2,2,2,2,4,2,4,4,
2,2,2,2,4,4,2,2,2,2,4,
4,2,2,2,2,2,2,4,2,2,2,2,4,4,
4};//音长
//第二首音乐:
小兔子乖乖
uintcodemusic2[]={15,21,16,15,15,13,15,16,21,15,15,16,15,13,12,12,13,15,13,12,11,
16,15,16,15,13,16,15,12,15,13,12,11,6,11,12,13,11,
0x0};
uintcodemusic2_L[]={4,2,2,4,4,2,2,2,2,4,4,4,2,2,4,4,4,2,2,4,4,
2,2,2,2,2,2,4,2,2,2,2,4,4,2,2,2,2,4,4,
4};
//第三首音乐:
祝你生日快乐
uintcodemusic3[]={15,15,16,15,21,17,
15,15,16,15,22,21,
15,15,25,23,21,17,16,
24,24,23,21,22,21,
0x0};
uintcodemusic3_L[]={2,2,4,4,4,8,
2,2,4,4,4,8,
2,2,4,4,4,4,8,
2,2,4,4,4,4,2};
voidreplay(uint*Song,uint*Song_L)//回放功能
{
uinti;
TR1=0;
for(i=0;i{
temp=Song[i];//把音谱频率赋给n
m=Song_L[i];//把音长赋给m
if(temp==8)//如果此时播放的是键与键之间的空隙时间
{
TR0=0;//定时关闭即不发出声音
BUZZER=1;//关闭蜂鸣器
temp=Song[i-1];