基于单片机的电子琴和音乐播放器设计.docx

上传人:b****5 文档编号:7747438 上传时间:2023-01-26 格式:DOCX 页数:36 大小:151.49KB
下载 相关 举报
基于单片机的电子琴和音乐播放器设计.docx_第1页
第1页 / 共36页
基于单片机的电子琴和音乐播放器设计.docx_第2页
第2页 / 共36页
基于单片机的电子琴和音乐播放器设计.docx_第3页
第3页 / 共36页
基于单片机的电子琴和音乐播放器设计.docx_第4页
第4页 / 共36页
基于单片机的电子琴和音乐播放器设计.docx_第5页
第5页 / 共36页
点击查看更多>>
下载资源
资源描述

基于单片机的电子琴和音乐播放器设计.docx

《基于单片机的电子琴和音乐播放器设计.docx》由会员分享,可在线阅读,更多相关《基于单片机的电子琴和音乐播放器设计.docx(36页珍藏版)》请在冰豆网上搜索。

基于单片机的电子琴和音乐播放器设计.docx

基于单片机的电子琴和音乐播放器设计

北京邮电大学

基于单片机的电子琴和音乐播放器设计

实验报告

 

学院:

信息与通信工程学院

指导老师:

葛顺明

 

摘要

电子琴是现代电子科技与音乐结合的产物,是一种新型的键盘乐器。

它在现代音乐扮演着重要的角色,单片机具有强大的控制功能和灵活的编程实现特性,它已经溶入现代人们的生活中,成为不可替代的一部分。

本文的主要内容设计为一个基于PIC32MX795F512L单片机的电子琴与音乐播放器,利用单片机上的按键来选择相应功能,利用键盘按键来选择弹奏某一音调或播放某首曲子。

能够实时将数据传至液晶屏显示。

根据单片机的工作原理,通过硬件电路制作和软件编译,设计出一个能够自由弹奏乐曲及流畅播放内置音乐的电子琴与音乐播放器。

该系统主要由液晶显示模块、键盘模块、喇叭模块组成。

设计利用MPLAB软件对源程序进行编译和调试。

关键词:

PIC32MX795F512L单片机,模块

一.实验目的

1.通过学习使用单片机PIC32,使学生增进对单片机的感性认识,加深对单片机理论方面的理解。

2. 使学生掌握单片机的内部功能模块的功能和应用,如定时器/计数器、中断、I/O口等。

 

3使学生理解和掌握单片机应用系统的软件硬件设计过程、方法及实现,为以后设计和实现单片机应用系统打下良好基础。

二.实验分工

本次实验我的队友主要负责的部分是XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

过程期间出现的问题是由我们两个人共同查阅资料完成的,整体合作协调很好,完成的较为顺利。

三.功能简介

1.设计一个电子琴。

所能实现的功能如下:

(1).能够实现舒适化菜单,由按键选择菜单中的两个功能:

播放乐曲和弹奏乐曲,并实现其功能;

(2).播放乐曲:

又初始化菜单选择进入,进入后屏幕提示”SONGPLAYING”,同时事先在程序中存入了8首不同的乐曲,可以一次通过键盘的按键来选择播放各首乐曲。

在播放曲目中设置了暂停键,按下即暂停,不按下则继续播放循环播放。

(3).自行弹奏:

设计键盘上的13个键能够发出低音部5,6,7,中音部1,2,3,4,5,6,7,高音部1,2,3总共14个音,要求按下按键发声,松开延时一段时间停止,中间再换按其他键则发另一音调的声音。

(4).走马灯:

设计了4个蓝光走马灯配合播放音乐和演奏时闪烁。

2.当系统扫描到有键被按下,则快速检测出是哪一个键被按下,然后单片机的定时器被启动,发出一定频率的脉冲,该频率的脉冲输入到蜂鸣器后,就会发出相应的音调如果在前一个按下的键发声的同时另一个键被按下,则启动中断系统,前面键的发音停止,转到后按的发音程序,发出后按的键的音调。

四.实验原理

4.1音频脉冲的产生 

一首音乐是许多不同的音阶组成的,而每个音阶对应着不同的频率,这样我们就可以利用不同的频率的组合,即可构成我们所想要的音乐了,当然对于单片机来产生不同的频率非常方便,我们可以利用单片机的定时/计数器来产生这样方波频率信号,因此,我们只要把一首歌曲的音阶对应频率关系弄正确即可。

 

若要产生音频脉冲,只要算出某一音频的周期(1/频率),再将此周期除以2,即为半周期的时间。

利用定时器计时半周期时间,每当计时终止后就将相应的端口反相,然后重复计时再反相。

就可在各对应的引脚上得到此频率的脉冲。

 

  我们小组利用PIC32MX795F512L的80M主频,运用delay函数,改变delay的时间以产生不同频率的方法产生不同音阶。

由于主频较高,没有一个音符的频率可以参考,于是我们小组是利用自己的乐理知识将每个音校正。

    

每个音与delay时间对应如下表所示:

音符

Delay

音符

Delay

中音Do

8876

高音Re

2446

中音Re

7476

高音Mi

1936

中音Mi

6456

高音Fa

1666

中音Fa

5886

高音So

1186

中音So

5036

高音La

766

中音La

4036

高音Xi

376

中音Xi

3236

高音Do

186

高音Do

3006

4.2音乐节拍的产生 

每个音符使用1个字节,字节的高4位代表音符的高低,低4位代表音符的节拍,表1-2为节拍与节拍码的对照表。

如果1拍为0.4s,1/4拍是0.1s,只要设定延时时间就可求得节拍的时间。

假设1/4拍为1DELAY,那么1拍应为4DELAY,以此类推。

所以只要求得1/4拍的DELAY,其余的节拍就是它的倍数,表1-3为1/4和1/8拍的时间设定。

本小组的节拍是由while函数实现的,在每个节拍delay的时间中播放对应的音符,1/8为1,1/4为2,以此类推。

而while循环的时间为节拍*310,这是我们经过反复试验确定的最佳的节拍延时。

 

五.方案设计

5.1硬件设计

5.1.1电路设计框图

PIC32MX795F512L芯片

输出模块:

喇叭

5.1.2硬件概述

本电路是由PIC32MX795F512L单片机为控制核心,具有键盘输入、液晶显示屏输出和三极管驱动的喇叭构成的简易电子琴电路。

1.单片机

PIC32MX795F512L型号单片机具有USB、CAN和以太网的高性能32位闪存,其所拥有的主要资源有:

✧80MHz的主频,1.56DMIPS/MHz,总线32位;

✧USB2.0接口;

✧2个带1024缓存的CAN2.0接口;

✧8通道DMA通道;

✧5级流水线,哈佛架构;

✧1个以太网接口;

✧512K的Flash,外加12k的启动Flash;

✧128K的RAM;

✧可编程中断向量控制器;

✧16个10位AD转换器;

✧UART/SPI/IIC等串行通信方式;

✧带JTAG调试口,具有休眠功能,节省能耗。

2.输入模块(键盘)

一个简易的电子琴需要键盘15个按键,选择用4*4行列式键盘完成输入。

4*4行列式键盘又称为矩阵键盘,它是用4条I/O线作为行线,4条I/O线作为列线组成的键盘。

在行线和列线的每一个交叉点上,设置一个按键。

这样键盘中按键的个数是4×4个。

这种行列式键盘结构能够有效地提高单片机系统中I/O口的利用率。

而键盘应具有以下几个基本功能:

(1)去抖动:

每个按键在按下或松开时,都会产生短时间的抖动。

抖动的持续时间与键的质量相关,一般为5—20mm。

所谓抖动是指在识别被按键是必须避开抖动状态,只有处在稳定接通或稳定断开状态才能保证识别正确无误。

去抖问题可通过软件延时或硬件电路解决。

  

(2)被按键识别:

如何识别被按键是接口解决的主要问题,一般可通过软硬结合的方法完成。

常用的方法有行扫描法和线反转法两种。

行扫描法的基本思想是,由程序对键盘逐行扫描,通过检测到的列输出状态来确定闭合键,为此,需要设置入口、输出口一个,该方法在微机系统中被广泛使用。

本实验采用扫描法。

(3)键码产生:

为了从键的行列坐标编码得到反映键功能的键码,一般在内存区中建立一个键盘编码表,通过查表获得被按键的键码。

RE0

RG14

RG1

RD3

RE1RD4RE3RE2

3.输出模块(显示屏)

采用型号为RT1602C的液晶显示屏,液晶显示屏的显示功能强大,可显示大量文字、图形,显示多样,清晰可见,与传统的阴极射线管相比,液晶显示屏具有占用空间小、低功耗、低辐射、无闪烁、降低视觉疲劳等优点。

字符型液晶屏是一种用5*7点阵图形来显示字符的液晶显示器,根据显示的容量可以分为1行16个字、2行16个字、2行20个字等,最常用的为2行16个字。

型号为RT1602C的液晶显示屏就是2行16个字。

它有16个管脚,分别有电源地、电源正、偏压信号、读写控制、使能控制、I/O接口、背光控制等功能。

它的读写操作、屏幕和光标的操作都是通过指令编程来实现的。

VO为显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高。

为了简化电路以及获得最好的显示效果,将VO端口直接接地。

R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。

GND接电源,VDD接正电源。

RS为寄存器选择,高电平时选择数据寄存器,低电平时选择指令寄存器。

源代码中write_cmd函数为向LCD写入指令的函数,因此会有RS=0;write_date函数为向LCD写入数据的函数,因此会有RS=1。

E端为使能端,当E端由高电平跳变成低电平,也就是下降沿时,LCD模块进行命令执行。

BL1和BL2为设置LCD背光,分别接了电源与地。

DO~D7八个为数据I/O口,按照表格内的接法相连。

 

脚号

符号

引脚功能以及接法

脚号

符号

引脚功能以及接法

1

GND

电源地

9

D2

 RF13

2

VDD

电源正

10

D3

 RB12

3

V0

显示偏压信号

11

D4

 RB13

4

RS

数据/命令控制RA7

12

D5

 RB14

5

R/W

读/写控制RA6

13

D6

 RB8

6

E

使能信号RF4

14

D7

RB9

7

D0

数据I/ORF5

15

BL1

背光源正

8

D1

 RF12

16

BL2

背光源负

4.输出模块(喇叭)

将一固定端口通过三极管PNP放大再连接喇叭构成我们的输出音频模块。

喇叭一端接电源一端接发射极,当有方波送入时,喇叭便发出相应频率的响声。

5.输出模块(走马灯)

将四个发光二极管与四个端口相连,另外一端通过小电阻接地,通过控制四个端口依次为高电平使得四个灯依次点亮,实现走马灯的效果。

 

5.2软件设计

5.2.1程序流程图

判断LCD按键

SW3

SW1

5.2.2各模块具体软件实现

1.键盘模块

运用行扫描的方式来判断是否有键按下及按下的是哪一键。

首先令行都为输出并置为零,列为输入且都为高电位,则只要有一列为低就是有键按下。

再依次令每一行为低电平其他行为高电平,检查每一列是否为低电平,行和列均为低电平所对应的交汇处即为按键按下的地方。

#include"KEYBOARD.h"

//时延函数

voiddelay(uintms)

{

uintx,y;

for(x=ms;x>0;x--)

for(y=10;y>0;y--);

}

ucharkeyboard()//判断按下哪一键

{

while

(1)

{

delay(100);

//将R行全部设置为输出为低电平0;

PORTSetPinsDigitalOut(IOPORT_G,BIT_14|BIT_1);

PORTSetPinsDigitalOut(IOPORT_D,BIT_3);

PORTSetPinsDigitalOut(IOPORT_E,BIT_0);

PORTClearBits(IOPORT_G,BIT_14|BIT_1);

PORTClearBits(IOPORT_D,BIT_3);

PORTClearBits(IOPORT_E,BIT_0);delay

(1);

//将C列全部设置为输入为高电平1

PORTSetPinsDigitalIn(IOPORT_E,BIT_1|BIT_2|BIT_3);

PORTSetPinsDigitalIn(IOPORT_D,BIT_4);

PORTSetBits(IOPORT_E,BIT_1|BIT_2|BIT_3);

PORTSetBits(IOPORT_D,BIT_4);delay

(1);

//第一列

R0=0;R1=1;R2=1;R3=1;//第一行

if(C0==0)//第一列

{

delay(10);

if(C0==0)return1;

}

if(C1==0)

{

delay(10);

if(C1==0)return2;

}

if(C2==0)

{

delay(10);

if(C2==0)return3;

}

if(C3==0)

{

delay(10);

if(C3==0)return4;

}

//第二列

R0=1;R1=0;R2=1;R3=1;

if(C0==0)

{

delay(10);

if(C0==0)return5;

}

if(C1==0)

{

delay(10);

if(C1==0)return6;

}

if(C2==0)

{

delay(10);

if(C2==0)return7;

}

if(C3==0)

{

delay(10);

if(C3==0)return8;

}

//第三列

R0=1;R1=1;R2=0;R3=1;

if(C0==0)

{

delay(10);

if(C0==0)return9;

}

if(C1==0)

{

delay(10);

if(C1==0)return10;

}

if(C2==0)

{

delay(10);

if(C2==0)return11;

}

if(C3==0)

{

delay(10);

if(C3==0)return12;

}

//第四列

R0=1;R1=1;R2=1;R3=0;

if(C0==0)

{

delay(10);

if(C0==0)return13;

}

if(C1==0)

{

delay(10);

if(C1==0)return14;

}

if(C2==0)

{

delay(10);

if(C2==0)return15;

}

if(C3==0)

{

delay(10);

if(C3==0)return16;

}

}

};

ucharpresskey()//判断是否有键按下

{delay(100);

//将R行全部设置为输出为低电平0;

PORTSetPinsDigitalOut(IOPORT_G,BIT_14|BIT_1);

PORTSetPinsDigitalOut(IOPORT_D,BIT_3);

PORTSetPinsDigitalOut(IOPORT_E,BIT_0);

PORTClearBits(IOPORT_G,BIT_14|BIT_1);

PORTClearBits(IOPORT_D,BIT_3);

PORTClearBits(IOPORT_E,BIT_0);delay

(1);

//将C列全部设置为输入为高电平1

PORTSetBits(IOPORT_E,BIT_1|BIT_2|BIT_3);

PORTSetBits(IOPORT_D,BIT_4);

PORTSetPinsDigitalIn(IOPORT_E,BIT_1|BIT_2|BIT_3);

PORTSetPinsDigitalIn(IOPORT_D,BIT_4);

delay

(1);

R0=0;R1=0;R2=0;R3=0;

if(C0==0)

{

delay(10);

if(C0==0)return1;

}

if(C1==0)

{

delay(10);

if(C1==0)return1;

}

if(C2==0)

{

delay(10);

if(C2==0)return1;

}

if(C3==0)

{

delay(10);

if(C3==0)return1;

}

return0;

}

2.LCD模块(本模块为组员xx主要编写,此处不再叙述)

3.喇叭播放模块

通过将不同频率的方波输送到喇叭的端口来使其发出声音。

在弹奏时,若一直按着按键,就会一直发出相应键值的音调。

在播放音乐时,首先通过键盘选择一首乐曲,通过同一参数将节拍和音调结合,在第一个音调的节拍长度中播放第一个音,直到节拍结束,令Tone_Index加1,继续下一个音的相应节拍中的发声,以此类推,直到播完一首曲子。

同时我们还通过设置中断实现了暂停的功能,只要按下单片机上的SW2,就可以暂停音乐的播放。

while

(1)

{

if(FY==0)

{//若没有松开按键,则等待,等待期间弹奏该音符

while(presskey()==1)

{

k=keyboard();

uintx=tab[k];

d(x);

SPK=!

SPK;

if(h==499)h=1;

run(h);h++;

}

}

else

{

k=keyboard();

while

(1)

{

if(Song[k][Tone_Index]==-1)Tone_Index=0;

uintms=310*Len[k][Tone_Index];

while(ms--)

{

intx=2600+tab[Song[k][Tone_Index]];

d(x);

SPK=!

SPK;

if(h==499)h=1;

run(h);h++;

};

Tone_Index++;

d(200000);

}

}

}

void__ISR(_CHANGE_NOTICE_VECTOR,ipl2)ChangeNotice_Handler(void)

{

//读取D端口的bit7的数据,放到全局变量dummy缓存中

dummy=PORTReadBits(IOPORT_D,BIT_7);

//清空中断标志位,目的是使其能产商第二次中断

mCNClearIntFlag();

//按钮按着则灯一直亮

if(dummy==BIT_7)

{//D端口的bit1位清0,即LED2灯灭

PORTClearBits(IOPORT_D,BIT_1);//turnoffLED2

LCD_Initialize();//初始化LCD

LCD_ShowString(0,0,"2.SONGSPLAY");

}

else

{//D端口的bit1位置1,即LED2灯亮

PORTSetBits(IOPORT_D,BIT_1);//turnonLED2

while(PORTReadBits(IOPORT_D,BIT_7)==0)

{

LCD_Initialize();//初始化LCD

LCD_ShowString(0,0,"PAUSE");

d(2000000);

}

}

}

4.走马灯模块

通过控制四个端口依次为高电平使得四个灯依次点亮,实现走马灯的效果。

由于系统主频较快,因此每一个灯亮的时间为100个系统周期,这样才能看清依次的变化。

#include"lighting.h"

#defineucharunsignedchar

voidrun(inth)

{

PORTSetPinsDigitalOut(IOPORT_A,BIT_10);

PORTSetPinsDigitalOut(IOPORT_E,BIT_4);

PORTSetPinsDigitalOut(IOPORT_D,BIT_5);

PORTSetPinsDigitalOut(IOPORT_G,BIT_13);

if((h>0)&(h<100))

{

L1=1;L2=0;L3=0;L4=0;

}

if((h>99)&(h<200))

{

L1=0;L2=1;L3=0;L4=0;

}

if((h>199)&(h<300))

{

L1=0;L2=0;L3=1;L4=0;

}

if((h>299)&(h<500))

{

L1=0;L2=0;L3=0;L4=1;

}

};

 

六.实验问题及心得体会

6.1出现的问题

1.定时器

小学期的前五天我和我的队友四处搜集关于PIC单片机的资料,综合老师课上提供的数据手册使用说明,得知单片机有五个定时器,按理说依照说明在我们发声的部分正确书写代码就可以提供出我们相应音色的频率,并且我们发出声音的模块想要频率为1MHz的定时器来完成,这样无论从计数的计算上还是程序的编写上都十分方便,但是在读说明书和函数说明中出现了很多问题,很多地方不很清晰,英文版说明也给阅读带来了一定的障碍,经过三番五次向老师询问,写出的代码编译时总是不能完好通过,所以最终无奈之下我们放弃了这一方法,仅仅使用延时函数及自己的乐理知识来校准的每一个音,增加了不少工作量,而没有好好运用定时器也是这次小学期试验的一个遗憾,在以后的学习中一定会加深认识定时器并尽量学会应用。

2.显示屏的调试

显示屏的调试是我们班整体遇到的最大的问题,直到验收前一天显示屏还没有达到很好的效果。

刚开始拿到硬件连接之后,我们的显示屏连背光都没有亮,经检查连接无误后想可能是显示屏本身出了问题,正好班上其他同学的显示屏也都存在着一定的错误,于是我们集体换了一批显示屏。

新的显示屏拿来后背光是亮了,但是依旧没有字显示,经过代码的各种调试与更改终于能实现一行字的显示,但在我们想实现按键显示屏做出相应变化的功能时,发现显示屏根本没有变化,于是又回去调试它。

经过老师的直到我们发现成功显示的那一句代码是放在设置主频之前的,而在主频之下我们的LCD代码就失效了,我们短暂的成功只是偶然性的。

于是这次我们就先设置好主频,然后回去更改LCD中延时的长度,经过多次尝试后终于能显示出字并实现刷新显示了。

这之后又出现一个小问题,就是字符串不是一下子全显示出来,而是有那种渐变的效果,思考一下发现是延时太长,于是改短写数据的延时后问题迎刃而解。

LCD调试是个漫长需要耐心的工作,一旦成功,就会发现这一切努力都没有白费。

3.喇叭的调试

在网上查阅关于喇叭的连接方法和注意事项之后我们将喇叭焊在了板子上,第一次测验时随意取了一个机器频率测试是否能够正常发声,可是没有成功,喇叭没有声音而且变烫,我们迅速停止调试检查问题,发现三极管损坏,于是我们又换了一个PNP管并重新设计电路,采用共集放大电路并将喇叭一端接电源,此时喇叭发出了声音,但频率很低,我们又回去调整了频率和延时才得到了较为满意的结果。

4.键盘的调试

小学期的第二天就在网上查阅资料弄懂了键盘的扫描输入原理,后来通过几天的修改将代码程序写好之后测试时是成功的,但是又过了几天待全部发声代码编写完成再次测试的时候有两个键按下时发声频率不正确,一个键按下后不论怎样调试频率没有变化,另一个键发声和相邻的键始终保持一致,后来通过不断地改代码调试发现第一个键出了问题,另一个键的接头接触不

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 理学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1