一、原理图
二、源代码
LD3320.c
#include "ld3320.h"
#include "delay.h"
#include "usart.h"
#include "string.h"
u8 ld3320Data;
extern u8 nAsrStatus;
unsigned long nMp3StartPos=0;
unsigned long nMp3Size=0;
unsigned long nMp3Pos=0;
u8 bMp3Play=0; // 用来记录播放MP3的状态
u8 nLD_Mode = LD_MODE_IDLE; // 用来记录当前是在进行ASR识别还是在播放MP3
u8 ucRegVal;
u8 ucHighInt;
u8 ucLowInt;
u8 ucStatus;
u8 ucSPVol=15; // MAX=15 MIN=0 // Speaker喇叭输出的音量
void ld3320_init()
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE); //使能PB,PE端口时钟
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_15);
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_14|GPIO_Pin_15);
LD3320_MD=0; //选择并口
LD3320_RST=1;
LD3320_A0=0;
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能复用功能时钟
// 中断线以及中断初始化配置 下降沿触发
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource11);
EXTI_InitStructure.EXTI_Line=EXTI_Line11;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //使能外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; //抢占优先级0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
//外部中断服务程序
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line11)!= RESET )
{
ld3320_process_init();
EXTI_ClearFlag(EXTI_Line11);
EXTI_ClearITPendingBit(EXTI_Line11);//清除LINE上的中断标志位
}
}
void ld3320_write_reg( unsigned char address, unsigned char dataout )
{
ld3320Data=address;
LD3320_D0=bita0;LD3320_D1=bita1;LD3320_D2=bita2;LD3320_D3=bita3;
LD3320_D4=bita4;LD3320_D5=bita5;LD3320_D6=bita6;LD3320_D7=bita7;
delay_us(1);
LD3320_A0 =1;
LD3320_CS = 0;
LD3320_WR = 0;
LD3320_WR = 1;
LD3320_CS = 1;
ld3320Data=dataout;
LD3320_D0=bita0;LD3320_D1=bita1;LD3320_D2=bita2;LD3320_D3=bita3;
LD3320_D4=bita4;LD3320_D5=bita5;LD3320_D6=bita6;LD3320_D7=bita7;
delay_us(1);
LD3320_A0 = 0;
LD3320_CS = 0;
LD3320_WR = 0;
LD3320_WR = 1;
LD3320_CS = 1;
}
unsigned char ld3320_read_reg( unsigned char address )
{
unsigned char datain;
ld3320Data=address;
LD3320_D0=bita0;LD3320_D1=bita1;LD3320_D2=bita2;LD3320_D3=bita3;
LD3320_D4=bita4;LD3320_D5=bita5;LD3320_D6=bita6;LD3320_D7=bita7;
LD3320_A0 = 1;
delay_us(1);
LD3320_CS = 0;
delay_us(1);
LD3320_WR = 0;
delay_us(1);
LD3320_WR = 1;
delay_us(1);
LD3320_CS = 1;
delay_us(1);
LD3320_A0 = 0;
delay_us(1);
LD3320_CS = 0;
delay_us(1);
LD3320_RD = 0;
LD3320_DATA_IN();
delay_us(1);
bita0=LD3320_D0_R;bita1=LD3320_D1_R;bita2=LD3320_D2_R;bita3=LD3320_D3_R;
bita4=LD3320_D4_R;bita5=LD3320_D5_R; bita6=LD3320_D6_R;bita7=LD3320_D7_R;
datain= ld3320Data;
LD3320_DATA_OUT();
LD3320_RD = 1;
delay_us(1);
LD3320_CS = 1;
return datain;
}
void ld3320_reset()
{
LD3320_RST=1;
delay_ms(1);
LD3320_RST=0;
delay_ms(1);
LD3320_RST=1;
delay_ms(1);
LD3320_CS=0;
delay_ms(1);
LD3320_CS=1;
delay_ms(1);
}
u8 ld3320_check()
{
u8 a[3];
memset(a,0x00,sizeof(a));
ld3320_reset();
delay_ms(1);
ld3320_read_reg(0x06);
delay_ms(1);
ld3320_write_reg(0x35, 0x33);
delay_ms(1);
ld3320_write_reg(0x1b, 0x55);
delay_ms(1);
ld3320_write_reg(0xb3, 0xaa);
a[0]=ld3320_read_reg(0x35);
delay_ms(5);
a[1]=ld3320_read_reg(0x1b);
delay_ms(5);
a[2]=ld3320_read_reg(0xb3);
if(a[0]!=0x33||a[1]!=0x55||a[2]!=0xaa)
return 1;
return 0;
}
void ld3320_init_common()
{
bMp3Play = 0;
ld3320_read_reg(0x06);
ld3320_write_reg(0x17, 0x35);
delay_ms(10);
ld3320_read_reg(0x06);
ld3320_write_reg(0x89, 0x03);
delay_ms(5);
ld3320_write_reg(0xCF, 0x43);
delay_ms(5);
ld3320_write_reg(0xCB, 0x02);
/*PLL setting*/
ld3320_write_reg(0x11, LD_PLL_11);
if (nLD_Mode == LD_MODE_MP3)
{
ld3320_write_reg(0x1E, 0x00);
ld3320_write_reg(0x19, LD_PLL_MP3_19);
ld3320_write_reg(0x1B, LD_PLL_MP3_1B);
ld3320_write_reg(0x1D, LD_PLL_MP3_1D);
}
else
{
ld3320_write_reg(0x1E,0x00);
ld3320_write_reg(0x19, LD_PLL_ASR_19);
ld3320_write_reg(0x1B, LD_PLL_ASR_1B);
ld3320_write_reg(0x1D, LD_PLL_ASR_1D);
}
delay_ms(10);
ld3320_write_reg(0xCD, 0x04);
ld3320_write_reg(0x17, 0x4c);
delay_ms(5);
ld3320_write_reg(0xB9, 0x00);
ld3320_write_reg(0xCF, 0x4F);
ld3320_write_reg(0x6F, 0xFF);
}
void ld3320_init_mp3()
{
nLD_Mode = LD_MODE_MP3;
ld3320_init_common();
ld3320_write_reg(0xBD,0x02);
ld3320_write_reg(0x17, 0x48);
delay_ms(10);
ld3320_write_reg(0x85, 0x52);
ld3320_write_reg(0x8F, 0x00);
ld3320_write_reg(0x81, 0x00);
ld3320_write_reg(0x83, 0x00);
ld3320_write_reg(0x8E, 0xff);
ld3320_write_reg(0x8D, 0xff);
delay_ms(1);
ld3320_write_reg(0x87, 0xff);
ld3320_write_reg(0x89, 0xff);
delay_ms(1);
ld3320_write_reg(0x22, 0x00);
ld3320_write_reg(0x23, 0x00);
ld3320_write_reg(0x20, 0xef);
ld3320_write_reg(0x21, 0x07);
ld3320_write_reg(0x24, 0x77);
ld3320_write_reg(0x25, 0x03);
ld3320_write_reg(0x26, 0xbb);
ld3320_write_reg(0x27, 0x01);
}
void ld3320_init_asr()
{
nLD_Mode=LD_MODE_ASR_RUN;
ld3320_init_common();
ld3320_write_reg(0xBD, 0x00);
ld3320_write_reg(0x17, 0x48);
delay_ms(10);
ld3320_write_reg(0x3C, 0x80);
ld3320_write_reg(0x3E, 0x07);
ld3320_write_reg(0x38, 0xff);
ld3320_write_reg(0x3A, 0x07);
ld3320_write_reg(0x40, 0);
ld3320_write_reg(0x42, 8);
ld3320_write_reg(0x44, 0);
ld3320_write_reg(0x46, 8);
delay_ms(10);
}
void ld3320_reload_mp3data()
{
unsigned long nCurMp3Pos;
u8 val;
u8 k;
nCurMp3Pos = nMp3StartPos + nMp3Pos;
ucStatus = ld3320_read_reg(0x06);
while ( !(ucStatus&MASK_FIFO_STATUS_AFULL) && (nMp3Pos<nMp3Size) )
{
val=0;
for(k=0;k<8;k++)
{
}
ld3320_write_reg(0x01,val);
nMp3Pos++;
ucStatus = ld3320_read_reg(0x06);
}
}
void ld3320_reload_mp3data_2()
{
unsigned long nCurMp3Pos;
u8 val;
u8 k;
nCurMp3Pos = nMp3StartPos + nMp3Pos;
//读取音乐文件写入
ucStatus = ld3320_read_reg(0x06);
while ( !(ucStatus&MASK_FIFO_STATUS_AFULL) && (nMp3Pos<nMp3Size) )
{
val=0;
nMp3Pos++;
ucStatus = ld3320_read_reg(0x06);
}
}
void ld3320_process_init()
{
u8 nAsrResCount=0;
ucRegVal = ld3320_read_reg(0x2B);
if(nLD_Mode == LD_MODE_ASR_RUN)
{
// 语音识别产生的中断
// (有声音输入,不论识别成功或失败都有中断)
ld3320_write_reg(0x29,0) ;
ld3320_write_reg(0x02,0) ;
if((ucRegVal & 0x10) &&
ld3320_read_reg(0xb2)==0x21 &&
ld3320_read_reg(0xbf)==0x35)
{
nAsrResCount = ld3320_read_reg(0xba);
if(nAsrResCount>0 && nAsrResCount<=4)
{
nAsrStatus=LD_ASR_FOUNDOK;
}
else
{
nAsrStatus=LD_ASR_FOUNDZERO;
}
}
else
{
nAsrStatus=LD_ASR_FOUNDZERO;
}
ld3320_write_reg(0x2b, 0);
ld3320_write_reg(0x1C,0);
return;
}
// 声音播放产生的中断,有三种:
// A. 声音数据已全部播放完。
// B. 声音数据已发送完毕。
// C. 声音数据暂时将要用完,需要放入新的数据。
ucHighInt = ld3320_read_reg(0x29);
ucLowInt=ld3320_read_reg(0x02);
ld3320_write_reg(0x29,0) ;
ld3320_write_reg(0x02,0) ;
if(ld3320_read_reg(0xBA)&CAUSE_MP3_SONG_END)
{
// A. 声音数据已全部播放完。
ld3320_write_reg(0x2B, 0);
ld3320_write_reg(0xBA, 0);
ld3320_write_reg(0xBC,0x0);
bMp3Play=0; // 声音数据全部播放完后,修改bMp3Play的变量
ld3320_write_reg(0x08,1);
delay_ms(5);
ld3320_write_reg(0x08,0);
ld3320_write_reg(0x33, 0);
return ;
}
if(nMp3Pos>=nMp3Size)
{
// B. 声音数据已发送完毕。
ld3320_write_reg(0xBC, 0x01);
ld3320_write_reg(0x29, 0x10);
// bMp3Play=0; // 此时,只是主控MCU把所有MP3数据发送到LD3320芯片内,但是还没有把送入的数据全部播放完毕
return;
}
// C. 声音数据暂时将要用完,需要放入新的数据。
ld3320_reload_mp3data_2();
ld3320_write_reg(0x29,ucHighInt);
ld3320_write_reg(0x02,ucLowInt) ;
}
void ld3320_play()
{
nMp3Pos=0;
bMp3Play=1;
if (nMp3Pos >= nMp3Size)
return ;
ld3320_reload_mp3data();
ld3320_write_reg(0xBA, 0x00);
ld3320_write_reg(0x17, 0x48);
ld3320_write_reg(0x33, 0x01);
ld3320_write_reg(0x29, 0x04);
ld3320_write_reg(0x02, 0x01);
ld3320_write_reg(0x85, 0x5A);
}
void ld3320_adjust_volume(u8 val)
{
ucSPVol = val;
val = ((15-val)&0x0f) << 2;
ld3320_write_reg(0x8E, val | 0xc3);
ld3320_write_reg(0x87, 0x78);
}
// Return 1: success.
u8 ld3320_check_asrbusyflag_b2()
{
u8 j;
u8 flag = 0;
for (j=0; j<10; j++)
{
if (ld3320_read_reg(0xb2) == 0x21)
{
flag = 1;
break;
}
delay_ms(10);
}
return flag;
}
void LD_AsrStart()
{
ld3320_init_asr();
}
// Return 1: success.
u8 ld3320_asrun()
{
ld3320_write_reg(0x35, MIC_VOL);
ld3320_write_reg(0x1C, 0x09);
ld3320_write_reg(0xBD, 0x20);
ld3320_write_reg(0x08, 0x01);
delay_ms( 1 );
ld3320_write_reg(0x08, 0x00);
delay_ms( 1 );
if(ld3320_check_asrbusyflag_b2() == 0)
{
return 0;
}
ld3320_write_reg(0xB2, 0xff);
ld3320_write_reg(0x37, 0x06);
delay_ms( 10 );
ld3320_write_reg(0x1C, 0x0b);
ld3320_write_reg(0x29, 0x10);
ld3320_write_reg(0xBD, 0x00);
return 1;
}
// Return 1: success.
// 添加识别关键词语,开发者可以学习"语音识别芯片LD3320高阶秘籍.pdf"中关于垃圾词语吸收错误的用法
u8 ld3320_asr_addFixed()
{
u8 k, flag;
u8 nAsrAddLength;
const char sRecog[24][30] = {"xiao hui hui",
"ni you xi fu mei",
"jiang ge gu shi",
"ni shi bu shi dan teng",
"ni ban ben hao duo shao",
"jin tian duo shao hao",
"jin tian ji hao le",
"xian zai ji dian le",
"jin nian ji sui le",
"ni sheng wa le mei",
"da kai ji dian qi yi",
"da kai ji dian qi er",
"guan bi ji dian qi yi",
"guan bi ji dian qi er",
"da kai suo you ji dian qi",
"guan bi suo you ji dian qi",
"tiao gao yin liang",
"zeng jia tin liang",
"tiao xiao yin liang",
"jiang di yin lliang",
"tiao gao yu su",
"zeng jia yu su",
"tiao xiao yu su",
"jiang di yu su",
};
const Order pCode[24] = {
name,
wife,
speakStore,
eggPain,
visionNum,
todayDate,
whyToday,
whatTime,
howOld,
haveChild,
openRelayOne,
openRelayTwo,
closeRelayOne,
closeRelayTwo,
openRelay,
closeRelay,
upVolume,
upVolume,
downVolume,
downVolume,
upSpeed,
upSpeed,
downSpeed,
downSpeed,
};
flag = 1;
for (k=0; k<24; k++)
{
if(ld3320_check_asrbusyflag_b2() == 0)
{
flag = 0;
break;
}
ld3320_write_reg(0xc1, pCode[k] );
ld3320_write_reg(0xc3, 0 );
ld3320_write_reg(0x08, 0x04);
delay_ms(1);
ld3320_write_reg(0x08, 0x00);
delay_ms(1);
for (nAsrAddLength=0; nAsrAddLength<30; nAsrAddLength++)
{
if (sRecog[k][nAsrAddLength] == 0)
break;
ld3320_write_reg(0x5, sRecog[k][nAsrAddLength]);
}
ld3320_write_reg(0xb9, nAsrAddLength);
ld3320_write_reg(0xb2, 0xff);
ld3320_write_reg(0x37, 0x04);
}
return flag;
}
u8 ld3320_get_result()
{
return ld3320_read_reg(0xc5 );
}
/************************************************************************************/
// RunASR()函数实现了一次完整的ASR语音识别流程
// LD_AsrStart() 函数实现了ASR初始化
// LD_AsrAddFixed() 函数实现了添加关键词语到LD3320芯片中
// LD_AsrRun() 函数启动了一次ASR语音识别流程
//
// 任何一次ASR识别流程,都需要按照这个顺序,从初始化开始进行
/************************************************************************************/
u8 ld3320_run_asr()
{
u8 i=0;
u8 asrflag=0;
for (i=0; i<5; i++) // 防止由于硬件原因导致LD3320芯片工作不正常,所以一共尝试5次启动ASR识别流程
{
LD_AsrStart();
delay_ms(10);
if (ld3320_asr_addFixed()==0)
{
ld3320_reset(); // LD3320芯片内部出现不正常,立即重启LD3320芯片
delay_ms(100); // 并从初始化开始重新ASR识别流程
continue;
}
delay_ms(300);
if (ld3320_asrun() == 0)
{
ld3320_reset(); // LD3320芯片内部出现不正常,立即重启LD3320芯片
delay_ms(100); // 并从初始化开始重新ASR识别流程
continue;
}
asrflag=1;
break; // ASR流程启动成功,退出当前for循环。开始等待LD3320送出的中断信号
}
return asrflag;
}
#include "ld3320