MY1690-12P是深圳市迈优科技有限公司自主研发的一款小巧的微集成MP3模块。采用MY1690-SOP16 MP3主控芯片,支持MP3、WAV格式双解码。模块最大支持32G TF卡;也可外接U盘或USB数据线连接电脑更换SD卡音频文件。该模块内置3W功放,可以直接驱动3W的喇叭,使用更方便。
MY1690-12P内置标准UART异步串口接口,为3.3V TTL电平接口。可通过MAX3232芯片转换成RS232电平或者通过USB转TTL模块与PC通讯进行调试。通讯数据格式是:起始位:1位;数据位:8位;奇偶位:无;停止位:1位。3.3V TTL电平,波特率9600。USB转TTL模块与MY1690-12P的连接图如下。
图1 USB转TTL模块与MY1690-12P的连接图
使用电脑串口调试助手,需要正确设置串口的参数,设置如下图:
协议命令格式:
起始码 |
长度 |
操作码 |
参数 |
校验码 |
结束码 |
0x7E |
见下文 |
见下文 |
见下文 |
见下文 |
0xEF |
注意: 数据全部为十六进制数。
“长度”是指:长度+操作码+参数(有些没有参数,有些有两位参数)+校验码的个数;
“校验码”是指:长度<异或>操作码<异或>参数的值,既按顺序分别异或的值。
校验码客户可通过计算器计算得到:
例如,设置音量指令为 7E 04 3119 2C EF
长度04是这样得到:就是“04”,“31”,“19”,“2C” 4个数。
校验码2C是这样得到:
首先打开计算器选择程序员模式,然后选择16进制、双字,最后点击进行计算:
04 Xor 31 Xor19 = 2C
注:以上内容来自深圳市迈优科技的官方网站的相关资料,详细内容前往官网下载模块使用说明书,MY1690-12P的使用说明书链接:http://www.maiyout.com/col.jsp?id=103。
在实际项目中,我们通常使用这种MP3解码模块运用于语音提示的场景中。例如,当水加热达到指定温度时,关闭加热设备,并语音提示:“加热已完成!”还可以进行组合语音提示,例如,当水加热达到65摄氏度时,语音提示:“水温已达到”“六”“十”“五”“摄氏度”五段语音组合播放,但是组合播放最多连续播放20段语音文件,且对应的语音文件命名方式为:0001 XXX.mp3。
官方网站下载的程序只是串口通信+几个常用指令的例程,在实际项目中还远远不够,需要根据需要写好驱动程序。
项目中需要使用串口通信的模块有3个,而STC15F2K60S2中只有2个串口通信资源,所以需要将语音模块放置在串口1可硬件引脚切换的位置,当需要进行语音提示播放时,操作切换串口通信硬件引脚的寄存器即可,涉及到硬件引脚切换的程序如下。
/****************************************************************
STC15系列单片机串口通信硬件引脚切换
****************************************************************/
#define S1_S0 0x40 //P_SW1.6
#define S1_S1 0x80 //P_SW1.7
/************************************************************
当sw_flag=0时,P3.0/RxD, P3.1/TxD;
当sw_flag=1时,P3.6/RxD_2, P3.7/TxD_2
*************************************************************/
void UART1_switch(uchar sw_flag)
{
if(sw_flag)
{
ACC = P_SW1;
ACC &= ~(S1_S0 | S1_S1); //S1_S0=1 S1_S1=0
ACC |= S1_S0; //(P3.6/RxD_2, P3.7/TxD_2)
P_SW1 = ACC;
}
else
{
ACC = P_SW1;
ACC &= ~(S1_S0 | S1_S1); //S1_S0=0 S1_S1=0
P_SW1 = ACC; //(P3.0/RxD, P3.1/TxD)
}
}
#ifndef _MY1690_H_
#define _MY1690_H_
#include <STC15F2K60S2.H>
#include "UART.h"
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
//void send_3dat_cmd(uchar cmd,uchar jy);
//void send_4dat_cmd(uchar cmd,uchar cs,uchar jy);
void send_5dat_cmd(uchar cmd,uchar cs,uchar gq,uchar jy);
void Voice(uchar a,int b);
uchar Check(uchar cs);
#endif
#include "MY1690.h"
/******************************************************************************
- 功能描述: 串口1初始化
- 注: 设置为9600波特率
******************************************************************************/
//void Serial_init(void)
//{
// TMOD = 0x20; // 设置 T1 为波特率发生器
// SCON = 0x50; // 0101,0000 8位数据位, 无奇偶校验
// PCON = 0x00; //PCON=0;
// TH1=256-(OSC_FREQ/COMM_BAUD_RATE/32/12);//设置为9600波特率
// TL1=256-(OSC_FREQ/COMM_BAUD_RATE/32/12);
// TR1 = 1; //定时器1打开
// REN = 1; //串口1接收使能
// ES = 1; //串口1中断使能
//}
//
/*********************************************************************************
* 【函 数 名】: void write_COM(uchar dat)
* 【功 能】: 串口发送数据命令
**********************************************************************************/
//void write_COM(uchar dat)
//{
// SBUF=dat; //发送指令到SBUF
// while(!TI); //等待发送结束
// TI=0; //清除结束标志,以便再发送数据
//}
/*********************************************************************************
* 【函 数 名】: void send_3dat_cmd(uchar cmd,uchar dat)
* 【功 能】: 除了起始和结束标志外,发三位长度的数据
*send_3dat_cmd(0x11,0x12); // 播放
*send_3dat_cmd(0x12,0x11); //暂停
* send_3dat_cmd(0x13,0x10); // 下一曲
* send_3dat_cmd(0x14,0x17); //上一曲
*send_3dat_cmd(0x15,0x16); //音量加
*send_3dat_cmd(0x16,0x15); //音量减
* send_3dat_cmd(0x1A,0x19); //快进
*send_3dat_cmd(0x1B,0x18); //快退
* send_3dat_cmd(0x1C,0x1F); //播放/暂停
**********************************************************************************/
//void send_3dat_cmd(uchar cmd,uchar jy)
//{
// write_COM(0x7E); //发送“开始命令”到SBUF
// write_COM(0x03); //发送“命令长度”到SBUF
// write_COM(cmd); //发送“命令”到SBUF
// write_COM(jy); // 发送校验码到SBUF
// write_COM(0xEF); //发送“结束指令”到SBUF
//}
/*********************************************************************************
* 【函 数 名】: void send_4dat_cmd(uchar cmd,uchar cs,uchar jy )
* 【功 能】: 除了起始和结束标志外,发四位长度的数据
* send_4dat_cmd(0x32,0x00,0x36 ) ; //设置EQ
* send_4dat_cmd(0x34,0x01,0x31 ) ; //文件切换
* send_4dat_cmd(0x35,0x01,0x30 ) ; //设备切换
**********************************************************************************/
//void send_4dat_cmd(uchar cmd,uchar cs,uchar jy )
//{
// write_COM(0x7E); //发送“开始命令”到SBUF
// write_COM(0x04); //发送“命令长度”到SBUF
// write_COM(cmd); //发送“插播指令”到SBUF
// write_COM(cs); // 发送参数 到SBUF
// write_COM(jy); // 发送校验码到SBUF
// write_COM(0xEF); //发送“结束指令”到SBUF
//}
/*********************************************************************************
* 【函 数 名】: void send_5dat_cmd(uchar cmd,uchar cs,uchar gq,uchar jy )
* 【功 能】: 除了起始和结束标志外,发四位长度的数据
* send_5dat_cmd(0x43,0x00,0x03,0x45); //插播功能
* send_5dat_cmd(0x44,0x01,0x06,0x46) ; //插播指定文件夹的歌曲播放,本指令为文件夹01的第6首歌曲
**********************************************************************************/
void send_5dat_cmd(uchar cmd,uchar cs,uchar gq,uchar jy )
{
write_COM(0x7E); //发送“开始命令”到SBUF
write_COM(0x05); //发送“命令长度”到SBUF
write_COM(cmd); //发送“插播指令”到SBUF
write_COM(cs); // 发送参数 到SBUF
write_COM(gq); //发送第几首歌曲到SBUF
write_COM(jy); // 发送校验码到SBUF
write_COM(0xEF); //发送“结束指令”到SBUF
}
/*********************************************************************************
* 【函 数 名】: Voice(a,b)
* 【功 能】:
a(0:温度 1:水量 2:叫水)
b(温度:0:加热开始 1:加热完成;
水量:0:已换新水 2:水已不足;
叫水:宿舍号)
例如:Voice(2,1517);//语音提示:你好,请送水到1517。
Voice(0,0);//语音提示:加热开始!
Voice(1,0);//语音提示:已换上新的饮用水!
**********************************************************************************/
void Voice(uchar a,int b)
{
uchar check_flag = 0x00,check1 = 0x00,check2 = 0x00,check3 = 0x00,check4 = 0x00;//校验码
uchar Voice_number[] = {0,0,0,0};//宿舍号
uchar i=0;
UART1_switch(1);//uart1切换到P3^6\P3^7
if(a == 0)//温度部分
{
if(b == 0)//加热开始 语音提示
{
check_flag = Check(0x0C);//校验码计算
send_5dat_cmd(0x41,0x00,0x0C,check_flag);//播放加热开始(0012)语音文件
}
if(b == 1)//加热完成 语音提示
{
check_flag = Check(0x0B);//校验码计算
send_5dat_cmd(0x41,0x00,0x0B,check_flag);//播放加热开始(0011)语音文件
}
}
else if(a == 1)//水量部分
{
if(b == 0)//已换新水 语音提示
{
check_flag = Check(0x0E);//校验码计算
send_5dat_cmd(0x41,0x00,0x0E,check_flag);//播放已换新水(0014)语音文件
}
if(b == 1)//水已不足 语音提示
{
check_flag = Check(0x0D);//校验码计算
send_5dat_cmd(0x41,0x00,0x0D,check_flag);//播放水已不足(0013)语音文件
}
}
else if(a == 2)//叫水部分
{
check_flag = Check(0x0F);//校验码计算
Voice_number[0] = b/1000%10;
Voice_number[1] = b/100%10;
Voice_number[2] = b/10%10;
Voice_number[3] = b%10;
for(i=0;i<4;i++)//如果结果是0x00,因为数字0对应的文件是0x10,所以要加0x10
{
if(Voice_number[i] == 0)
Voice_number[i] = Voice_number[i]+0x10;
}
check1 = Check(Voice_number[0]);//校验码计算
check2 = Check(Voice_number[1]);//校验码计算
check3 = Check(Voice_number[2]);//校验码计算
check4 = Check(Voice_number[3]);//校验码计算
send_5dat_cmd(0x41,0x00,0x0F,check_flag);//播放请送水到(0015)语音文件
send_5dat_cmd(0x41,0x00,Voice_number[0],check1);//播放宿舍号
send_5dat_cmd(0x41,0x00,Voice_number[1],check2);
send_5dat_cmd(0x41,0x00,Voice_number[2],check3);
send_5dat_cmd(0x41,0x00,Voice_number[3],check4);
// check_flag = Check(0x0F);//校验码计算
// send_5dat_cmd(0x41,0x00,0x0F,check_flag);//播放请送水到(0015)语音文件
// send_5dat_cmd(0x41,0x00,Voice_number[0],check1);//播放两遍宿舍号
// send_5dat_cmd(0x41,0x00,Voice_number[1],check2);
// send_5dat_cmd(0x41,0x00,Voice_number[2],check3);
// send_5dat_cmd(0x41,0x00,Voice_number[3],check4);
}
else //系统出错
// buzz = 0;//蜂鸣器报警,出错
{
}
UART1_switch(0);//uart1重新初始化
check_flag = 0x00,check1 = 0x00,check2 = 0x00,check3 = 0x00,check4 = 0x00;
}
/*********************校验码算法****************************/
uchar Check(uchar jy)//校验码计算(异或运算)
{
jy = jy^0x44;
return jy;
}