小车实物图
本实验基于51单片机和LD3320语音识别模块
小车能够实现遥控器直接控制,语音控制以及自动避障
涉及到的知识有:I/O口的配置(点亮led),定时器(循迹),串口通信(两个板子的连接),SPI同步通信(遥控器),中断(定时器中断和串口中断),PWM(循迹)
原理图如下
值得注意的是,串口通信使用的是串口2,要接到P4.6和P4.7
其实串口2和串口1没什么本质区别,只是其中某些寄存器不能直接赋值
代码的逻辑如下图所示
遥控器通过按下不同的按键,得到不同的flag值从而进入不同的驱动模式
初始定时器中断默认打开
但串口中断优先级更低
所以在选择语音模式的时候要将定时器中断关闭
此外,通过板载led灯可以观察小车的状态
上电后小车亮蓝灯,进入语音模式后亮红灯
前进时灯都亮,后退时全灭
左转亮红灯,右转亮蓝灯
通过板载指示灯能看出运动状态
以下是详细的代码(主控51单片机和LD3320)
头文件都是默认的因此只给出main函数
51单片机函数:
#include "delay.h"
#include "ps2.h"
#include "stdio.h"
#include "15W4KxxS4.h"
#include "uart.h"
#include "beep.h"
/**********引脚设置***********/
sbit IN1=P2^6;
sbit IN2=P0^2;
sbit IN3=P2^0;
sbit IN4=P2^4;
sbit OUTR=P0^0;
sbit OUTL=P0^1;
sbit led1=P0^6;
sbit led2=P0^7;
/*********变量设置**********/
volatile uint8 Flag1=FALSE;
uint8 uart2temp,sig;
int g_carstate = 0;
int pwm_control=0;
int flag=0;
/************函数调用********************/
void TIME0_Init(void);//定时器设置
void Uart2_Init(void);//串口2设置
void run(void);//运动函数设置
void back(void);
void left(void);
void right(void);
void stop(void);
void PS2_control();//ps2按键控制
void SendDataByUart2(uint8 dat);//串口2发送数据函数
void UART2_Tx_Puts(void);//串口2接收到数据后发送出去
/************枚举按键状态****************/
enum{
enSTOP = 0,
enRUN,
enBACK,
enLEFT,
enRIGHT,
enTRIANGLE,
enCIRCLE,
enCROSS,
enSQUARE,
enR2,
}enCarState;
/***********主函数***************/
int main()
{
int i=0;
int pwm=0;
Uart2_Init(); //串口初始化
TIME0_Init(); //定时器0初始化
PS2_Init(); //PS2初始化
P0M1 &= 0x3F; P0M0 &= 0x3F; //设置P0.6,P0.7为准双向口
P3M1 &= 0x7F; P3M0 &= 0x7F; //设置P3.7为准双向口
P2M1 &= 0xDF; P2M0 &= 0xDF; //设置P2.5为准双向口
delay_ms(10); //初始化后延时
while (1)
{
PS2_control();
IN1=0;
IN2=0;
IN3=0;
IN4=0;//电机接收电流置零
if(g_carstate==enTRIANGLE)
{
flag=1;//将遥控器发出的对应模式以flag的形式记录
}
else if(g_carstate==enCROSS)
{
flag=3;
}
else if(g_carstate==enCIRCLE)
{
flag=2;
}
else if(g_carstate==enSQUARE)
{
flag=0;
}
if(flag==1)
{
BEEP_off();
EA=1;
switch(g_carstate)
{
case enRUN:
{
run();
}
break;
case enBACK:
{
back();
}
break;
case enLEFT:
{
left();
}
break;
case enRIGHT:
{
right();
}
break;
default:
{
stop();
}
break;
}
}
delay_ms(10);
if(flag==2)//语音模式
{
BEEP_off();
EA=1;
ET0=0;//关闭定时器中断
}
if(flag==3)//红外避障模式
{
BEEP_off();
ET0=1;//关闭定时器中断
EA=1;
}
if(flag==0)
{
stop();
}
}
}
/**************定时器设置**************/
void TIME0_Init(void)
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = (65526-1000/1.085)/256; //设置定时初始值
TH0 = 65526-1000/1.085; //设置定时重载值
TR0= 1; //启动T0工作
TF0=0;
ET0= 1; //允许T0中断,定时器中断开
EA = 1; //开总中断
}
/********** 串口2初始化函数************/
void Uart2_Init(void)
{
P_SW2|=S2_S; //选择P46 P47为串口2
S2CON = 0x50; //8位数据,可变波特率,启动串行接收器
AUXR |= 0x04; //定时器2时钟为Fosc,即1T
T2L = 0xE0; //设定定时初值
T2H = 0xFE; //设定定时初值
AUXR |= 0x10; //启动定时器2
IE2 |= 0x01; //串口2中断打开
}
/**************运动状态函数设定*********/
void run(void)
{
IN1=0;
IN2=1;
IN3=0;
IN4=1;
led1=0;
led2=0;
return;
}
void back(void)
{
IN1=1;
IN2=0;
IN3=1;
IN4=0;
led1=1;
led2=1;
return;
}
void left(void)
{
IN1=1;
IN2=0;
IN3=0;
IN4=1;
led1=0;
led2=1;
return;
}
void right(void)
{
IN1=0;
IN2=1;
IN3=1;
IN4=0;
led1=1;
led2=0;
return;
}
void stop(void)
{
IN1=0;
IN2=0;
IN3=0;
IN4=0;
return;
}
/******************ps2按键控制***************/
void PS2_control()
{
//PS2按键变量定义
stPS2KeyValue * PS2;
PS2 = ReadPS2KeyValue(); //检测手柄按键之后获得的值
//由data[3]和data[4]返回来的组合成16位的数组
//如data[4]data[3]:当select按下时
//FunBtn:0x1111 1111 1111 1110
if((PS2->FunBtn & PSB_SELECT) == 0)
{
}
if((PS2->FunBtn & PSB_START) == 0)
{
}
if((PS2->FunBtn & PSB_L3) == 0)
{
g_carstate = enSTOP; //将小车定义为停止状态
}
if((PS2->FunBtn & PSB_R3) == 0)
{
g_carstate = enSTOP; //将小车定义为停止状态
}
if((PS2->FunBtn & PSB_PAD_UP) == 0)
{
g_carstate = enRUN; //将小车定义为前进状态
}
else if((PS2->FunBtn & PSB_PAD_RIGHT) == 0)
{
g_carstate = enRIGHT; //将小车定义为状态右转
}
else if((PS2->FunBtn & PSB_PAD_DOWN) == 0)
{
g_carstate = enBACK; //将小车定义为后退状态
}
else if((PS2->FunBtn & PSB_PAD_LEFT) == 0)
{
g_carstate = enLEFT; //将小车定义为左转状态
}
else if((PS2->FunBtn & PSB_TRIANGLE) == 0) // 遥控器操作模式
{
BEEP_on();
delay_ms(10);
g_carstate= enTRIANGLE;
}
else if((PS2->FunBtn & PSB_CIRCLE) == 0) // 声控模式
{
BEEP_on();
delay_ms(10);
g_carstate= enCIRCLE;
}
else if((PS2->FunBtn & PSB_CROSS) == 0) // 自动避障模式
{
delay_ms(10);
g_carstate= enCROSS;
BEEP_on();
}
else if((PS2->FunBtn & PSB_SQUARE) == 0) //停止
{
g_carstate= enSQUARE;
}
else if((PS2->FunBtn & PSB_R2) == 0)
{
g_carstate= enR2;
}
else //去掉则按下一直执行,加此段则放开停止
{
g_carstate = enSTOP; //将小车定义为停止状态
}
}
/**********串口2发送数据函数*****************/
void SendDataByUart2(uint8 dat)
{
S2BUF = dat; //写数据到UART数据寄存器
while(!(S2CON&S2TI)); //在停止位没有发送时,S2TI为0即一直等待
S2CON&=~S2TI; //清除S2CON寄存器对应S2TI位(该位必须软件清零)
}
/************ 串口2接收到数据后发送出去****************/
void UART2_Tx_Puts(void)
{
if(Flag1) //有新数据通过串口被接收到
{
IE2 &= 0xFE; // 串口2中断关闭
SendDataByUart2(uart2temp); //发送字符
SendDataByUart2(0x0D); //发送换行符
SendDataByUart2(0x0A); //发送换行符
IE2 |= 0x01; // 串口2中断打开
Flag1=FALSE; //清除接收标识符
}
}
/**********串口2中断服务函数********************/
void Uart2() interrupt UART2_VECTOR using 1
{
IE2 &= 0xFE; // 串口2中断关闭
Flag1=TRUE; //接收到数据,接收标识符有效
led1=0; //串口2指示灯亮,红灯
if (S2CON & S2RI) //串行接收到停止位的中间时刻时,该位置1
{
S2CON &= ~S2RI; //清除S2CON寄存器对应S2RI位(该位必须软件清零)
uart2temp = S2BUF;
}
switch(uart2temp)
{
case 0x01: //收到“1”
run();
delay_ms(300);
stop();
break;
case 0x02: //收到“2”
back();
delay_ms(300);
stop();
break;
case 3: //收到“3”
left();
delay_ms(250);
stop();
break;
case 4: //收到“4”
right();
delay_ms(250);
stop();
break;
default:
P2=0XFF;
break;
}
if (S2CON & S2TI) //在停止位开始发送时,该位置1
{
S2CON &= ~S2TI; //清除S2CON寄存器对应S2TI位(该位必须软件清零)
}
IE2 |= 0x01; // 串口2中断打开
}
/**************定时器0中断***************/
void timer0()interrupt 1
{
TL0 = (65526-1000/1.085)/256; //设置定时初始值
TH0 = 65526-1000/1.085;
if(pwm_control>10)
{
pwm_control=0;
}
if(flag==3)
{
if(pwm_control<9)
{
if(OUTR==0&&OUTL==0)
{
back();
}
else if(OUTL==0)
{
right();
}
else if(OUTR==0)
{
left();
}
if(OUTR==1&&OUTL==1)
{
run();
}
}
else
{
stop();
}
}
pwm_control++;
}
语音模块函数
main.c
/*******************************************************
** CPU: STC11L08XE
** 晶振:22.1184MHZ
** 波特率:9600 bit/S
** 口令模式: 即每次识别时都需要说“大哥”这个口令 ,才能够进行下一级的识别
/*********************************************************/
#include "config.h"
/************************************************************************************/
// nAsrStatus 用来在main主程序中表示程序运行的状态,不是LD3320芯片内部的状态寄存器
// LD_ASR_NONE: 表示没有在作ASR识别
// LD_ASR_RUNING: 表示LD3320正在作ASR识别中
// LD_ASR_FOUNDOK: 表示一次识别流程结束后,有一个识别结果
// LD_ASR_FOUNDZERO: 表示一次识别流程结束后,没有识别结果
// LD_ASR_ERROR: 表示一次识别流程中LD3320芯片内部出现不正确的状态
/***********************************************************************************/
uint8 idata nAsrStatus = 0;
void MCU_init();
void ProcessInt0(); //识别处理函数
void delay(unsigned long uldata);
void User_handle(uint8 dat);//用户执行操作函数
void Delay200ms();
void Led_test(void);//单片机工作指示
void Send_Data(uint8_t Key_val);//串口发送函数
uint8_t G0_flag = DISABLE; //运行标志,ENABLE:运行。DISABLE:禁止运行
sbit LED = P4 ^ 2; //信号指示灯
sbit SRD1 = P1 ^ 0;
sbit SRD2 = P1 ^ 1;
sbit SRD3 = P1 ^ 3;
sbit SRD4 = P1 ^ 2;
/***********************************************************
* 名 称: void main(void)
* 功 能: 主函数 程序入口
* 入口参数:
* 出口参数:
* 说 明:
* 调用方法:
**********************************************************/
void main(void)
{
uint8 idata nAsrRes;
uint8 i = 0;
P1M0 = 0xFF;
P1M1 = 0x00;
SRD1 = SRD2 = SRD3 = SRD4 = 0;
Led_test();
MCU_init();
LD_Reset();
UartIni(); /*串口初始化*/
nAsrStatus = LD_ASR_NONE; // 初始状态:没有在作ASR
PrintCom("<G>欢迎使用");
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: /* 一次ASR识别流程结束,去取ASR识别结果*/
{
nAsrRes = LD_GetResult(); /*获取结果*/
User_handle(nAsrRes);//用户执行函数
nAsrStatus = LD_ASR_NONE;
break;
}
case LD_ASR_FOUNDZERO:
default:
{
nAsrStatus = LD_ASR_NONE;
break;
}
}// switch
}// while
}
/***********************************************************
* 名 称: LED灯测试
* 功 能: 单片机是否工作指示
* 入口参数: 无
* 出口参数:无
* 说 明:
**********************************************************/
void Led_test(void)
{
LED = ~ LED;
Delay200ms();
LED = ~ LED;
Delay200ms();
LED = ~ LED;
Delay200ms();
LED = ~ LED;
Delay200ms();
LED = ~ LED;
Delay200ms();
LED = ~ LED;
}
/***********************************************************
* 名 称: void MCU_init()
* 功 能: 单片机初始化
* 入口参数:
* 出口参数:
* 说 明:
* 调用方法:
**********************************************************/
void MCU_init()
{
P0 = 0xff;
P1 = 0x00;
P2 = 0xff;
P3 = 0xff;
P4 = 0xff;
AUXR &= 0x7F; //定时器时钟12T模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x00; //设置定时初值
TH0 = 0x28; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
SM0=0;//设置串口工作方式
SM1=1;
ES=1;//打开串口中断
LD_MODE = 0; // 设置MD管脚为低,并行模式读写
IE0 = 1;
EX0 = 1;
EA = 1;
WDT_CONTR = 0x3D;
}
/***********************************************************
* 名 称: 延时函数
* 功 能:
* 入口参数:
* 出口参数:
* 说 明:
* 调用方法:
**********************************************************/
void Delay200us() //@22.1184MHz
{
unsigned char i, j;
_nop_();
_nop_();
i = 5;
j = 73;
do
{
while (--j);
}
while (--i);
}
void delay(unsigned long uldata)
{
unsigned int j = 0;
unsigned int g = 0;
while(uldata--)
Delay200us();
}
void Delay200ms() //@22.1184MHz
{
unsigned char i, j, k;
i = 17;
j = 208;
k = 27;
do
{
do
{
while (--k);
}
while (--j);
}
while (--i);
}
/***********************************************************
* 名 称: 中断处理函数
* 功 能:
* 入口参数:
* 出口参数:
* 说 明:
* 调用方法:
**********************************************************/
void ExtInt0Handler(void) interrupt 0
{
ProcessInt0();
}
/***********************************************************
* 名 称:串口发送函数
* 功 能:识别成功后,执行动作可在此进行修改
* 入口参数: 无
* 出口参数:无
* 说 明:
**********************************************************/
void Send_Data(uint16_t Key_val)
{
SBUF=Key_val; //将要发送的数据存入发送缓冲器中
while(!TI); //若发送中断标志位没有置1(正在发送数据),就等待
TI=0; //若发送完成,TI自动置1,这里把它清零
}
/***********************************************************
* 名 称:用户执行函数
* 功 能:识别成功后,执行动作可在此进行修改
* 入口参数: 无
* 出口参数:无
* 说 明:
**********************************************************/
void User_handle(uint16_t dat)
{
if(0 == dat)
{
G0_flag = ENABLE;
LED = 0;
}
else if(ENABLE == G0_flag)
{
G0_flag = DISABLE;
LED = 1;
switch(dat)
{
case CODE_1: /*命令“前进”*/
Send_Data(0x01);
SRD1 = 1;
SRD2 = 0;
SRD3 = 1;
SRD4 = 0;
Delay200ms();
Delay200ms();
Delay200ms();
Delay200ms();
Delay200ms();
SRD1 = 0;
SRD2 = 0;
SRD3 = 0;
SRD4 = 0;
break;
case CODE_2: /*命令“后退”*/
Send_Data(2);
SRD1 = 0;
SRD2 = 1;
SRD3 = 0;
SRD4 = 1;
Delay200ms();
Delay200ms();
Delay200ms();
Delay200ms();
Delay200ms();
SRD1 = 0;
SRD2 = 0;
SRD3 = 0;
SRD4 = 0;
break;
case CODE_3: /*命令“左转”*/
Send_Data(3);
SRD1 = 1;
SRD2 = 0;
SRD3 = 0;
SRD4 = 1;
Delay200ms();
Delay200ms();
Delay200ms();
SRD1 = 0;
SRD2 = 0;
SRD3 = 0;
SRD4 = 0;
break;
case CODE_4: /*命令“右转”*/
Send_Data(4);
SRD1 = 0;
SRD2 = 1;
SRD3 = 1;
SRD4 = 0;
Delay200ms();
Delay200ms();
Delay200ms();
SRD1 = 0;
SRD2 = 0;
SRD3 = 0;
SRD4 = 0;
break;
case CODE_5: /*命令“打开冰箱”*/
SRD3 = 1;
PrintCom("<G>冰箱已打开\r\n");
break;
case CODE_6: /*命令“关闭冰箱”*/
SRD3 = 0;
PrintCom("<G>冰箱已关闭\r\n");
break;
case CODE_7: /*命令“打开空调”*/
SRD4 = 1;
PrintCom("<G>空条已打开\r\n");
break;
case CODE_8: /*命令“关闭空调”*/
SRD4 = 0;
PrintCom("<G>空条已关闭\r\n");
break;
case CODE_9: /*命令“全部打开”*/
SRD1 = 1;
SRD2 = 1;
SRD3 = 1;
SRD4 = 1;
PrintCom("<G>已全部打开\r\n");
break;
case CODE_10: /*命令“全部关闭”*/
SRD1 = 0;
SRD2 = 0;
SRD3 = 0;
SRD4 = 0;
PrintCom("<G>已全部关闭\r\n");
break;
case CODE_11: /*命令“.....”*/
PrintCom("");
break;
case CODE_12: /*命令“.....”*/
PrintCom("");
break;
case CODE_13: /*命令“.....”*/
PrintCom("");
break;
case CODE_14: /*命令“.....”*/
PrintCom("");
break;
case CODE_15: /*命令“.....”*/
PrintCom("");
break;
case CODE_16: /*命令“.....”*/
PrintCom("");
break;
case CODE_17: /*命令“.....”*/
PrintCom("");
break;
case CODE_18: /*命令“.....”*/
PrintCom("");
break;
case CODE_19: /*命令“.....”*/
PrintCom("");
break;
case CODE_20: /*命令“.....”*/
PrintCom("");
break;
case CODE_21: /*命令“.....”*/
PrintCom("");
break;
case CODE_22: /*命令“.....”*/
PrintCom("");
break;
case CODE_23: /*命令“.....”*/
PrintCom("");
break;
case CODE_24: /*命令“.....”*/
PrintCom("");
break;
case CODE_25: /*命令“.....”*/
PrintCom("");
break;
case CODE_26: /*命令“.....”*/
PrintCom("");
break;
case CODE_27: /*命令“.....”*/
PrintCom("");
break;
case CODE_28: /*命令“.....”*/
PrintCom("");
break;
case CODE_29: /*命令“.....”*/
PrintCom("");
break;
case CODE_30: /*命令“.....”*/
PrintCom("");
break;
case CODE_31: /*命令“.....”*/
PrintCom("");
break;
case CODE_32: /*命令“.....”*/
PrintCom("");
break;
case CODE_33: /*命令“.....”*/
PrintCom("");
break;
case CODE_34: /*命令“.....”*/
PrintCom("");
break;
case CODE_35: /*命令“.....”*/
PrintCom("");
break;
case CODE_36: /*命令“.....”*/
PrintCom("");
break;
case CODE_37: /*命令“.....”*/
PrintCom("");
break;
case CODE_38: /*命令“.....”*/
PrintCom("");
break;
case CODE_39: /*命令“.....”*/
PrintCom("");
break;
case CODE_40: /*命令“.....”*/
PrintCom("");
break;
case CODE_41: /*命令“.....”*/
PrintCom("");
break;
case CODE_42: /*命令“.....”*/
PrintCom("");
break;
case CODE_43: /*命令“.....”*/
PrintCom("");
break;
case CODE_44: /*命令“.....”*/
PrintCom("");
break;
case CODE_45: /*命令“.....”*/
PrintCom("");
break;
case CODE_46: /*命令“.....”*/
PrintCom("");
break;
case CODE_47: /*命令“.....”*/
PrintCom("");
break;
case CODE_48: /*命令“.....”*/
PrintCom("");
break;
case CODE_49: /*命令“.....”*/
PrintCom("");
break;
default:/*text.....*/
break;
}
}
else
{
//PrintCom("请说出一级口令\r\n"); /*text.....*/
}
}
void tm0_isr() interrupt 1
{
TL0 = 0x00; //设置定时初值
TH0 = 0x28; //设置定时初值
WDT_CONTR=0x3D;
}
LDChip.c文章来源:https://www.toymoban.com/news/detail-457828.html
/*******************************************************
** CPU: STC11L08XE
** 晶振:22.1184MHZ
** 波特率:9600 bit/S
** 口令模式: 即每次识别时都需要说“小杰”这个口令 ,才能够进行下一级的识别
/*********************************************************/
#include "config.h"
extern void delay(unsigned long uldata);
uint8 idata ucRegVal;
extern uint8 idata nAsrStatus;
void ProcessInt0(void);
/************************************************************************
功能描述: 复位LD模块
入口参数: none
返 回 值: none
其他说明: none
**************************************************************************/
void LD_Reset()
{
RSTB=1;
delay(5);
RSTB=0;
delay(5);
RSTB=1;
delay(5);
CSB=0;
delay(5);
CSB=1;
delay(5);
}
/************************************************************************
功能描述: LD模块命令初始化
入口参数: none
返 回 值: none
其他说明: 该函数为出厂配置,一般不需要修改;
有兴趣的客户可对照开发手册根据需要自行修改。
**************************************************************************/
void LD_Init_Common()
{
LD_ReadReg(0x06);
LD_WriteReg(0x17, 0x35);
delay(10);
LD_ReadReg(0x06);
LD_WriteReg(0x89, 0x03);
delay(5);
LD_WriteReg(0xCF, 0x43);
delay(5);
LD_WriteReg(0xCB, 0x02);
/*PLL setting*/
LD_WriteReg(0x11, LD_PLL_11);
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);
delay(10);
LD_WriteReg(0xCD, 0x04);
// LD_WriteReg(0x17, 0x4c);
delay(5);
LD_WriteReg(0xB9, 0x00);
LD_WriteReg(0xCF, 0x4F);
LD_WriteReg(0x6F, 0xFF);
}
/************************************************************************
功能描述: LD模块 ASR功能初始化
入口参数: none
返 回 值: none
其他说明: 该函数为出厂配置,一般不需要修改;
有兴趣的客户可对照开发手册根据需要自行修改。
**************************************************************************/
void LD_Init_ASR()
{
LD_Init_Common();
LD_WriteReg(0xBD, 0x00);
LD_WriteReg(0x17, 0x48);
delay( 10 );
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);
delay( 1 );
}
/************************************************************************
功能描述: 中断处理函数
入口参数: none
返 回 值: none
其他说明: 当LD模块接收到音频信号时,将进入该函数,
判断识别是否有结果,如果没有从新配置寄
存器准备下一次的识别。
**************************************************************************/
void ProcessInt0(void)
{
uint8 nAsrResCount=0;
EX0=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*/
EX0=1;
}
/************************************************************************
功能描述: 运行ASR识别流程
入口参数: none
返 回 值: asrflag:1->启动成功, 0—>启动失败
其他说明: 识别顺序如下:
1、RunASR()函数实现了一次完整的ASR语音识别流程
2、LD_AsrStart() 函数实现了ASR初始化
3、LD_AsrAddFixed() 函数实现了添加关键词语到LD3320芯片中
4、LD_AsrRun() 函数启动了一次ASR语音识别流程
任何一次ASR识别流程,都需要按照这个顺序,从初始化开始
**************************************************************************/
uint8 RunASR(void)
{
uint8 i=0;
uint8 asrflag=0;
for (i=0; i<5; i++) // 防止由于硬件原因导致LD3320芯片工作不正常,所以一共尝试5次启动ASR识别流程
{
LD_AsrStart();
delay(50);
if (LD_AsrAddFixed()==0)
{
LD_Reset(); // LD3320芯片内部出现不正常,立即重启LD3320芯片
delay(50); // 并从初始化开始重新ASR识别流程
continue;
}
delay(10);
if (LD_AsrRun() == 0)
{
LD_Reset(); // LD3320芯片内部出现不正常,立即重启LD3320芯片
delay(50); // 并从初始化开始重新ASR识别流程
continue;
}
asrflag=1;
break; // ASR流程启动成功,退出当前for循环。开始等待LD3320送出的中断信号
}
return asrflag;
}
/************************************************************************
功能描述: 检测LD模块是否空闲
入口参数: none
返 回 值: flag:1-> 空闲
其他说明: none
**************************************************************************/
uint8 LD_Check_ASRBusyFlag_b2()
{
uint8 j;
uint8 flag = 0;
for (j=0; j<10; j++)
{
if (LD_ReadReg(0xb2) == 0x21)
{
flag = 1;
break;
}
delay(10);
}
return flag;
}
/************************************************************************
功能描述: 启动ASR
入口参数: none
返 回 值: none
其他说明: none
**************************************************************************/
void LD_AsrStart()
{
LD_Init_ASR();
}
/************************************************************************
功能描述: 运行ASR
入口参数: none
返 回 值: 1:启动成功
其他说明: none
**************************************************************************/
uint8 LD_AsrRun()
{
EX0=0;
LD_WriteReg(0x35, MIC_VOL);
LD_WriteReg(0x1C, 0x09);
LD_WriteReg(0xBD, 0x20);
LD_WriteReg(0x08, 0x01);
delay( 1 );
LD_WriteReg(0x08, 0x00);
delay( 1 );
if(LD_Check_ASRBusyFlag_b2() == 0)
{
return 0;
}
// LD_WriteReg(0xB6, 0xa); //识别时间 1S
// LD_WriteReg(0xB5, 0x1E); //背景音段时间 300ms
// LD_WriteReg(0xB8, 10); //结束时间
// LD_WriteReg(0x1C, 0x07); //配置双通道音频信号做为输入信号
LD_WriteReg(0x1C, 0x0b); //配置麦克风做为输入信号
LD_WriteReg(0xB2, 0xff);
delay( 1);
LD_WriteReg(0x37, 0x06);
delay( 1 );
LD_WriteReg(0x37, 0x06);
delay( 5 );
LD_WriteReg(0x29, 0x10);
LD_WriteReg(0xBD, 0x00);
EX0=1;
return 1;
}
/************************************************************************
功能描述: 向LD模块添加关键词
入口参数: none
返 回 值: flag:1->添加成功
其他说明: 用户修改.
1、根据如下格式添加拼音关键词,同时注意修改sRecog 和pCode 数组的长度
和对应变了k的循环置。拼音串和识别码是一一对应的。
2、开发者可以学习"语音识别芯片LD3320高阶秘籍.pdf"中
关于垃圾词语吸收错误的用法,来提供识别效果。
3、”xiao jie “ 为口令,故在每次识别时,必须先发一级口令“小捷”
**************************************************************************/
uint8 LD_AsrAddFixed()
{
uint8 k, flag;
uint8 nAsrAddLength;
#define DATE_A 50 /*数组二维数值*/
#define DATE_B 20 /*数组一维数值*/
uint8 code sRecog[DATE_A][DATE_B] =
{
"da ge",\
"qian jin",\
"hou tui",\
"zuo zhuan",\
"you zhuan",\
"da kai bing xiang",\
"guan bi bing xiang",\
"da kai kong tiao",\
"guan bi kong tiao",\
"quan bu da kai",\
"quan bu guan bi",\
}; /*添加关键词,用户修改*/
uint8 code pCode[DATE_A] =
{
CODE_CMD, \
CODE_1, \
CODE_2, \
CODE_3, \
CODE_4, \
CODE_5, \
CODE_6, \
CODE_7, \
CODE_8, \
CODE_9, \
CODE_10, \
CODE_11, \
CODE_12, \
CODE_13, \
CODE_14, \
CODE_15, \
CODE_16, \
CODE_17, \
CODE_18, \
CODE_19, \
CODE_20, \
CODE_21, \
CODE_22, \
CODE_23, \
CODE_24, \
CODE_25, \
CODE_26, \
CODE_27, \
CODE_28, \
CODE_29, \
CODE_30, \
CODE_31, \
CODE_32, \
CODE_33, \
CODE_34, \
CODE_35, \
CODE_36, \
CODE_37, \
CODE_38, \
CODE_39, \
CODE_40, \
CODE_41, \
CODE_42, \
CODE_43, \
CODE_44, \
CODE_45, \
CODE_46, \
CODE_47, \
CODE_48, \
CODE_49, \
}; /*添加识别码,用户修改*/
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);
delay(1);
LD_WriteReg(0x08, 0x00);
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;
}
/************************************************************************
功能描述: 获取识别结果
入口参数: none
返 回 值: LD_ReadReg(0xc5 ); 读取内部寄存器返回识别码。
其他说明: none
**************************************************************************/
uint8 LD_GetResult()
{
return LD_ReadReg(0xc5 );
}
LDChip.h文章来源地址https://www.toymoban.com/news/detail-457828.html
/*******************************************************
** CPU: STC11L08XE
** 晶振:22.1184MHZ
** 波特率:9600 bit/S
** 口令模式: 即每次识别时都需要说“小杰”这个口令 ,才能够进行下一级的识别
/*********************************************************/
#ifndef LD_CHIP_H
#define LD_CHIP_H
#define uint8 unsigned char
#define uint16 unsigned int
#define uint32 unsigned long
// 以下五个状态定义用来记录程序是在运行ASR识别过程中的哪个状态
#define LD_ASR_NONE 0x00 /* 表示没有在作ASR识别*/
#define LD_ASR_RUNING 0x01 /* 表示LD3320正在作ASR识别中*/
#define LD_ASR_FOUNDOK 0x10 /*表示一次识别流程结束后,有一个识别结果*/
#define LD_ASR_FOUNDZERO 0x11 /*表示一次识别流程结束后,没有识别结果*/
#define LD_ASR_ERROR 0x31 /*表示一次识别流程中LD3320芯片内部出现不正确的状态*/
#define CLK_IN 22.1184 /* 用户注意修改输入的晶振时钟大小 */
#define LD_PLL_11 (uint8)((CLK_IN/2.0)-1)
#define LD_PLL_MP3_19 0x0f
#define LD_PLL_MP3_1B 0x18
#define LD_PLL_MP3_1D (uint8)(((90.0*((LD_PLL_11)+1))/(CLK_IN))-1)
#define LD_PLL_ASR_19 (uint8)(CLK_IN*32.0/(LD_PLL_11+1) - 0.51)
#define LD_PLL_ASR_1B 0x48
#define LD_PLL_ASR_1D 0x1f
//函数声明
void LD_Reset();
void LD_Init_Common();
void LD_Init_ASR();
uint8 RunASR(void);
void LD_AsrStart();
uint8 LD_AsrRun();
uint8 LD_AsrAddFixed();
uint8 LD_GetResult();
//识别码客户修改处
#define CODE_CMD 0x00 //该命令码0x00用户不可进行修改。
#define CODE_1 0x01
#define CODE_2 0x02
#define CODE_3 0x04
#define CODE_4 0x14
#define CODE_5 0x15
#define CODE_6 0x16
#define CODE_7 0x17
#define CODE_8 0x18
#define CODE_9 0x19
#define CODE_10 0x1A
#define CODE_11 0x1B
#define CODE_12 0x1C
#define CODE_13 0x1D
#define CODE_14 0x1E
#define CODE_15 0x1F
#define CODE_16 0x20
#define CODE_17 0x21
#define CODE_18 0x22
#define CODE_19 0x23
#define CODE_20 0x24
#define CODE_21 0x25
#define CODE_22 0x26
#define CODE_23 0x27
#define CODE_24 0x28
#define CODE_25 0x29
#define CODE_26 0x2A
#define CODE_27 0x2B
#define CODE_28 0x2C
#define CODE_29 0x2D
#define CODE_30 0x2E
#define CODE_31 0x2F
#define CODE_32 0x30
#define CODE_33 0x31
#define CODE_34 0x32
#define CODE_35 0x33
#define CODE_36 0x34
#define CODE_37 0x35
#define CODE_38 0x36
#define CODE_39 0x37
#define CODE_40 0x38
#define CODE_41 0x39
#define CODE_42 0x3A
#define CODE_43 0x3B
#define CODE_44 0x3C
#define CODE_45 0x3D
#define CODE_46 0x3E
#define CODE_47 0x3F
#define CODE_48 0x40
#define CODE_49 0x41
//数值越大越灵敏识别距离越远,但误识别率就越大, 根据自己的实际情况调节。
#define MIC_VOL 0x43 //咪头增益(灵敏度调节) 范围:00-7f
#endif
到了这里,关于基于LD3320的51智能遥控语音小车的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!