基于单片机的简易MP3

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

基于单⽚机的简易MP3
1 项⽬概述和要求
1.1 项⽬开发背景
随着电⼦科技的飞速发展,电⼦技术正在逐渐改善着⼈们的学习、⽣活、⼯作,因此开发本系统希望能够给⼈们多带来⼀点⽣活上的乐趣。

基于当前市场上的玩具市场需求量⼤,其中电⼦琴就是⼀个很好的应⽤⽅⾯。

单⽚机技术使我们可以利⽤软硬件实现电⼦琴的功能,从⽽实现电⼦琴的微型化,可以⽤作玩具琴、⾳乐转盘以及⾳乐童车等等。

并且可以进⾏⼀定的功能扩展。

鉴于传统电⼦琴可以⽤键盘上的“1”到“A”键演奏从低So到⾼DO等11个⾳,从⽽可以⽤来弹奏喜欢的乐曲。

该设计将⼗⼀个琴键改成16个,使电⼦琴的功能更加完美。

不但可以实现对乐曲的演奏,同时还具有存储⾳乐、播放歌曲以及显⽰按键的功能。

使该设计功能更加完善。

1.2 项⽬⽬的
利⽤AT89C51单⽚机⾃带资源,设计⼀款能实现弹奏和带存储功能的电⼦琴。

(1)能够对电⼦电路、电⼦元器件、印制电路板等⽅⾯的知识有进⼀步的认识,独⽴对其进⾏测试与检查。

(2)熟悉8051单⽚机的内部结构和功能,合理使⽤其内部寄存器,能够完成相关软件编程设计⼯作。

(3)为实现预期功能,能够对系统进⾏快速的调试,并能够对出现的功能故障进⾏分析,及时修改相关软硬件。

(4)对软件编程、排错调试、焊接技术、相关仪器设备的使⽤技能等⽅⾯得到较全⾯的锻炼和提⾼。

1.3设计要求
①设计出15个⾳符,随意弹奏,按“0”键为⾳乐休⽌符,不发声,⽤它时间的长短表⽰休⽌时间的长短。

②⽤功能键转换成歌曲演奏,可播放预存的⾳乐。

③可存储现场弹奏的⾳乐。

[扩充功能]:
④采⽤LCD显⽰信息,开机时有欢迎提⽰符,播放时显⽰歌曲序号(或名称)。

⑤显⽰乐曲播放时间或剩余时间。

2 系统硬件设计
2.1电⼦琴原理
在介绍总体⽅案之前,先简单介绍⼀下电⼦琴的发⽣原理以及如何改变⾳⾊的基本原理:声⾳的频谱范围约在⼏⼗到⼏千赫兹, 若能利⽤程序来控制单⽚机某个⼝线不断输出“⾼”“低”电平, 则在该⼝线上就能产⽣⼀定频率的⽅波, 将该⽅波接上喇叭就能发出⼀定频率的声⾳, 若再利⽤程序控制“⾼”“低”电平的持续时间, 就能改变输出波形的频率从⽽改变⾳调。

乐曲中, 每⼀⾳符对应着确定的频率, 下表给出各⾳符频率。

如果单⽚机某个⼝线输出“⾼”“低”电平的频率和某个⾳符的频率⼀样, 那么将此⼝线接上喇叭就可以发出此⾳符的声⾳[1]。

本系统就是根据此原理设计, 对于单⽚机来说要产⽣⼀定频率的⽅波⼤致是先将某⼝线输出⾼电平然后延时⼀段时间再输出低电平, 如此循环的输出就会产⽣⼀定频率的⽅波, 通过改变延时的时间就可以改变输出⽅波的频率。

单⽚机内部有两个位的定时计数器T1和T0, 单⽚机的定时计数器实际上是个计数装置它既可以对单⽚机的内部晶振驱动时钟计数也可以对外部输⼊的脉冲计数, 对内部晶振计数时称为定时器, 对外部时钟计数时称为计数器。

当对单⽚机的内部晶振驱动时钟计数时,每个机器周期定时计数器的计数值就加, 当计数值达到计数最⼤值时计数完毕并通知单⽚机的⼫⽐对外部输⼊的时钟信号计数时, 外部时钟的每个时钟上升沿定时计数器的计数值就加, 当计数值达到计数最⼤值时计数完毕并通知单⽚机。

因此, 如果知道单⽚机的机器周期或者外部输⼊时钟信号的周期单⽚机就可以根据定时器的计数值计算出定时的时间。

⽤此⽅法定时⼗分准确, 想得到多⼤的延时时间就可以给定时器赋⼀定的计数初值, 定时器从预先设置的计数初值开始不断增当增加到计数最⼤值时计数完毕, 调整计数初值的⼤⼩就可以调整定时器定时的时间, 从⽽达到准确的延时。

2.2系统结构
(2)扬声器:发声
(3)LED:显⽰欢迎界⾯,显⽰操作,显⽰演奏⾳乐歌词(后期开发计划)
(4)AT89C51:系统控制中⼼系统结构图如图2-1所⽰。

图2-1 系统结构图
2.3 硬件部分总体⽅案
51单⽚机P0⼝通过8155扩展,连接4*8的矩阵键盘,作为琴键键盘和相应的功能控制键;并P2⼝⼀起,与EPROM 连接;P0⼝则接通不通⾳⾊的滤波电路,通过程序控制P0⼝,选通不通的琴声⾳⾊滤波电路,使电⼦琴发出不同⾳⾊的声⾳。

硬件电路包括中⼼控制模块、播放模块、按键控制模块三⼤模块。

其电路图如图2-2所⽰:
振荡器
分频器
电源
键盘
放⼤器
扬声器
1
2
3
4
5
Title Num
Size B Date:26-M File :
D:\Pr
V c c
40
E A
31
R S T
9
G N D
20
X 1
19
X 2
18
P1.1
2P1.2
3P1.3
4P1.4
5P1.5
6
P1.6
7P1.7
8P3.0/RXD 10P3.1/TXD 11P3.2/INT0 12P3.3/INT1 13P3.4/T0 14P3.5/T1 15P3.6/WR 16P3.7/RD 17P0.0/AD0 39
P0.1/AD1 38P0.2/AD2 37P0.3/AD3 36P0.4/AD4 35P0.5/AD5 34
P0.6/AD6 33P0.7/AD7 32ALE 30 PSEN
29P2.7/A15 28
P2.6/A14 27P2.5/A13 26P2.4/A12 25P2.3/A11
23P2.1/A9
22P2.0/A821U1
AT89S51
R110K R210K
R310K
Y112MHz
C7
30pF C630pF
12345678P1
HEADER 8
S1SW -PB
S2SW -PB
S3SW -PB
S4SW -PB
S5SW -PB S6SW -PB S7SW -PB S8SW -PB S9SW -PB S10SW -PB S11SW -PB S12SW -PB S13SW -PB S14SW -PB S15SW -PB S16SW -PB C1
10uF
VCC
Vcc 6IN+3IN-2BYPASS 7
V OUT 5GAIN 1GAIN 8GND
4
U2
LM386
C2
10uF C3
0.1uF VCC
C4
10uF R4
10K C50.1uF
LS1
扬声器
CR4CR3CR2CR1BR4BR3BR2BR1
C R 4
C R 3C R 2C R 1B R 4B R 3B R 2B R 1a
b
c d p a
7
b 6
c 4
d 2
e 1
f 9G N D
3
G N D
8
g 10dp 5U3
DP Y7_SEG_DP
R4220
图2-2 电⼦琴电路图
2.4元件清单
1) AT89C51
AT89C51是⼀种带4K 字节闪存可编程可擦除只读存储器(FPEROM —Flash Programmable and Erasable Read Only Memory )的低电压,⾼性能CMOS 8位微处理器,俗称单⽚机。

AT89C2051是⼀种带2K 字节闪存可编程可擦除只读存储器的单⽚机。

单⽚机的可擦除只读存储器可以反复擦除100次。

该器件采⽤ATMEL ⾼密度⾮易失存储器制造技术制造,与⼯业标准的MCS-51指令集和输出
管脚相兼容。

由于将多功能8位CPU和闪烁存储器组合在单个芯⽚中,ATMEL的AT89C51是⼀种⾼效微控制器,AT89C2051是它的⼀种精简版本[2]。

AT89C单⽚机为很多嵌⼊式控制系统提供了⼀种灵活性⾼且价廉的⽅案。

本次设计中中⼼控制模块是采⽤AT89C51单⽚机来控制整个系统。

其中P1⼝作为输⼊⼝,连接蜂鸣器驱动电路,⽽P2⼝连接按键控制电路,从⽽实现播放⾳乐的功能。

2) LCD1602
LCD1062 在本次中主要⽤于显⽰,有如下特点:
显⽰质量⾼:由于液晶显⽰器每⼀个点在收到信号后就⼀直保持那种⾊彩和亮度,恒定发光,⽽不像阴极射线管显⽰器(CRT)那样需要不断刷新新亮点。

因此,液晶显⽰器画质⾼且不会闪烁。

数字式接⼝:液晶显⽰器都是数字式的,和单⽚机系统的接⼝更加简单可靠,操作更加⽅便。

体积⼩、重量轻:液晶显⽰器通过显⽰屏上的电极控制液晶分⼦状态来达到显⽰的⽬的,在重量上⽐相同显⽰⾯积的传统显⽰器要轻得多。

功耗低:相对⽽⾔,液晶显⽰器的功耗主要消耗在其内部的电极和驱动IC 上,因⽽耗电量⽐其它显⽰器要少得多[3]。

其硬件原理图如图2-3所⽰。

图2-3 LCD1062 硬件原理图
3)4X4⾏列式键盘识别及显⽰键盘接⼝必须具有去抖动、防串键、按键识别和键码产⽣4个基本功能。

持续时间与键的质量相关,⼀般为5~20mm。

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

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

(2)防串键:防串键是为了解决多个键同时按下或者前⼀按键没有释放⼜有新的按键按下时产⽣的问题。

常⽤的⽅法有双键锁定和N键轮回两种⽅法。

双键锁定,是当有两个或两个以上的按键按下时,只把最后释放的键当作有效键并产⽣相应的键码。

N键轮回,是当检测到有多个键被按下时,能根据发现它们的顺序依次产⽣相应键的键码。

(3)被按键识别:如何识别被按键是接⼝解决的主要问题,⼀般可通过软硬结合的⽅法完成。

常⽤的⽅法有⾏扫描法和线反转法两种。

⾏扫描法的基本思想是,由程序对键盘逐⾏扫描,通过检测到的列输出状态来确定闭合键,为此,需要设置⼊⼝、输出⼝⼀个,该⽅法在微机系统中被⼴泛使⽤。

线反转法的基本思想是通过⾏列颠倒两次扫描来识别闭合键,为此需要提供两个可编程的双向输⼊/输出端⼝。

(4)键码产⽣:为了从键的⾏列坐标编码得到反映键功能的键码,⼀般在内存区中建⽴⼀个键盘编码表,通过查表获得被按键的键码[4]。

⽤AT89S51的并⾏⼝P1接4×4矩阵键盘,以P1.0-P1.3作输⼊线,以P1.4-P1.7作输出线;在数码管上显⽰每个按键的“0-F”序号。

4)speaker蜂鸣器
5)三极管
3软件设计
本软件设计关键是要实现⼀种由单⽚机控制的简单⾳乐发⽣器,它由16个⾳节组成的的键盘,⽤户可以根据乐谱在键盘上进⾏演奏,⾳乐发⽣器会根据⽤户的弹奏,通过扬声器将⾳乐播放出来。

3.1单⽚机实现⾳乐
⼀⾸⾳乐是由许多不同的⾳符组成的,⽽每个⾳符对应着不同的频率,这样就可以利⽤不同频率的组合,加以与拍数对应的延时,构成⾳乐。

(1)节拍设计
除了⾳符以外,节拍也是⾳乐的关键组成部分。

节拍实际上就是⾳持续时间的长短,在单⽚机系统中可以⽤延时来实现,如果1/4拍的延时是0.4秒,则1拍的延时是1.6秒,只要知道1/4拍的延时时间,其余的节拍延时时间就是它的陪数。

如果单⽚机要⾃⼰播放⾳乐,那么必须在程序设计中考虑到节拍的设置,由于本例实现的⾳乐发⽣器是由⽤户通过键盘输⼊弹奏乐曲的,所以节拍由⽤户掌握,不由程序控制。

对于不同的曲调我们也可以⽤单⽚机的另外⼀个定时/计数器来完成。

⾳乐的⾳拍,⼀个节拍为单位(C调)具体如表3-1:
表3-1 ⾳乐节拍表
曲调值DELAY曲调值DELAY
调4/4125ms 调4/462ms
调3/4187ms 调3/494ms
调2/4250ms 调2/4125ms
(2)⾳频脉冲实现
了解⾳乐的⼀些基本知识后可知,产⽣不同频率的⾳频脉冲即能产⽣⾳乐,对于单⽚机⽽⾔,产⽣不同频率有脉冲⾮常⽅便,可以利⽤它的定时/计数器来产⽣这样的⽅波频率信号,因此,需要弄清楚⾳乐中的⾳符和对应的频率,以及单⽚机定时计数的关系。

在本实验中,单⽚机⼯作于12MHZ时钟频率,使⽤其定时/计数器T0,⼯作模式为1,改变计数值TH0和TL0可以产⽣不同频率的脉冲信号,在此情况下,C调的各⾳符频率与计数值T的对照如表3-2:
表3-2 ⾳符频率与计数值T的对照表
⾳符频率(HZ)计数值(T值)⾳符频率(HZ)计数值(T值)低1DO 262 63628 #4FA# 740 64860
#1DO# 277 63737 中5SO 784 64898
#2RE# 311 63928 中6LA 880 64968
低3MI 330 64021 #6LA# 932 64994
低4FA 349 64103 中7SI 968 65030
#4FA# 370 64185 低1DO 1046 65058
低SO 392 64260 #1DO# 1109 65085
#5SO# 415 64331 ⾼2RE 1175 65110
低6LA 440 64400 #2RE# 1245 65134
#6LA# 466 64463 ⾼3MI 1318 65157
低7SI 494 64524 ⾼4FA 1397 65178
中1DO 523 64580 #4FA# 1490 65198
#1DO# 554 64633 ⾼5SO 1568 65217
中2RE 587 64633 #5SO# 1661 65235
#2RE# 622 64884 ⾼6LA 1760 65252
中3MI 659 64732 #6LA# 1865 65268
中4FA 698 64820 ⾼7SI 1967 65283
T的值决定了TH0和TL0的值,其关系为:TH0=T/256,TL0=T%256 3.2软件框图及部分代码
(1)总程序简易流程图如图3-1:
图 3-1 总程序简易流程图
(2)显⽰流程图如图3-2:
键盘扫描程序
有键按下
赋键值
功能键地址转移程序
取键值
A>17H
A>1A
转⾄⾳⾊调节
转⾄弹奏
转⾃动播放
N
Y
Y N
N
R1=0
根据R1的值查表
查表获得的数据送P0
延时0.2秒
R1=R1+1
R1的内容=10
图3-2显⽰流程图
C语⾔源程序
#include
#define uchar unsigned char
#define uint unsigned int
unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66, 0x6d,0x7d,0x07,0x7f,0x6f}; unsigned char discount; void delay02s(void)
{
unsigned char i, j, k;
for(i=20;i>0;i--)
for(j=20;j>0;j--)
for(k=248;k>0;k--);
}
void main(void)
{
while(1)
{
for(discount=0;dispcount<10;dispcount++)
{
P0=table[discount];
delay02s();
}}}
(3)键盘识别程序框图如图3-3所⽰:
图3-3键盘识别程序框图
语⾔源程序
#include
unsigned char code table[]=table[]={0x3f,0x06,0x5b,0x4f,
unsigned char key;
unsigned char i,j;
void main(void) {
while(1)
{P3=0xff;
P3_4=0;
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--); temp=P3;
temp=temp & 0x0f; if (temp!=0x0f) {
temp=P3;
temp=temp & 0x0f; switch(temp)
{
case 0x0e:
key=7;
break;
case 0x0d:
key=8;
break;
case 0x0b:
key=9;
break;
case 0x07:
key=10;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key]; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3;
temp=temp & 0x0f; }
}
P3=0xff;
P3_5=0;
temp=P3;
temp=temp & 0x0f; if (temp!=0x0f) {
for(i=50;i>0;i--)
for(j=200;j>0;j--); temp=P3;
temp=temp & 0x0f; {
temp=P3;
temp=temp & 0x0f; switch(temp)
{
case 0x0e: key=4; break;
case 0x0d: key=5; break;
case 0x0b: key=6; break;
case 0x07: key=11; break; }
temp=P3;
P1_0=~P1_0;
P0=table[key]; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f; }
}
}
P3=0xff;
P3_6=0;
temp=P3;
temp=temp & 0x0f; if (temp!=0x0f) { for(i=50;i>0;i--)
for(j=200;j>0;j--); temp=P3;
temp=temp & 0x0f; if (temp!=0x0f) { temp=P3;
temp=temp & 0x0f; switch(temp)
{
case 0x0e: key=1; break;
case 0x0d: key=2; break;
case 0x0b: key=3;
break;
case 0x07: key=12; break;
temp=P3;
P1_0=~P1_0;
P0=table[key]; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3;
temp=temp & 0x0f; }
}
}
P3=0xff;
P3_7=0;
temp=P3;
temp=temp & 0x0f; if (temp!=0x0f) {
for(i=50;i>0;i--)
for(j=200;j>0;j--); temp=P3;
temp=temp & 0x0f; if (temp!=0x0f) {
temp=P3;
temp=temp & 0x0f; switch(temp) {case 0x0e:
key=0;
break;
case 0x0d:
key=13;
break;
case 0x0b:
key=14;
break;
case 0x07:
key=15;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
temp=temp & 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;}
(4)⾳乐发声程序框图如图3-4所⽰:
图3-4 ⾳乐发声程序框图
程序为:
#include
unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
unsigned char temp;
unsigned char key;
unsigned char i,j;
unsigned char STH0;
unsigned char STL0;
unsigned int code tab[]={64021,64103,64260,64400, 64524,64580,64684,64777, 64820,64898,64968,65030, 65058,65110,65157,65178};
void main(void)
{
TMOD=0x01;
ET0=1;
EA=1;
while(1)
{
P3=0xff;
P3_4=0;
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
{
case 0x0e: key=0; break;
case 0x0d: key=1; break;
case 0x0b:
key=2;
break;
case 0x07:
key=3;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key]; STH0=tab[key]/256; STL0=tab[key]%6; TR0=1;
temp=temp & 0x0f; while(temp!=0x0f) {
temp=P3;
temp=temp & 0x0f; }
TR0=0;
}
}
P3=0xff;
P3_5=0;
temp=P3;
temp=temp & 0x0f; {
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=temp & 0x0f; if (temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f; switch(temp)
{
case 0x0e:
key=4;
break;
case 0x0d:
key=5;
break;
case 0x0b:
key=6;
break;
case 0x07:
key=7;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key]; STH0=tab[key]/256; STL0=tab[key]%6; TR0=1;
temp=temp & 0x0f; while(temp!=0x0f) {
temp=P3;
temp=temp & 0x0f; }
TR0=0;
}
P3_6=0;
temp=P3;
temp=temp & 0x0f; {
for(i=50;i>0;i--)
for(j=200;j>0;j--); temp=P3;
temp=temp & 0x0f; if (temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f; switch(temp)
{ case 0x0e: key=8; break;
case 0x0d:
key=9;
break;
case 0x0b:
key=10;
break;
case 0x07:
key=11;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key]; STH0=tab[key]/256; STL0=tab[key]%6; TR0=1;
temp=temp & 0x0f; while(temp!=0x0f)
temp=temp & 0x0f; } TR0=0;
}
}
P3=0xff;
P3_7=0;
temp=P3;
temp=temp & 0x0f; if (temp!=0x0f)
{。

相关文档
最新文档