/*
这个音乐模块,是一个串口控制的模块,我们提供的有串口命令手册,内存卡插上之后,想让模块去播放哪个音乐,加减音量,可以
通过串口命令去控制模块完成这写功能。
*/
#include<reg52.h> //头文件
#define uchar unsigned char //简化宏定义
#define uint unsigned int //简化宏定义
#define LCD1602_dat P0 //LCD1602数据脚
uchar code ss[]= //LCD1602显示特殊符号去模数组
{
0x00,0x00,0x0E,0x0E,0x0E,0x0E,0x00,0x00,/*"停止",0*/
0x00,0x00,0x0A,0x0A,0x0A,0x0A,0x00,0x00,/*"暂停",0*/
0x00,0x08,0x0C,0x0E,0x0F,0x0E,0x0C,0x08,/*"播放",0*/
0x00,0x00,0x03,0x03,0x03,0x03,0x00,0x00,/*"喇叭01",0*/
0x04,0x0C,0x1C,0x1C,0x1C,0x1C,0x0C,0x04,/*"喇叭02",0*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
/*
1602液晶,是常用的显示器件,一共是16个管脚,其中有八个管脚是数据传输管脚,有三个管脚是数据命令使能端管脚,还有两组电源管脚,
其中一组电源管脚是给整个液晶进行供电的,还有一组电源是单纯的背景光电源,还剩下的最后一个管脚是对比度调节管脚,一般接上一个3K电
阻再接地即可。
一般我们用的函数,无非就是 LCD1602_write 和 LCD1602_writebyte
LCD1602_write(x,y); 这个函数括号里面可以填写两个数据,第一个数据只能是 0 1 ,是0就说明第二个数据对液晶来说就是命令,填1就说明
第二个数据对于液晶来说就是要显示的数据。
LCD1602_writebyte(); 这个函数里面直接填上要显示的字符串即可,自动进行显示
*/
/*
数据显示的时候一般的处理:
首先,无论是数码管显示还是液晶显示,进行显示的时候绝对都是一个一个进行显示的,那么,比如说一个数据123,一百二十三,
进行显示的时候,要先显示1,然后是2,然后是3,那么怎么把数据提取出来??
提取百位 123/100=1
提取十位 123/10=12 12%10=2 “%”是取余的意思,像这个,就是12对10取余,换句话说,12除以10,然后取余数,就是2
提取个位 123%10=3 解释同上
取余的用法也有很多种,大家只要知道出现这个的时候,一般都是进行数据提取的就行
然后
如果您是数码管显示数据,将提取的数据放到段码数组里面送给IO即可,
如果是液晶显示,需要将数据转化成字符,因为液晶是字符屏,只能显示字符数据,数据0对应的字符是0x30,数据1对应的字符是0x31,
所以将提取出的数据直接加上0x30送给液晶即可,或者加上'0' 也是一样的
*/
sbit LCD1602_rs=P2^5; //LCD1602控制脚
sbit LCD1602_rw=P2^6; //LCD1602控制脚
sbit LCD1602_e=P2^7; //LCD1602控制脚
uint times,timer;
uchar dat[20],bz,time,ACIS,shu[4],bits,vox=15;
uchar sec,min,min1,sec1,mode,vol=15,state,EQ,ms;
uint sum,sum_song;
bit SD,Again,wc;
uchar once;
/********************************************************************
* 名称 : delay()
* 功能 : 小延时。
* 输入 : 无
* 输出 : 无
***********************************************************************/
void delay(uint T)
{
while(T--);
}
/********************************************************************
* 名称 : LCD1602_write(uchar order,dat)
* 功能 : 1602写如数据函数
* 输入 : 输入的命令值
* 输出 : 无
***********************************************************************/
void LCD1602_write(uchar order,dat) //1602 一个字节 处理 order为命令与数据选择 dat为写的数据内容
{
LCD1602_rs=order;
LCD1602_dat=dat;
LCD1602_e=1;
delay(1);
LCD1602_e=0;
}
/********************************************************************
* 名称 : LCD1602_writebye(uchar *prointer)
* 功能 : 1602写入数据函数 指针式
* 输入 : 输入的命令值
* 输出 : 无
***********************************************************************/
void LCD1602_writebyte(uchar *prointer) //1602 字符串 处理
{
while(*prointer!='\0')
{
LCD1602_write(1,*prointer);
prointer++;
}
}
/********************************************************************
* 名称 : LCD1602_Save(uchar add,uchar *pic_num) add为地址 pic_num 为存储数据
* 功能 : 自定义字符 地址为0~7
* 输入 : 无
* 输出 : 无
***********************************************************************/
void LCD1602_Save(uchar *pic_num)
{
uchar a1;
uchar a2;
uchar add;
for(a1=0;a1<8;a1++)
{
add=a1<<3;
for(a2=0;a2<8;a2++)
{
LCD1602_write(0,0x40|add+a2);
LCD1602_write(1,*pic_num++);
}
}
}
/********************************************************************
* 名称 : LCD1602_cls()
* 功能 : 初始化1602液晶
* 输入 : 无
* 输出 : 无
***********************************************************************/
void LCD1602_cls() //1602 初始化
{
LCD1602_rw=0;
LCD1602_write(0,0x01); //1602 清屏 指令
delay(1500);
LCD1602_write(0,0x38); // 功能设置 8位、5*7点阵
delay(1500);
LCD1602_write(0,0x0c); //设置 光标 不显示开关、不显示光标、字符不闪烁
LCD1602_write(0,0x06);
LCD1602_write(0,0xd0);
delay(1500);
LCD1602_write(0,0x80);
LCD1602_writebyte(" MP3_Init ");
}
/********************************************************************
* 名称 : void write_send(uchar dat)
* 功能 : 串口数据发送函数
* 输入 : 需要发送的数据 dat
* 输出 : 无
***********************************************************************/
void write_send(uchar dat)
{
SBUF=dat;
while(!TI); //数据发送接受判断
TI=0; //置0
}
/********************************************************************
* 名称 : void send_6(uchar a1,a2,a3,a4,a5,a6)
* 功能 : 串口数据串发送6位数据
* 输入 : a1————a6 发送数据的内容
* 输出 : 无
***********************************************************************/
void send_6(uchar a1,a2,a3,a4,a5,a6)
{
uchar a7;
write_send(a1);
write_send(a2);
write_send(a3);
write_send(a4);
a7=a2^a3^a4; //求校验位
write_send(a7);
write_send(a6);
}
/********************************************************************
* 名称 : void send_5(uchar a1,a2,a3,a4,a5)
* 功能 : 串口数据串发送5位数据
* 输入 : a1————a5 发送数据的内容
* 输出 : 无
***********************************************************************/
void send_5(uchar a1,a2,a3,a4,a5)
{
uchar a6;
write_send(a1);
write_send(a2);
write_send(a3);
a6=a2^a3; //求校验位
write_send(a6);
write_send(a5);
}
/********************************************************************
* 名称 : void show()
* 功能 : 系统显示函
* 输入 : 无
* 输出 : 无
***********************************************************************/
void show()
{
LCD1602_write(0,0x80); //LCD1602显示内容位置设定
LCD1602_write(1,0x30+min/10%10); //显示当前播放时间分
LCD1602_write(1,0x30+min%10);
LCD1602_writebyte(":");
LCD1602_write(1,0x30+sec/10%10); //显示当前时间播放秒
LCD1602_write(1,0x30+sec%10);
LCD1602_writebyte("-");
LCD1602_write(1,0x30+min1/10%10); //总时间分
LCD1602_write(1,0x30+min1%10);
LCD1602_writebyte(":");
LCD1602_write(1,0x30+sec1/10%10); //总时间秒
LCD1602_write(1,0x30+sec1%10);
LCD1602_writebyte(" ");
LCD1602_write(1,3);
LCD1602_write(1,4);
LCD1602_write(1,0x30+vox/10%10);//显示当前音量
LCD1602_write(1,0x30+vox%10);
LCD1602_write(0,0xC0); //LCD1602显示内容位置设定
LCD1602_write(1,0x30+sum_song/100%10); //显示总歌曲数
LCD1602_write(1,0x30+sum_song/10%10);
LCD1602_write(1,0x30+sum_song%10);
LCD1602_writebyte("/");
LCD1602_write(1,0x30+sum/100%10); //显示当前歌曲数
LCD1602_write(1,0x30+sum/10%10);
LCD1602_write(1,0x30+sum%10);
LCD1602_writebyte(" ");
/*
N -- NO 原音
P -- POP 流行音乐
R -- ROCK 摇滚
J -- JAZZ 爵士
C -- CLASSIC 古典
B -- BASS 低音效
*/
switch(EQ) //判断显示当前音效
{
case 0:
LCD1602_writebyte("N"); //显示当前音效
break;
case 1:
LCD1602_writebyte("P"); //显示当前音效
break;
case 2:
LCD1602_writebyte("R"); //显示当前音效
break;
case 3:
LCD1602_writebyte("J"); //显示当前音效
break;
case 4:
LCD1602_writebyte("C"); //显示当前音效
break;
case 5:
LCD1602_writebyte("B"); //显示当前音效
break;
}
LCD1602_writebyte(" ");
switch(state) //系统状态显示
{
case 0:
LCD1602_write(1,0);
break;
case 1:
LCD1602_write(1,2);
break;
case 2:
LCD1602_write(1,1);
break;
}
LCD1602_writebyte(" ");
/*
N -- NO 无循环(播放完当前歌曲停止)
A -- ALL 全盘循环
F -- FOLDER 文件夹循环
O -- ONE 单曲循环
R -- RANDOM 随机播放
*/
switch(mode) //显示系统循环模式
{
case 0:
LCD1602_writebyte("A"); //系统循环模式
break;
case 1: //系统循环模式
LCD1602_writebyte("F");
break;
case 2:
LCD1602_writebyte("O"); //系统循环模式
break;
case 3:
LCD1602_writebyte("R");
break; //系统循环模式
case 4:
LCD1602_writebyte("N"); //系统循环模式
break;
}
LCD1602_writebyte(" ");
if(SD==0) //显示当前应用的设备
{
LCD1602_writebyte("U"); //U盘
}else
{
LCD1602_writebyte("S"); //SD卡
}
}
/********************************************************************
* 名称 : void read_dat()
* 功能 : 读取系统状态数据
* 输入 : 无
* 输出 : 无
***********************************************************************/
void read_dat()
{
if(state!=1&&ACIS>7) ACIS=0; //循环检测
switch(ACIS)
{
case 0:
send_5(0x7E,0x03,0x13,0x01,0xEF);// 播放模式
break;
case 1:
send_5(0x7E,0x03,0x12,0x01,0xEF);// 查看 当前EQ 音效
break;
case 7:
send_5(0x7E,0x03,0x10,0x01,0xEF);// 播放状态
break;
case 2:
send_5(0x7E,0x03,0x1C,0x01,0xEF);// 歌曲播放时间
break;
case 3:
send_5(0x7E,0x03,0x1D,0x01,0xEF);// 歌曲总时间
break;
case 4:
send_5(0x7E,0x03,0x18,0x01,0xEF);// 查看当前设备 U S
break;
case 5:
if(SD==1)
{
send_5(0x7E,0x03,0x15,0x01,0xEF); //SD 卡总曲目
}else
{
send_5(0x7E,0x03,0x16,0x01,0xEF); //U盘 总曲目
}
break;
case 6:
if(SD==1)
{
send_5(0x7E,0x03,0x19,0x01,0xEF); //SD播放当前曲目数
}else
{
send_5(0x7E,0x03,0x1A,0x01,0xEF); //U盘当前曲目
}
break;
}
}
/********************************************************************
* 名称 : void key()
* 功能 : 系统按键处理函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void key()
{
uchar fs=255; //暂存按键数据变量
P1=0xff;
if(P1!=0xff) //判断是否有按键按下
{
delay(1000); //按键延时去抖
P1=0xff;
if(P1!=0xff) //再次判断 是否有按键按下
{
fs=P1;
time=0;
P1=0xff;
while(P1!=0xff) //等待按键释放 松开
{
if(time>39&&Again==0)
{
Again=1;
// time=40;
switch(fs) //判断按下的按键
{
case 0xfe: //音量++++
if(vol<20) vol=15;
if(vox<20) vox++;
send_6(0x7E,0x04,0x31,vox,0x22,0xEF);
break;
case 0xfd: //音量-----
if(vol>0) vol=15;
if(vox>0) vox--;
send_6(0x7E,0x04,0x31,vox,0x22,0xEF);
break;
case 0xfb: //快进
times+=28;
if(times>timer) times=timer;
min=times/600;
sec=times/10%60;
send_5(0x7E,0x03,0x0A,0x09,0xEF);
break;
case 0xf7: //快退
if(times>27)times-=28;
else times=0;
min=times/600;
sec=times/10%60;
send_5(0x7E,0x03,0x0B,0x08,0xEF);
break;
}
}
show();//调出显示函数
}
switch(fs)
{
case 0xfe:
if(time<40) //上一曲
{
send_5(0x7E,0x03,0x04,0x07,0xEF);
state=1;
once=1;
ACIS=6;
}
break;
case 0xfd:
if(time<40) //下一曲
{
send_5(0x7E,0x03,0x03,0x00,0xEF);
state=1;
once=1;
ACIS=6;
}
break;
case 0xfb:
if(time<40)
{ //快进
times+=27;
if(times>timer) times=timer;
min=times/600;
sec=times/10%60;
send_5(0x7E,0x03,0x0A,0x09,0xEF);
}
break;
case 0xf7:
if(time<40) //快退
{
if(times>26)times-=27;
else times=0;
min=times/600;
sec=times/10%60;
send_5(0x7E,0x03,0x0B,0x08,0xEF);
}
break;
case 0xef: //模式切换
if(state==2|state==0)
{
state=1;
send_5(0x7E,0x03,0x01,0x02,0xEF);
}else
{
state=2;
send_5(0x7E,0x03,0x02,0x01,0xEF);
}
break;
case 0xdf: //停止
state=0;
send_5(0x7E,0x03,0x0E,0x0D,0xEF);
break;
case 0xbf: //音效
EQ=(EQ+1)%6;
send_6(0x7E,0x04,0x32,EQ,0x36,0xEF);
break;
case 0x7f: //模式切换
mode=(mode+1)%5;
send_6(0x7E,0x04,0x33,mode,0x35,0xEF);
break;
}
}
}
}
/********************************************************************
* 名称 :void main()
* 功能 : 主函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void main()
{
TMOD=0x21; //定时器初始化
TH1=0xfd; //波特率 9600 初始化
TL1=0xfd;
TH0=0x3c; //定时器0定时初值
TL0=0xb0;
SCON=0x50; //发送接收
EA=1; //打开终端
ES=1; //打开串口中断
ET0=1; //打开定时器0
TR1=1;
LCD1602_cls(); //LCD1602初始化
LCD1602_Save(ss); //LCD1602存储符号
TR0=1;
send_6(0x7E,0x04,0x31,15,0x22,0xEF); //音量设置
while(1)
{
times=min*600+sec*10; //当前时间计算
timer=min1*600+sec1*10; //总歌曲时间计算
show(); //显示函数调用
key(); //按键函数调用
read_dat(); //读取系统状态
}
}
/********************************************************************
* 名称 :void main()
* 功能 : 主函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void init_1() interrupt 1
{
TH0=0x3c; //重新附定时器初值
TL0=0xb0;
time++; //计时变量计时自+++
if(time>40&&time%5==0) //按键长按处理
{
Again=0;
}
if(time>99) time=60; //按键长按处理
ms++;
if((ms==5|ms==15)&&state==1) //定时读取系统状态
{
ACIS=2; //读取系统状态
}
if(ms==10&&once!=0)
{
if(once==1)ACIS=6;
else if(once==2) ACIS=3;
once++;
if(once>2) once=0;
}
if(ms>19) //定时一秒 50模式*20 ===1000ms
{
ms=0;
if(state==1&&once==0) ACIS=7;
else if(once!=0)
{
if(once==1)ACIS=6;
else if(once==2) ACIS=3;
once++;
if(once>2) once=0;
}
}
}
/********************************************************************
* 名称 : void init_4() interrupt 4
* 功能 : 串口中断函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void init_4() interrupt 4
{
if(RI) //中断标志位
{
RI=0; //置0
dat[bz]=SBUF; //缓冲暂存数据
switch(bz) //判断数据内容
{
case 0:
if(dat[bz]=='O') //OK 判断
{
bz=1;
}else if(dat[bz]=='S') //STOP 判断
{
bz=10;
}else
{
bz=0;
}
break;
case 1:
if(dat[bz]=='K') //OK 判断
{
bz=2;
bits=0;
}else
{
bz=0;
}
break;
case 2:
if(dat[bz]==0x0D)
{
bz=3;
}else
{
if(dat[bz]<=0x39)shu[bits]=dat[bz]-0x30;
else shu[bits]=dat[bz]-0x61+10;
bits++;
if(bits>4)
{
bits=0;
bz=0;
}
}
break;
case 3:
switch(ACIS) //判断MP3模块返回的数据内容
{
case 0:
mode=shu[0]*4096+shu[1]*256+shu[2]*16+shu[3];//循环模式
break;
case 1:
EQ=shu[0]*4096+shu[1]*256+shu[2]*16+shu[3]; //音效
break;
case 2:
min=(shu[0]*4096+shu[1]*256+shu[2]*16+shu[3])/60; //当前播放时间
sec=(shu[0]*4096+shu[1]*256+shu[2]*16+shu[3])%60;
break;
case 3:
min1=(shu[0]*4096+shu[1]*256+shu[2]*16+shu[3])/60; //系统总时间
sec1=(shu[0]*4096+shu[1]*256+shu[2]*16+shu[3])%60;
break;
case 4:
SD=shu[0]*4096+shu[1]*256+shu[2]*16+shu[3]; //播放外接设备
break;
case 5:
sum=shu[0]*4096+shu[1]*256+shu[2]*16+shu[3]; //当前歌曲序号
break;
case 6:
sum_song=shu[0]*4096+shu[1]*256+shu[2]*16+shu[3]; //总的歌曲数
break;
case 7:
state=shu[0]*4096+shu[1]*256+shu[2]*16+shu[3]; //系统状态
if(state>2) state=1;
break;
}
if(state!=1) ACIS=(ACIS+1)%8;
else ACIS=8;
bz=0;
break;
case 10:
if(dat[bz]=='T') //STOP 判断
{
bz=11;
}else
{
bz=0;
}
break;
case 11:
if(dat[bz]=='O') //STOP 判断
{
bz=12;
}else
{
bz=0;
}
break;
case 12:
if(dat[bz]=='P') //STOP 判断
{
state=2;
bz=0;
}else
{
bz=0;
}
break;
}
}
}
你好,我是有问必答小助手,非常抱歉,本次您提出的有问必答问题,技术专家团超时未为您做出解答
本次提问扣除的有问必答次数,将会以问答VIP体验卡(1次有问必答机会、商城购买实体图书享受95折优惠)的形式为您补发到账户。
因为有问必答VIP体验卡有效期仅有1天,您在需要使用的时候【私信】联系我,我会为您补发。