LD3320语音识别模块驱动:
一、硬件连接 主控芯片:STM32F103VCT6 PB12-----------LD3320_IRQ PB13-----------LD3320_WR PB15-----------LD3320_RST
PA4-------------LD3320_CS PA5-------------LD3320_SCK PA6-------------LD3320_MISO PA7-------------LD3320_MOSI
二、使用STM32CUBEMX创建工程 引脚配置: SPI配置: 其他引脚配置: IRQ中断引脚,配置为下降沿触发: 使能中断,优先级随便:
WR引脚: RST引脚: 使用串口1进行查看,串口1配置如下: 二、驱动代码编写 这里我们使用商家给的代码进行移植,商家的代码时模拟SPI,我们转换为HAL的SPI;只需要修改两个函数以及添加一个函数即可:
void LD_WriteReg(uint8_t address,uint8_t dataout)
{
uint8_t i = 0;
uint8_t command=0x04;
SCS = 0;
delay_us(1);
for (i=0;i < 8; i++)
{
if (command & 0x80)
SDI = 1;
else
SDI = 0;
delay_us(1);
SDCK = 0;
command = (command << 1);
delay_us(1);
SDCK = 1;
}
for (i=0;i < 8; i++)
{
if (address & 0x80)
SDI = 1;
else
SDI = 0;
delay_us(1);
SDCK = 0;
address = (address << 1);
delay_us(1);
SDCK = 1;
}
for (i=0;i < 8; i++)
{
if (dataout & 0x80)
SDI = 1;
else
SDI = 0;
delay_us(1);
SDCK = 0;
dataout = (dataout << 1);
delay_us(1);
SDCK = 1;
}
delay_us(1);
SCS = 1;
}
uint8_t LD_ReadReg(uint8_t address)
{
#ifndef USE_HAL_LIB
uint8_t i = 0;
uint8_t datain =0 ;
uint8_t temp = 0;
uint8_t command=0x05;
SCS = 0;
delay_us(1);
for (i=0;i < 8; i++)
{
if (command & 0x80)
SDI = 1;
else
SDI = 0;
delay_us(1);
SDCK = 0;
command = (command << 1);
delay_us(1);
SDCK = 1;
}
for (i=0;i < 8; i++)
{
if (address & 0x80)
SDI = 1;
else
SDI = 0;
delay_us(1);
SDCK = 0;
address = (address << 1);
delay_us(1);
SDCK = 1;
}
delay_us(1);
for (i=0;i < 8; i++)
{
datain = (datain << 1);
temp = SDO;
delay_us(1);
SDCK = 0;
if (temp == 1)
datain |= 0x01;
delay_us(1);
SDCK = 1;
}
delay_us(1);
SCS = 1;
return datain;
#else
uint8_t rx_data;
uint8_t tx_data[3];
CS_LOW;
delay_us(1);
tx_data[0] = 0x05;
tx_data[1] = address;
tx_data[2] = 0x00;
rx_data = SPI_RreadWrite_Data(tx_data,3);
delay_us(1);
CS_HIGH;
return rx_data;
#endif
}
这两个函数为软件模拟SPI时序读写代码,我们改成以下即可:
uint8_t SPI_RreadWrite_Data(uint8_t *tx_data, uint8_t len)
{
uint8_t rx_data[len];
HAL_SPI_TransmitReceive(&LD3320_SPI,tx_data,rx_data,len,0XFFFF);
return rx_data[len-1];
}
void LD_WriteReg(uint8_t address,uint8_t dataout)
{
uint8_t tx_data[3];
CS_LOW;
delay_us(1);
tx_data[0] = 0x04;
tx_data[1] = address;
tx_data[2] = dataout;
SPI_RreadWrite_Data(tx_data,3);
delay_us(1);
CS_HIGH;
}
uint8_t LD_ReadReg(uint8_t address)
{
uint8_t rx_data;
uint8_t tx_data[3];
CS_LOW;
delay_us(1);
tx_data[0] = 0x05;
tx_data[1] = address;
tx_data[2] = 0x00;
rx_data = SPI_RreadWrite_Data(tx_data,3);
delay_us(1);
CS_HIGH;
return rx_data;
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == LD3320_IRQ_Pin)
{
if(HAL_GPIO_ReadPin(LD3320_IRQ_GPIO_Port,LD3320_IRQ_Pin) == GPIO_PIN_RESET)
{
ProcessInt();
printf("进入中断12\r\n");
}
}
}
改成这样就可以使用了,由与我们配置使用STM32CUBEMX进行配置,所以不需要再对引脚进行初始化。 驱动文件: LD3320.c
#include "LD3320.h"
#include <stdio.h>
#include "delay.h"
#include "spi.h"
#define USE_HAL_LIB
uint8_t nAsrStatus=0;
uint8_t nAsrRes=0;
uint8_t flag=0;
extern uint8_t nAsrStatus;
uint8_t nLD_Mode=LD_MODE_IDLE;
uint8_t ucRegVal;
#define LD3320_SPI hspi1
uint8_t SPI_RreadWrite_Data(uint8_t *tx_data, uint8_t len)
{
uint8_t rx_data[len];
HAL_SPI_TransmitReceive(&LD3320_SPI,tx_data,rx_data,len,0XFFFF);
return rx_data[len-1];
}
void LD3320_main(void)
{
nAsrStatus = LD_ASR_NONE;
CS_LOW;
printf("运行程序\r\n");
while(1)
{
switch(nAsrStatus)
{
case LD_ASR_RUNING:
case LD_ASR_ERROR:
break;
case LD_ASR_NONE:
{
nAsrStatus=LD_ASR_RUNING;
if (RunASR()==0)
{
nAsrStatus = LD_ASR_ERROR;
}
break;
}
case LD_ASR_FOUNDOK:
{
nAsrRes = LD_GetResult();
User_Modification(nAsrRes);
nAsrStatus = LD_ASR_NONE;
break;
}
case LD_ASR_FOUNDZERO:
default:
{
nAsrStatus = LD_ASR_NONE;
break;
}
}
}
}
void LD3320_Init(void)
{
}
void User_Modification(uint8_t dat)
{
if(dat)
{
switch(nAsrRes)
{
case CODE_DMCS:
printf("\"代码测试\"识别成功\r\n");
break;
case CODE_CSWB:
printf("\"测试完毕\"识别成功\r\n");
break;
case CODE_1KL1:
printf("\"北京\"识别成功\r\n");
break;
case CODE_1KL2:
printf("\"上海\"识别成功\r\n");
break;
case CODE_1KL3:
printf("\"开灯\"识别成功\r\n");
break;
case CODE_1KL4:
printf("\"关灯\"识别成功\r\n");
break;
case CODE_2KL1:
printf("\"广州\"识别成功\r\n");
break;
case CODE_2KL2:
printf("\"深圳\"识别成功\r\n");
break;
case CODE_2KL3:
printf("\"向左转\"识别成功\r\n");
break;
case CODE_2KL4:
printf("\"向右转\"识别成功\r\n");
break;
case CODE_3KL1:
printf("\"打开空调\"识别成功\r\n");
break;
case CODE_3KL2:
printf("\"关闭空调\"识别成功\r\n");
break;
case CODE_5KL1:
printf("\"后退\"识别成功");
break;
default:break;
}
}
}
void LD_Reset(void)
{
RST_HIGH;
HAL_Delay(5);
RST_LOW;
HAL_Delay(5);
RST_HIGH;
HAL_Delay(5);
CS_LOW;
HAL_Delay(5);
CS_HIGH;
HAL_Delay(5);
}
void LD_Init_Common(void)
{
LD_ReadReg(0x06);
LD_WriteReg(0x17, 0x35);
HAL_Delay(5);
LD_ReadReg(0x06);
LD_WriteReg(0x89, 0x03);
HAL_Delay(5);
LD_WriteReg(0xCF, 0x43);
HAL_Delay(5);
LD_WriteReg(0xCB, 0x02);
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);
}
HAL_Delay(5);
LD_WriteReg(0xCD, 0x04);
LD_WriteReg(0x17, 0x4c);
HAL_Delay(5);
LD_WriteReg(0xB9, 0x00);
LD_WriteReg(0xCF, 0x4F);
LD_WriteReg(0x6F, 0xFF);
}
void LD_Init_ASR(void)
{
nLD_Mode=LD_MODE_ASR_RUN;
LD_Init_Common();
LD_WriteReg(0xBD, 0x00);
LD_WriteReg(0x17, 0x48);
HAL_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);
HAL_Delay(5);
}
void ProcessInt(void)
{
uint8_t 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);
LD_WriteReg(0x29,0);
LD_WriteReg(0x02,0);
LD_WriteReg(0x2B,0);
LD_WriteReg(0xBA,0);
LD_WriteReg(0xBC,0);
LD_WriteReg(0x08,1);
LD_WriteReg(0x08,0);
}
uint8_t LD_Check_ASRBusyFlag_b2(void)
{
uint8_t j,i;
uint8_t flag = 0;
for (j=0; j<5; j++)
{
i=LD_ReadReg(0xb2);
if ( i== 0x21)
{
flag = 1;
break;
}
HAL_Delay(20);
}
return flag;
}
void LD_AsrStart(void)
{
LD_Init_ASR();
}
uint8_t LD_AsrRun(void)
{
LD_WriteReg(0x35, MIC_VOL);
LD_WriteReg(0x1C, 0x09);
LD_WriteReg(0xBD, 0x20);
LD_WriteReg(0x08, 0x01);
HAL_Delay(5);
LD_WriteReg(0x08, 0x00);
HAL_Delay(5);
if(LD_Check_ASRBusyFlag_b2() == 0)
{
return 0;
}
LD_WriteReg(0xB2, 0xff);
LD_WriteReg(0x37, 0x06);
HAL_Delay(5);
LD_WriteReg(0x37, 0x06);
HAL_Delay(5);
LD_WriteReg(0x1C, 0x0b);
LD_WriteReg(0x29, 0x10);
LD_WriteReg(0xBD, 0x00);
return 1;
}
uint8_t LD_AsrAddFixed(void)
{
uint8_t k, flag;
uint8_t nAsrAddLength;
#define DATE_A 14
#define DATE_B 20
uint8_t sRecog[DATE_A][DATE_B] = {
"xiao jie",\
"dai ma ce shi",\
"ce shi wan bi",\
"bei jing",\
"shang hai",\
"kai deng",\
"guan deng",\
"guang zhou",\
"shen zhen",\
"xiang zuo zhuan",\
"xiang you zhuan",\
"da kai kong tiao",\
"guan bi kong tiao",\
"hou tui",\
};
uint8_t pCode[DATE_A] = {
CODE_CMD,\
CODE_DMCS,\
CODE_CSWB,\
CODE_1KL1,\
CODE_1KL2,\
CODE_1KL3,\
CODE_1KL4,\
CODE_2KL1,\
CODE_2KL2,\
CODE_2KL3,\
CODE_2KL4,\
CODE_3KL1,\
CODE_3KL2,\
CODE_5KL1,
};
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);
HAL_Delay(1);
LD_WriteReg(0x08, 0x00);
HAL_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;
}
uint8_t RunASR(void)
{
uint8_t i=0;
uint8_t asrflag=0;
for (i=0; i<5; i++)
{
LD_AsrStart();
HAL_Delay(5);
if (LD_AsrAddFixed()==0)
{
LD_Reset();
HAL_Delay(5);
continue;
}
delay_us(5);
if (LD_AsrRun() == 0)
{
LD_Reset();
HAL_Delay(5);
continue;
}
asrflag=1;
break;
}
return asrflag;
}
uint8_t LD_GetResult(void)
{
return LD_ReadReg(0xc5 );
}
void LD_WriteReg(uint8_t address,uint8_t dataout)
{
#ifndef USE_HAL_LIB
uint8_t i = 0;
uint8_t command=0x04;
SCS = 0;
delay_us(1);
for (i=0;i < 8; i++)
{
if (command & 0x80)
SDI = 1;
else
SDI = 0;
delay_us(1);
SDCK = 0;
command = (command << 1);
delay_us(1);
SDCK = 1;
}
for (i=0;i < 8; i++)
{
if (address & 0x80)
SDI = 1;
else
SDI = 0;
delay_us(1);
SDCK = 0;
address = (address << 1);
delay_us(1);
SDCK = 1;
}
for (i=0;i < 8; i++)
{
if (dataout & 0x80)
SDI = 1;
else
SDI = 0;
delay_us(1);
SDCK = 0;
dataout = (dataout << 1);
delay_us(1);
SDCK = 1;
}
delay_us(1);
SCS = 1;
#else
uint8_t tx_data[3];
CS_LOW;
delay_us(1);
tx_data[0] = 0x04;
tx_data[1] = address;
tx_data[2] = dataout;
SPI_RreadWrite_Data(tx_data,3);
delay_us(1);
CS_HIGH;
#endif
}
uint8_t LD_ReadReg(uint8_t address)
{
#ifndef USE_HAL_LIB
uint8_t i = 0;
uint8_t datain =0 ;
uint8_t temp = 0;
uint8_t command=0x05;
SCS = 0;
delay_us(1);
for (i=0;i < 8; i++)
{
if (command & 0x80)
SDI = 1;
else
SDI = 0;
delay_us(1);
SDCK = 0;
command = (command << 1);
delay_us(1);
SDCK = 1;
}
for (i=0;i < 8; i++)
{
if (address & 0x80)
SDI = 1;
else
SDI = 0;
delay_us(1);
SDCK = 0;
address = (address << 1);
delay_us(1);
SDCK = 1;
}
delay_us(1);
for (i=0;i < 8; i++)
{
datain = (datain << 1);
temp = SDO;
delay_us(1);
SDCK = 0;
if (temp == 1)
datain |= 0x01;
delay_us(1);
SDCK = 1;
}
delay_us(1);
SCS = 1;
return datain;
#else
uint8_t rx_data;
uint8_t tx_data[3];
CS_LOW;
delay_us(1);
tx_data[0] = 0x05;
tx_data[1] = address;
tx_data[2] = 0x00;
rx_data = SPI_RreadWrite_Data(tx_data,3);
delay_us(1);
CS_HIGH;
return rx_data;
#endif
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == LD3320_IRQ_Pin)
{
if(HAL_GPIO_ReadPin(LD3320_IRQ_GPIO_Port,LD3320_IRQ_Pin) == GPIO_PIN_RESET)
{
ProcessInt();
printf("进入中断12\r\n");
}
}
}
LD3320.h:
#ifndef LD3320_H__
#define LD3320_H__
#include "stm32f1xx_hal.h"
#include "main.h"
#define LD_MODE_IDLE 0x00
#define LD_MODE_ASR_RUN 0x08
#define LD_MODE_MP3 0x40
#define LD_ASR_NONE 0x00
#define LD_ASR_RUNING 0x01
#define LD_ASR_FOUNDOK 0x10
#define LD_ASR_FOUNDZERO 0x11
#define LD_ASR_ERROR 0x31
#define CLK_IN 24
#define LD_PLL_11 (uint8_t)((CLK_IN/2.0)-1)
#define LD_PLL_MP3_19 0x0f
#define LD_PLL_MP3_1B 0x18
#define LD_PLL_MP3_1D (uint8_t)(((90.0*((LD_PLL_11)+1))/(CLK_IN))-1)
#define LD_PLL_ASR_19 (uint8_t)(CLK_IN*32.0/(LD_PLL_11+1) - 0.51)
#define LD_PLL_ASR_1B 0x48
#define LD_PLL_ASR_1D 0x1f
#define MIC_VOL 0x43
#define CODE_CMD 0x00
#define CODE_DMCS 0x01
#define CODE_CSWB 0x02
#define CODE_1KL1 0x03
#define CODE_1KL2 0x04
#define CODE_1KL3 0x05
#define CODE_1KL4 0x06
#define CODE_2KL1 0x18
#define CODE_2KL2 0x19
#define CODE_2KL3 0x1A
#define CODE_2KL4 0x1B
#define CODE_3KL1 0x1C
#define CODE_3KL2 0x1D
#define CODE_3KL3 0x1E
#define CODE_3KL4 0x1F
#define CODE_4KL1 0x20
#define CODE_4KL2 0x21
#define CODE_4KL3 0x22
#define CODE_4KL4 0x23
#define CODE_5KL1 0x24
#define RST_HIGH HAL_GPIO_WritePin(LD3320_RST_GPIO_Port,LD3320_RST_Pin,GPIO_PIN_SET)
#define RST_LOW HAL_GPIO_WritePin(LD3320_RST_GPIO_Port,LD3320_RST_Pin,GPIO_PIN_RESET)
#define SCK_HIGH HAL_GPIO_WritePin(LD3320_SCK_GPIO_Port,LD3320_SCK_Pin,GPIO_PIN_SET)
#define SCK_LOW HAL_GPIO_WritePin(LD3320_SCK_GPIO_Port,LD3320_SCK_Pin,GPIO_PIN_RESET)
#define MOSI_HIGH HAL_GPIO_WritePin(LD3320_MOSI_GPIO_Port,LD3320_MOSI_Pin,GPIO_PIN_SET)
#define MOSI_LOW HAL_GPIO_WritePin(LD3320_MOSI_GPIO_Port,LD3320_MOSI_Pin,GPIO_PIN_RESET)
#define IRQ_HIGH HAL_GPIO_WritePin(LD3320_IRQ_GPIO_Port,LD3320_IRQ_Pin,GPIO_PIN_SET)
#define IRQ_LOW HAL_GPIO_WritePin(LD3320_IRQ_GPIO_Port,LD3320_IRQ_Pin,GPIO_PIN_RESET)
#define CS_HIGH HAL_GPIO_WritePin(LD3320_CS_GPIO_Port,LD3320_CS_Pin,GPIO_PIN_SET)
#define CS_LOW HAL_GPIO_WritePin(LD3320_CS_GPIO_Port,LD3320_CS_Pin,GPIO_PIN_RESET)
void LD3320_main(void);
void User_Modification(uint8_t dat);
void LD_Reset(void);
void LD_Init_Common(void);
void LD_Init_ASR(void);
void ProcessInt(void);
void LD_AsrStart(void);
uint8_t LD_AsrRun(void);
uint8_t LD_AsrAddFixed(void);
uint8_t RunASR(void);
uint8_t LD_GetResult(void);
void LD3320_Init(void);
void LD_WriteReg(uint8_t address,uint8_t dataout);
uint8_t LD_ReadReg(uint8_t address);
#endif
测试举例:
#include "main.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"
#include <stdio.h>
#include "LD3320.h"
void SystemClock_Config(void);
int fputc(int ch,FILE *f){
uint8_t temp[1]={ch};
HAL_UART_Transmit(&huart1,temp,1,2);
return ch;
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI1_Init();
MX_USART1_UART_Init();
while (1)
{
LD3320_main();
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif
以上就是驱动相关代码,注意:在使用时LD3320_WR引脚一定要默认拉低。
三、测试结果 最终测试成功,移植完成。
|