电路综合实验实验报告 基于Amage16 电子琴 北邮
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2013-2014学年小学期电路综合实验实验报告
基于单片机ATmega16电子琴的设计与实现
姓名:
班级:
学号:
班内序号:
同组:
EMAIL :
组号:
北京邮电大学
时间:2013年09月12日
目录
1.实验概要
1.1摘要
1.2关键词
1.3实验目的
2.前期基础实验
3.原理图和流程图.及效果图
4.程序分析
5.调试排错过程
6.心得体会
7.小组分工
8.参考文献
1 实验概要
1.1 摘要
本实验是基于单片机A Tmega16制作的建议电子琴。
通过键盘的控制可以播放预置歌曲以及自行弹奏音符这两个主要功能以及变速,录放音,变调等其他的次要功能,通过数码管和二极管的发光来显示音调和当前模式。
1.2 关键词
avr单片机电子琴弹奏存储播放
1.3 实验目的
(1)对单片机有初步的了解,了解ATmega16单片机的各个端口管脚以及其逻辑功能。
(2)熟悉A VR studio,GCC等软件的编译环境,进行软件仿真。
(3)了解各个模块的作用以及用法,如4*4键盘,喇叭等。
(4)通过对于上述的了解,设计出简易电子琴并实现若干功能。
2 前期基础实验
代码:
#include<avr/io.h>
int main(void)
{
char temp;
unsigned int i,j;
DDRD = 0xff;
PORTD = 0b11100110;
while(1)
{
temp = PORTD;
PORTD = PORTD << 1;
if(temp & 0b10000000)
PORTD |= 0b00000001;
for(i=0;i<500;i++)
for(j=0;j<1000;j++);
}
}
#include<avr/io.h>
#include<avr/interrupt.h>
char shuma[10]=
{
~0b10111011,
~0b10100000,
~0b01101011,
~0b11101010,
~0b11110000,
~0b11011010,
~0b11011011,
~0b10101000,
~0b11111011,
~0b11111010,
};
volatile unsigned int cnt=0,i=0,j=0,m=0,p=0;
int main(void)
{
DDRD = 0xff;
DDRB = 0xff;
MCUCR = 0;
MCUCR |=(1<<ISC10) | (1<<ISC00)| (1<<ISC01);
GICR |= (1<<INT0) | (1<<INT1);
sei();
TCNT0 = 5;
TCCR0 |=(1<<CS01);
while(1);
}
SIGNAL(SIG_INTERRUPT0)
{
i=0;j=0;m=0;p=0;
TIMSK |= (1<<TOIE0);
}
SIGNAL(SIG_INTERRUPT1)
{
TIMSK &= ~(1<<TOIE0);
PORTD = 0b10000000;
PORTB = shuma[i];
for(int n=0;n<500;n++);
PORTD = 0b01000000;
PORTB = shuma[j];
for(int n=0;n<500;n++);
PORTD = 0b00100000;
PORTB = shuma[m]&(~(1<<2));
for(int n=0;n<500;n++);
PORTD = 0b00010000;
PORTB = shuma[p];
for(int n=0;n<500;n++);
}
SIGNAL(SIG_OVERFLOW0)
{
TCNT0 = 5;
cnt++;
if(cnt>60)
{
cnt=0;
PORTD = 0b10000000;
PORTB = shuma[i];
for(int n=0;n<500;n++);
PORTD = 0b01000000;
PORTB = shuma[j];
for(int n=0;n<500;n++);
PORTD = 0b00100000;
PORTB = shuma[m]&(~(1<<2));
for(int n=0;n<500;n++);
PORTD = 0b00010000;
PORTB = shuma[p];
for(int n=0;n<500;n++);
i++;
if(i==10)
{i=0;j++;}
if(j==10)
{j=0;m++;}
if(m==10)
{m=0;p++;}
if(p==6)
p=0;
}
}
3 原理图及实物图
4 程序分析#include<avr/io.h>
#include<avr/interrupt.h>
#include<avr/iom16.h>
unsigned char anjian = 0;//获取按键的
int speed=20;//控制播放速度
unsigned int music_L[7]={262,294,330,349,392,440,494};//存放低八度音阶频率
unsigned int music_C[7]={524,588,660,698,784,880,988};//存放正常C大调音阶频率unsigned int music_H[7]={1047,1175,1319,1397,1568,1760,1976};//存放高八度音阶频率unsigned int music[7]={524,588,660,698,784,880,988};//存放正常C大调音阶频率并且在变调时将其他调的频率写入该数组
unsigned int musicmem[100]={}; //储存弹奏的音乐频率
unsigned int tune[100]={}; //储存弹奏的音乐的某个音符音长
int flag=0; //音长
char display[11]=
{
0,
0b00000110, //数码管显示1
0b01011011, //数码管显示2
0b01001111, //数码管显示3
0b01100110, //数码管显示4
0b01101101, //数码管显示5
0b01111101, //数码管显示6
0b00000111, //数码管显示7
0b01111111, //数码管显示8
0b01101111, //数码管显示9
0b00111111, //数码管显示0
};//控制8段数码管显示
void init()//初始化
{
DDRD |=0x30;//发声
DDRA = 0xf0;//按键
DDRB = 0xff;//8段数码管
DDRC = 0xff;//8段数码管
speed = 20;//播放速度
}
void delay(int ms)//延迟函数单位为毫秒,用于在按键按下后提供延迟响应滤除误按的影响。
同时用来控制发声时间
{
TCNT0 = 55; //设置TC寄存器的初值
TCCR0 |=(1<<CS01); //8分频
for(int i=0;i<ms;i++) //i表示计时器得到的毫秒数
{
for(int j=0;j<(11*speed);j++)//假设一毫秒对应110*speed个计数器周期平时speed=20,加速时speed减小,这样对于同样的输入参数ms,延迟时间变短了。
{while(!(TIFR & (1 << TOV0)));
TCNT0 = 55;}//一个计时器周期
}
}
unsigned char keyscan()//获取按键
{
DDRA = 0xf0;
PORTA = 0x0f;
unsigned char Key = 0;
delay(10);//防止误按、排除干扰
if ((PINA & 0x0f) != 0x0f)
{
delay(10);
if ((PINA & 0x0f) != 0x0f)
{
unsigned char i,j;
for (i=0;i<4;i++)
{
PORTA = ~(0x10<<i);
delay(10);
if ((PINA & 0x0f) != 0x0f)
{
for (j=0;j<4;j++)
{
if ((PINA & (0x01<<j)) == 0)
{
Key = i*4 + j;
Key++;
}
}
}
}
}
delay(10);
}
if(Key==8)//8键加速,并且相应的指示灯亮
{speed=10;
PORTC=0b01000000;}
else if(Key==10)//10键减速,并且相应的指示灯亮
{speed=40;
PORTC=0b00000001;}
else if(Key==9)//9键原速,并且相应的指示灯亮
{speed=20;
PORTC=0b00000010;}
return Key;
}
void player(unsigned int* x1,unsigned int* x2,int l)//播放某组音乐
{
PORTC=0b00000010;
PORTD=0b10111000;
unsigned int* x3=x1+l-1;
while(x1<=x3)
{
unsigned char anjian3=keyscan();
if(anjian3==1)//1停止
x1=x3;
else if(anjian3==2)//2暂停
while(1)
{DDRD&=~0x30;unsigned char anjian4=keyscan();if(anjian4==3)break;};//3继续if(*x1!=0)
{
if(*x1==660|*x1==1319|*x1==330)
PORTB=0b01001111;
if(*x1==262|*x1==524|*x1==1047)
PORTB=0b00000110;
if(*x1==294|*x1==588|*x1==1175)
PORTB=0b01011011;
if(*x1==349|*x1==698|*x1==1397)
PORTB=0b01100110;
if(*x1==392|*x1==784|*x1==1568)
PORTB=0b01101101;
if(*x1==440|*x1==880|*x1==1760)
PORTB=0b01111101;
if(*x1==494|*x1==988|*x1==1976)
PORTB=0b00000111;
DDRD|=0x30;
TCCR1A=0x50;
TCCR1B=0x09;
OCR1A=(8000000/(*x1)-1);
//CTC方式产生方波
}
else
{DDRD&=~0x30;}
keyscan();//调用一次获取按键函数,按8 9 0时加速、减速、原速。
delay(*x2);
x1++;
x2++;
};
DDRD&=~0x30;
PORTC=0b00000000;
}
void play()//弹奏+录制函数
{
int flag=0; //音长
while (1)
{
int i=1;
unsigned char j = 0;
anjian = keyscan();
if (anjian != 0)
{
if(anjian ==13)//按C 切换到L调
{
for(int i=0;i<7;i++)
music[i]=music_L[i];
PORTD=0b01111001;
}
else if(anjian ==14)//按D 切换到C调
{
for(int i=0;i<7;i++)
music[i]=music_C[i];
PORTD=0b01111010;
}
else if(anjian ==15)//按E 切换到H调
{
for(int i=0;i<7;i++)
music[i]=music_H[i];
PORTD=0b01111100;
}
else if(anjian ==16) //按F 播放储存的音乐{
for(int i=0;i<flag;i++)
{
int j=0;
j=tune[i];//
DDRD |=0x30;
PORTB = display[j];
TCCR1A=0x50;
TCCR1B=0x09;
OCR1A=(8000000/musicmem[i]-1);
delay(225);
DDRD &=~0x30;
delay(1500);
keyscan();
}
flag=0;
} //end播放储存的音乐else if(anjian==12) //按B 直接跳出play函数
break;
else //扫描键盘弹奏区
{
DDRD |=0x30;
PORTB = display[anjian];
TCCR1A=0x50;
TCCR1B=0x09;
OCR1A=(8000000/music[anjian-1]-1);//
while(i) //判断是否连续出声
{
j = keyscan();
if(j == 0) //不连续弹奏
{
DDRD &= ~0x30;
i=0;
} //end不连续弹奏
else
i=1;
} //end判断是否连续出声
musicmem[flag]=music[anjian-1];//储存频率
tune[flag]=anjian;//储存音长
flag++;
} //end扫描键盘弹奏区
}
};
}
int main()
{
init();
unsigned int sound1[51] = {
660,0,660,784,880,1047,0,1047,880,784,0,784,880,784,660,0,660,784,880,1047,0,1047,880 ,784,0,784,880,784,0,784,0,784,0,784,660,784,880,0,880,784,660,588,660,784,660,588,524,0,524 ,588,524};
//茉莉花
unsigned int time1[51]= {
1000,10,500,500,500,500,10,500,500,1000,10,500,500,2000,1000,10,500,500,500,500,10,500,500 ,1000,10,500,500,2000,10,1000,10,1000,10,1000,500,500,1000,10,1000,2000,1000,500,500,1000, 500,500,1000,10,500,500,2000};
unsigned int sound2[57] ={660,784,880,660,880,784,660,588,660,588,660,784,524,
440,524,588,0,588,660,784,660,0,660,588,660,588,660,698,784,
660,784,880,0,880,0,880,988,880,0,880,988,1047,1175,988,1047,880,
660,784,880,660,880,784,660,0,660,784,880};
//入阵曲
unsigned int time2[57] = {
300,300,600,300,300,600,300,300,300,300,300,300,600,300,300,600,10,300,300,300,300,10,300, 300,300,300,300,300,600,300,300,600,10,300,10,300,300,300,10,300,300,300,300,300,300,600,3 00,300,600,300,300,300,300,10,300,300,600};
unsigned char anjian1;
PORTB = 0x0f;//8段数码管显示可以表征程序运行到的行数
while(1)//最外层的while函数对应电子琴主菜单
{
anjian1=keyscan();
if(anjian1!=0)
{
if(anjian1==15)//按E播放茉莉花
player(&sound1,&time1,51);
if(anjian1==16)//按F播放入阵曲
player(&sound2,&time2,57);
else if(anjian1==13)//按C进入播放和储存
play();
}
else
PORTB = 0xf0;
}
return 0;
}
5 排错及调试
5.1 软件排错及调试
5.1.1数码管动态扫描
一开始做秒表时,本来是想用很简单的静态扫描,没想到因为PORTC不能用,导致端口不够,只能改为动态扫描。
改完之后,秒表居然每次都是从10直接蹦到59,然后到00又不动了,后来发现是循环的位置设置错了,while(1)也没用对,改了这两点后,秒表终于成功了。
5.1.2按键干扰问题
刚开始用键盘时,发现它极其敏感,都不用按,轻轻一碰就有反应,有时候还会因为过于灵敏出现一些非常奇怪的现象,上网一查才知道如果用到按键或者键盘时,都要有一个防抖动的程序来排除干扰,加上这个程序之后,这个问题被解决。
5.1.3编曲问题
最初我们是想编三首曲子,结果编完下载之后发现程序出了很大问题,再一看Avrstudio 下面的框里写着数据容量115%,才明白这是数据溢出了,只好忍痛删掉一首歌曲,解决了这个问题。
后来播放时又发现喇叭的声音很异常,可能是硬件原因,我把整个曲调调高了一个八度,听起来就舒服多了。
之后的变调也把网上查到的C大调频率通通调高了八度。
5.1.4按键冲突问题
我们做的电子琴有调快、慢、正常三个速度,变高、中、低三个调,播放和弹奏模式的切换,暂停、恢复播放功能,还要储存两首曲子。
但是键盘上最多只有9个键可以用,因此如何合理的排布这些功能就显得至关重要。
我们一开始没有想到会有这个问题,真播放的时候,发现按键功能混乱的一团糟,可能进了另一个模式就不管用了。
我们颇费了一番功夫设计,才排开了所有功能。
5.2 硬件排错及调试
5.2.1 端口选择不合理
前期做流水灯和秒表的时候,把流水灯放在PORT C,发现不能用。
找老师询问后得知那四个位置被电源占用,无法正常工作,只能换到其他PORT。
5.2.2 负载驱动不足
我们在做完电子琴的基础功能之后,进行功能优化的时候选择用二极管显示出播放模式或弹奏模式,模仿模式的当前速度以及弹奏模式的音调。
加入第一项模式显示的时候,把二极管加在了PORTD的两个位置,但是下载程序后发现这两只二极管发光很微弱。
我们开始以为代码的问题,就修改了好几次代码,试验了各种端口输出方式,但是发现没用。
后来发现是因为喇叭占用了大部分电压,我们只能尽可能的将二极管移到其他端口。
6 心得体会
A VR单片机实验是一个完全自学的实验,只能靠自己观看给的PDF文档、之前同学做出来的范例和视频教程来学习。
刚一使用Avrstudio就出现了问题,我根据视频写了一个最简单的软件来测试,结果却发现运行不了,经过查阅大量的网上资料,原来是WINAVR出现问题,我明明安装了这个软件,但它居然没有和Avrstudio关联起来。
我只好重新安装,最后才发现WINA VR只能安装到C盘。
Avestudio用的是C语言,我们之前学习了C++,两者之间总算还有些联系,因此写代码的基本问题还不用太头疼。
我主要是通过视频来学习的,期间还到图书馆借过一些相关书籍,视频里的讲解很详细,但过于基础了,做前面的基础实验还勉强够用,到后来自己设计的实验,我们非常需要的一些东西视频里都没有,我们只能在去各种论坛、网站学习。
整个实验中,我个人感觉最难的部分是计时器还有寄存器,虽然照葫芦画瓢就行,但他的根本原理我至今还没有特别搞清楚。
这次实验还出现过很多让我们意想不到的问题,比如有一次下载完程序后,单片机上的程序居然不变,后来没办法了,重新建立了一个工程他就又好了,真是让我们哭笑不得。
还有每次下载程序时,不知道是不是硬件的问题,几乎没有一次成功的时候,总要拔了再插、插了再拔的下载很多次才能成功。
我认为小组合作是一个非常好的学习方式,我和同伴既能专注于各自负责的部分,大大提高效率,又能互相帮助、讨论,共同思考对方的部分。
A VR单片机实验锻炼了我们自主学习能力,动手实践能力,小组合作能力,系统工程能力,给我带来很多启示,希望以后还能有这样的机会,进一步提高自己。
7 小组分工
8 参考文献
7.1 A VR单片机说明文档cn_mega16-16L.pdf
7.2 A VR单片机软硬件设计视频教程-入门篇-第一讲~第八讲
7.3 avr视频中压缩包的第一讲~第十一讲
7.4百度。