使用LD3320模块,实现用户说一句话,比如说一句"小车左转",小车就会进行左转,到后面会加SD卡模块,实现语音交互等功能.
LD3320是非特定人(不用针对指定人)语音识别芯片,即语音声控芯片。最多可以识别50条预先内置的指令。
工作模式:
LD3320(LDV7)语音模块可以工作在以下三种模式:
普通模式:直接说话,模块直接识别;
按键模式:按键触发开始ASR进程;
口令模式:需要一级唤醒词(口令);
推荐使用口令模式,这样避免嘈杂环境下误动作。
小车与STMF103接线图:
A轮 \\ ------ // B轮 TIM2
\\ ------ //
------
// ------ \\
D轮 // ------ \\ C轮 TIM3
控制ABCD四个轮子的PWM
PC6--A轮 //左前 ---- 电机驱动1-ENA
PC7--B轮 //右前 ---- 电机驱动1-ENB
PC8--C轮 //右后 ---- 电机驱动2-ENA
PC9--D轮 //左后 ---- 电机驱动2-ENB
A轮:PC1 PC0 控制前后运动 PC1----IN2,PC0----IN1
B轮:PC3 PC2 控制前后运动 PC3----IN4,PC2----IN3
C轮:PC10,PC11控制前后运动 PC10 --- IN1,PC11---IN2
D轮:PC12,PD2控制前后运动 PC12 --- IN3,PD2 ---IN4
制作出来的实物图如下:
LD332模块与单片机接线图:
LD3320 5v-----单片机的电源5v,GND----GND;
LD3320 RST----PB15
LD3320 CS---PB13
LD3320 IRQ---PB12
LD3320 CS---PA4
LD3320 SCK---PA5
LD3320 MISO----PA6
LD3320 MOSI---PA7
主要STM32单片机代码如下:
测试的时候可以串口助手进行调试.
#include "LD3320.h"
uint8 nAsrStatus = 0;
uint8 nLD_Mode = LD_MODE_IDLE;//用来记录当前是在进行ASR识别还是在播放MP3
uint8 ucRegVal;
///用户修改
void LD3320_main(void)
{
uint8 nAsrRes=0;
LD3320_init();
printf("1、小车前进\r\n");
printf("2、小车后退\r\n");
printf("3、小车右转\r\n");
printf("4、小车左转\r\n");
printf("5、小车停止\r\n");
nAsrStatus = LD_ASR_NONE;//初始状态:没有在作ASR
while(1)
{
switch(nAsrStatus)
{
case LD_ASR_RUNING:
case LD_ASR_ERROR:
break;
case LD_ASR_NONE:
nAsrStatus=LD_ASR_RUNING;
if (RunASR()==0)//启动一次ASR识别流程:ASR初始化,ASR添加关键词语,启动ASR运算
{
nAsrStatus = LD_ASR_ERROR;
}
break;
case LD_ASR_FOUNDOK:
nAsrRes = LD_GetResult( );//一次ASR识别流程结束,去取ASR识别结果
printf("\r\n识别码:%d", nAsrRes);
switch(nAsrRes) //对结果执行相关操作,客户修改
{
case CODE_XCQJ: //命令“小车前进”
printf(" 小车前进 指令识别成功\r\n");
break;
case CODE_XCHT: //命令“小车后退”
printf(" 小车后退 指令识别成功\r\n");
break;
case CODE_XCYZ: //命令“小车右转”
printf(" 小车右转 指令识别成功\r\n");
break;
case CODE_XCZZ: //命令“小车左转”
printf(" 小车左转 指令识别成功\r\n");
break;
case CODE_XCTZ: //命令“小车停止”
printf(" 小车停止 指令识别成功\r\n");
default:break;
}
nAsrStatus = LD_ASR_NONE;
break;
case LD_ASR_FOUNDZERO:
default:
nAsrStatus = LD_ASR_NONE;
break;
}//switch
//开发板测试
Board_text(nAsrRes );
}// while
}
static uint8 LD_AsrAddFixed(void)
{
uint8 k, flag;
uint8 nAsrAddLength;
#define DATE_A 5 //数组二维数值
#define DATE_B 20 //数组一维数值
//添加关键词
uint8 sRecog[DATE_A][DATE_B] = {
"xiao che qian jian",\
"xiao che hou tui",\
"xiao che you zhuan",\
"xiao che zuo zhuan",\
"xiao che ting zhi"\
};
uint8 pCode[DATE_A] = {
CODE_XCQJ, \
CODE_XCHT, \
CODE_XCYZ,\
CODE_XCZZ, \
CODE_XCTZ \
}; //添加识别码
flag = 1;
for (k=0; k<DATE_A; k++)
{
if(LD_Check_ASRBusyFlag_b2() == 0)
{
flag = 0;
break;
}
LD_WriteReg(0xc1, pCode[k] );
LD_WriteReg(0xc3, 0);
LD_WriteReg(0x08, 0x04);
LD3320_delay(1);
LD_WriteReg(0x08, 0x00);
LD3320_delay(1);
for (nAsrAddLength=0; nAsrAddLength<DATE_B; nAsrAddLength++)
{
if (sRecog[k][nAsrAddLength] == 0)
break;
LD_WriteReg(0x5, sRecog[k][nAsrAddLength]);
}
LD_WriteReg(0xb9, nAsrAddLength);
LD_WriteReg(0xb2, 0xff);
LD_WriteReg(0x37, 0x04);
}
return flag;
}
static void Board_text(uint8 Code_Val)
{
switch(Code_Val) //对结果执行相关操作
{
case CODE_XCQJ: //命令“小车前进”
car_go();
break;
case CODE_XCHT: //命令“小车后退”
car_back();
break;
case CODE_XCYZ: //命令“小车右转”
car_right();
break;
case CODE_XCZZ: //命令“小车左转”
car_left();
break;
case CODE_XCTZ: //命令“小车停止”
car_stop();
break;
default:break;
}
}
static void Delayms(uint16 i)
{
unsigned char a,b;
for(;i>0;i--)
for(b=4;b>0;b--)
for(a=113;a>0;a--);
}
static void car_go(void)
{
M1_OFF();M3_OFF();M6_OFF();M7_OFF();
M2_ON();M4_ON();M5_ON();M8_ON();
E1_ON();E2_ON();E3_ON();E4_ON();
}
static void car_back(void)
{
M2_OFF();M4_OFF();M5_OFF();M8_OFF();
M1_ON();M3_ON();M6_ON();M7_ON();
E1_ON();E2_ON();E3_ON();E4_ON();
}
static void car_right(void)
{
M3_OFF();M7_OFF();
M4_ON();M8_ON();
E2_ON();E4_ON();
}
static void car_left(void)
{
M1_OFF();M6_OFF();
M2_ON();M5_ON();;
E1_ON();E3_ON();
}
static void car_stop(void)
{
E1_OFF();E2_OFF();E3_OFF();E4_OFF();
}
///相关初始化
static void LD3320_init(void)
{
LD3320_GPIO_Cfg();
LD3320_EXTI_Cfg();
LD3320_SPI_cfg();
car_Init();
LD_reset();
}
static void LD3320_GPIO_Cfg(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(LD3320RST_GPIO_CLK | LD3320CS_GPIO_CLK,ENABLE);
//LD_CS /RSET
GPIO_InitStructure.GPIO_Pin =LD3320CS_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LD3320CS_GPIO_PORT,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin =LD3320RST_PIN;
GPIO_Init(LD3320RST_GPIO_PORT,&GPIO_InitStructure);
}
static void LD3320_EXTI_Cfg(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
RCC_APB2PeriphClockCmd(LD3320IRQ_GPIO_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin =LD3320IRQ_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LD3320IRQ_GPIO_PORT, &GPIO_InitStructure);
//外部中断线配置
GPIO_EXTILineConfig(LD3320IRQEXIT_PORTSOURCE, LD3320IRQPINSOURCE);
EXTI_InitStructure.EXTI_Line = LD3320IRQEXITLINE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger =EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
//中断嵌套配置
NVIC_InitStructure.NVIC_IRQChannel = LD3320IRQN;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
static void LD3320_SPI_cfg(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//spi端口配置
RCC_APB2PeriphClockCmd(LD3320SPI_CLK,ENABLE);
RCC_APB2PeriphClockCmd(LD3320WR_GPIO_CLK | LD3320SPIMISO_GPIO_CLK | LD3320SPIMOSI_GPIO_CLK | LD3320SPISCK_GPIO_CLK,ENABLE);
GPIO_InitStructure.GPIO_Pin = LD3320SPIMISO_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(LD3320SPIMISO_GPIO_PORT,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LD3320SPIMOSI_PIN;
GPIO_Init(LD3320SPIMOSI_GPIO_PORT,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LD3320SPISCK_PIN;
GPIO_Init(LD3320SPISCK_GPIO_PORT,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LD3320WR_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LD3320WR_GPIO_PORT, &GPIO_InitStructure);
LD_CS_H();
SPI_Cmd(LD3320SPI, DISABLE);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主模式
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //8位
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //时钟极性 空闲状态时,SCK保持低电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //时钟相位 数据采样从第一个时钟边沿开始
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //软件产生NSS
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; //波特率控制 SYSCLK/128
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据高位在前
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC多项式寄存器初始值为7
SPI_Init(LD3320SPI, &SPI_InitStructure);
SPI_Cmd(LD3320SPI, ENABLE);
}
static void car_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(M1_GPIO_CLK | M2_GPIO_CLK | M3_GPIO_CLK | M4_GPIO_CLK|M5_GPIO_CLK | M6_GPIO_CLK | M7_GPIO_CLK | M8_GPIO_CLK| E1_GPIO_CLK| E2_GPIO_CLK| E3_GPIO_CLK| E4_GPIO_CLK,ENABLE);
GPIO_InitStructure.GPIO_Pin = M1_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(M1_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = M2_PIN;
GPIO_Init(M2_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = M3_PIN;
GPIO_Init(M3_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = M4_PIN;
GPIO_Init(M4_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = M5_PIN;
GPIO_Init(M5_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = M6_PIN;
GPIO_Init(M6_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = M7_PIN;
GPIO_Init(M7_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = M8_PIN;
GPIO_Init(M8_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = E1_PIN;
GPIO_Init(E1_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = E2_PIN;
GPIO_Init(E2_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = E3_PIN;
GPIO_Init(E3_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = E4_PIN;
GPIO_Init(E4_GPIO_PORT, &GPIO_InitStructure);
}
///相关初始化 end
///中间层
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetITStatus(LD3320IRQEXITLINE)!= RESET )
{
ProcessInt();
printf("进入中断12\r\n");
EXTI_ClearFlag(LD3320IRQEXITLINE);
EXTI_ClearITPendingBit(LD3320IRQEXITLINE);//清除LINE上的中断标志位
}
}
static void LD3320_delay(unsigned long uldata)
{
unsigned int i = 0;
unsigned int j = 0;
unsigned int k = 0;
for (i=0;i<5;i++)
{
for (j=0;j<uldata;j++)
{
k = 200;
while(k--);
}
}
}
static uint8 RunASR(void)
{
uint8 i=0;
uint8 asrflag=0;
for (i=0; i<5; i++) //防止由于硬件原因导致LD3320芯片工作不正常,所以一共尝试5次启动ASR识别流程
{
LD_AsrStart(); //初始化ASR
LD3320_delay(100);
if (LD_AsrAddFixed()==0) //添加关键词语到LD3320芯片中
{
LD_reset(); //LD3320芯片内部出现不正常,立即重启LD3320芯片
LD3320_delay(50); //并从初始化开始重新ASR识别流程
continue;
}
LD3320_delay(10);
if (LD_AsrRun() == 0)
{
LD_reset(); //LD3320芯片内部出现不正常,立即重启LD3320芯片
LD3320_delay(50);//并从初始化开始重新ASR识别流程
continue;
}
asrflag=1;
break; //ASR流程启动成功,退出当前for循环。开始等待LD3320送出的中断信号
}
return asrflag;
}
static void LD_reset(void)
{
uint8 i;
LD_RST_H();
LD3320_delay(100);
LD_RST_L();
LD3320_delay(100);
LD_RST_H();
LD3320_delay(100);
LD_CS_L();
LD3320_delay(100);
LD_CS_H();
LD3320_delay(100);
i=LD_ReadReg(0x6);
LD_WriteReg(0x35, 0x33);
LD_WriteReg(0x1b, 0x55);
LD_WriteReg(0xb3, 0xaa);
i=LD_ReadReg(0x35);
i=LD_ReadReg(0x1b);
i=LD_ReadReg(0xb3);
i=i;
LD_RST_H();
LD3320_delay(100);
LD_RST_L();
LD3320_delay(100);
LD_RST_H();
LD3320_delay(100);
LD_CS_L();
LD3320_delay(100);
LD_CS_H();
i=LD_ReadReg(0x6);
LD3320_delay(100);
i=LD_ReadReg(0x35);
i=LD_ReadReg(0x1b);
i=LD_ReadReg(0xb3);
i=i;
}
static void LD_AsrStart(void)
{
LD_Init_ASR();
}
uint8 LD_Check_ASRBusyFlag_b2(void)
{
uint8 j;
uint8 flag = 0;
for (j=0; j<10; j++)
{
if (LD_ReadReg(0xb2) == 0x21)
{
flag = 1;
break;
}
LD3320_delay(10);
}
return flag;
}
///中间层end
///寄存器操作
static uint8 spi_send_byte(uint8 byte)
{
while (SPI_I2S_GetFlagStatus(LD3320SPI, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(LD3320SPI,byte);
while (SPI_I2S_GetFlagStatus(LD3320SPI,SPI_I2S_FLAG_RXNE) == RESET);
return SPI_I2S_ReceiveData(LD3320SPI);
}
static void LD_WriteReg(uint8 data1,uint8 data2)
{
LD_CS_L();
LD_SPIS_L();
spi_send_byte(0x04);
spi_send_byte(data1);
spi_send_byte(data2);
LD_CS_H();
}
static uint8 LD_ReadReg(uint8 reg_add)
{
uint8 i;
LD_CS_L();
LD_SPIS_L();
spi_send_byte(0x05);
spi_send_byte(reg_add);
i=spi_send_byte(0x00);
LD_CS_H();
return(i);
}
static uint8 LD_GetResult(void)
{
return LD_ReadReg(0xc5);
}
static uint8 LD_AsrRun(void)
{
LD_WriteReg(0x35, MIC_VOL);
LD_WriteReg(0x1C, 0x09);
LD_WriteReg(0xBD, 0x20);
LD_WriteReg(0x08, 0x01);
LD3320_delay( 5 );
LD_WriteReg(0x08, 0x00);
LD3320_delay( 5);
if(LD_Check_ASRBusyFlag_b2() == 0)
{
return 0;
}
LD_WriteReg(0xB2, 0xff);
LD_WriteReg(0x37, 0x06);
LD_WriteReg(0x37, 0x06);
LD3320_delay(5);
LD_WriteReg(0x1C, 0x0b);
LD_WriteReg(0x29, 0x10);
LD_WriteReg(0xBD, 0x00);
return 1;
}
static void ProcessInt(void)
{
uint8 nAsrResCount=0;
ucRegVal = LD_ReadReg(0x2B);
// 语音识别产生的中断
//(有声音输入,不论识别成功或失败都有中断)
LD_WriteReg(0x29,0) ;
LD_WriteReg(0x02,0) ;
if((ucRegVal & 0x10) && LD_ReadReg(0xb2)==0x21 && LD_ReadReg(0xbf)==0x35)
{
nAsrResCount = LD_ReadReg(0xba);
if(nAsrResCount>0 && nAsrResCount<=4)
{
nAsrStatus=LD_ASR_FOUNDOK;
}
else
{
nAsrStatus=LD_ASR_FOUNDZERO;
}
}
else
{
nAsrStatus=LD_ASR_FOUNDZERO;//执行没有识别
}
LD_WriteReg(0x2b,0);
LD_WriteReg(0x1C,0);//写0:ADC不可用
LD_WriteReg(0x29,0);
LD_WriteReg(0x02,0);
LD_WriteReg(0x2B,0);
LD_WriteReg(0xBA,0);
LD_WriteReg(0xBC,0);
LD_WriteReg(0x08,1);//清除FIFO_DATA
LD_WriteReg(0x08,0);//清除FIFO_DATA后 再次写0
}
static void LD_Init_Common(void)
{
LD_ReadReg(0x06);
LD_WriteReg(0x17, 0x35);
LD3320_delay(5);
LD_ReadReg(0x06);
LD_WriteReg(0x89, 0x03);
LD3320_delay(5);
LD_WriteReg(0xCF, 0x43);
LD3320_delay(5);
LD_WriteReg(0xCB, 0x02);
/*PLL setting*/
LD_WriteReg(0x11, LD_PLL_11);
if (nLD_Mode == LD_MODE_MP3)
{
LD_WriteReg(0x1E, 0x00);
LD_WriteReg(0x19, LD_PLL_MP3_19);
LD_WriteReg(0x1B, LD_PLL_MP3_1B);
LD_WriteReg(0x1D, LD_PLL_MP3_1D);
}
else
{
LD_WriteReg(0x1E,0x00);
LD_WriteReg(0x19, LD_PLL_ASR_19);
LD_WriteReg(0x1B, LD_PLL_ASR_1B);
LD_WriteReg(0x1D, LD_PLL_ASR_1D);
}
LD3320_delay(5);
LD_WriteReg(0xCD, 0x04);
LD_WriteReg(0x17, 0x4c);
LD3320_delay(1);
LD_WriteReg(0xB9, 0x00);
LD_WriteReg(0xCF, 0x4F);
LD_WriteReg(0x6F, 0xFF);
}
static void LD_Init_ASR(void)
{
nLD_Mode=LD_MODE_ASR_RUN;
LD_Init_Common();
LD_WriteReg(0xBD, 0x00);
LD_WriteReg(0x17, 0x48);
LD3320_delay(5);
LD_WriteReg(0x3C, 0x80);
LD_WriteReg(0x3E, 0x07);
LD_WriteReg(0x38, 0xff);
LD_WriteReg(0x3A, 0x07);
LD_WriteReg(0x40, 0);
LD_WriteReg(0x42, 8);
LD_WriteReg(0x44, 0);
LD_WriteReg(0x46, 8);
LD3320_delay( 1 );
}
///寄存器操作 end
全部代码51hei附件下载:
UNV-LD3320 基本识别工程-STM32F103ZET6.7z
(192.05 KB, 下载次数: 77)
|