1.可以通过简单的 I/O 操作实现小车的前进、后退、左转、右转功能;
2.配合 SPCE061A 的语音特色,利用系统的语音播放和语音识别资源,实现语音控制的功能; 3.可以在行走过程中声控改变小车运动状态; 4.在超出语音控制范围时能够自动停车。 2.2 参数说明
车体:双电机两轮驱动
供电:电池(四节 AA:1.2V×4 或 1.5V×4) 工作电压:DC 4V~6V
工作电流:运动时约 200mA
3. SPCE061A特性简介 SPCE061A是一款性价比很高的十六位单片机,使用它可以非常方便灵活的实现语音的录放,该芯片拥有8路10位精度的 ADC,其中一路为音频转换通道,并且内置有自动增益电路。这为实现语音录入提供了方便的硬件条件。两路10位精度的DAC,只需要外接功放(SPY0030A)即可完成语音的播放。该单片机具有一套易学易用的指令系统和集成开发环境,在此环境中,它支持标准 C 语言编程,也支持 C 语言与汇编语言的互相调用。另外还提供了语音录放的库函数,只要了解库函数的使用,就可以很容易的完成语音的录放、识别等功能,这些都为软件开发提供了方便的条件。 SPCE061A特性:
16位μ’nSP微处理器;
工作电压:内核工作电压VDD为 3.0V~3.6V(CPU),I/O口工作电压VDDH为VDD~5.5V(I/O); CPU时钟:0.32MHz~49.152MHz; 内置2K 字 SRAM; 内置32K 闪存 ROM; 可编程音频处理; 晶体振荡器;
系统处于备用状态下(时钟处于停止状态),耗电小于 2μA@3.6V;
2 个 16 位可编程定时器/计数器(可自动预置初始计数值); 2 个 10 位 DAC(数-模转换)输出通道; 32 位通用可编程输入/输出端口;
14 个中断源可来自定时器 A / B,时基,2 个外部时钟源输入,键唤醒; 具备触键唤醒的功能;
使用音频编码 SACM_S240 方式(2.4K 位/秒),能容纳 210 秒的语音数据; 锁相环 PLL 振荡器提供系统时钟信号; 32768Hz 实时时钟;
7 通道 10 位电压模-数转换器(ADC)和单通道声音模-数转换器;
声音模-数转换器输入通道内置麦克风放大器和自动增益控制(AGC)功能; 具备串行设备接口;
低电压复位(LVR)功和低电压监测(LVD)功能;
内置在线仿真板(IC E,In-C ircuitEm ulator)接口。
4、系统总体方案介绍
1
小车的运动控制采用语音控制和中断定时控制相结合,通过语音触发小车动作,小车动作之后,随时可以通过语音指令改变小车的运动状态。在每一次动作触发的同时启动定时器,如果小车由于某些原因不能正常的接收语音指令,则只要定时时间一到,中断服务程序就会发出指令让小车停下来。
图1 控制系统所需硬件
5、系统硬件设计 系统的硬件方面,由于大部分的功能实现都是在61板上完成的,只有电机控制部分电路另外设计在一块的电路板上,我们称之为控制板。下面详细的介绍小车的结构和运行原理以及控制电路板的结构和功能实现。
图2 系统硬件框图
2
图3 系统硬件组装效果图
5.1 车体介绍
语音控制小车为四轮结构。其中前面两个车轮由前轮电机控制,在连杆和支点作用下控制前轮左右摆动,来调节小车的前进方向。在自然状态下,前轮在弹簧作用下保持中间位置。后面两个车轮由后轮电机驱动,为整个小车提供动力。所以又称前面的轮子为方向轮,后面的两个轮子为驱动轮。
5.2 小车的行走原理.
直走:由小车的结构分析,在自然状态下,前轮在弹簧作用下保持中间状态,这是只要后轮电机正转小车就会前进。
倒车:倒车动作和前进动作刚好相反,前轮电机仍然保持中间状态,后轮电机反转,小车就会向后运动。
图4 小车前进、后退示意图
左转:前轮电机逆时针旋转(规定为正转),后轮电机正转,这时小车就会在前后轮共同作用下朝左侧前进。 右转:前轮电机反转,后轮电机正转,这时小车就是会在前后轮共同作用下朝右侧前进。
3
图5 小车转向示意图
5.3 控制板原理图
控制板主要包括:接口电路、电源电路和两路电机的驱动电路,控制板原理图如下。
接口电路:接口电路负责将61板的I/O接口信号传送给控制电路板,I/O信号主要为控制电机需要的IOB8~IOB11这四路信号,同时为了方便后续的开发和完善,预留了IOB12~IOB15 以及IOA8~IOA15接口,可以在这些接口上添加一些传感器。
电源部分:整个小车有4个电源信号:电池电源,控制板工作电源,61板工作电源,61板的I/O输出电源。系统供电由电池提供,控制板直接采用电池供电(VCC),然后经二极管D1后产生61板电源SPCE061A 在语音控制小车中的应用(VCC_61),通过61板的Vio跳线产生61板的端口电源(V1)。
图6 小车控制电路图
6.1 系统的主程序设计 系统的主程序流程如下图所示:
4
图7 主程序流程图
共分为四大部分:初始化部分、训练部分、识别部分、重训操作。
初始化部分:初始化操作将 IOB8~IOB11 设置为输出端,用以控制电机。必要时还要有对应的输入端设置和 PWM 端口设置等。
训练部分:训练部分完成的工作就是建立语音模型。程序一开始判断小车是否被训练过,如果没有训练过则要求对其进行训练,并且会在训练成功之后将训练的模型存储到 Flash,在以后使用时不需要重新训练;如果已经训练过会把存储在 Flash 中的模型调出来装载到辨识器中。
识别部分:在识别环节当中,如果辨识结果是名字,停止当前的动作并进入待命状态,然后等待动作命令。如果辨识结果为动作指令小车会语音告知相应动作并执行该动作,在运动过程中可以通过呼叫小车SPCE061A在语音控制小车中的应用的名字使小车停下来。
重训操作:考虑到有重新训练的需求,设置了重新训练的按键(61 板的 KEY3),
5
循环扫描该按键,一旦检测到此键按下,则将擦除训练标志位(0xe000 单元),并等待复位。复位后,程序重新执行,当检测到训练标志位为 0xffff 时会要求重新对其进行训练。
6.2主控制源程序: //====================================================== // The information contained herein is the exclusive property of
// Sunnnorth Technology Co. And shall not be distributed, reproduced, // or disclosed in whole in part without prior written permission. // (C) COPYRIGHT 2003 SUNNORTH TECHNOLOGY CO. // ALL RIGHTS RESERVED
// The entire notice above must be reproduced on all authorized copies.
//======================================================== //======================================================== // 工程名称: Car_Demo
// 功能描述: 实现小车的语音控制 // 涉及的库: CMacro1016.lib // bsrv222SDL.lib // sacmv26e.lib // 组成文件: main.c // Flash.asm, hardware.asm,ISR.asm // hardware.h,s480.h, hardware.inc // 硬件连接: IOA0-----KEY1 // IOA1-----KEY2 // IOA2-----KEY3 // IOB8-----前进 // IOB9-----倒车 // IOB10----左拐 // IOB11----右拐 // 维护记录: 2005-12-12 v1.0
//========================================================
#include \"s480.h\" #include \"bsrsd.h\"
#define P_IOA_Data (volatile unsigned int *)0x7000 #define P_IOA_Dir (volatile unsigned int *)0x7002 #define P_IOA_Attrib (volatile unsigned int *)0x7003 #define P_IOB_Data (volatile unsigned int *)0x7005 #define P_IOB_Dir (volatile unsigned int *)0x7007 #define P_IOB_Attrib (volatile unsigned int *)0x7008 #define P_TimerA_Data (volatile unsigned int *)0x700A #define P_TimerA_Ctrl (volatile unsigned int *)0x700B #define P_TimerB_Data (volatile unsigned int *)0x700C #define P_TimerB_Ctrl (volatile unsigned int *)0x700D #define P_Watchdog_Clear (volatile unsigned int *)0x7012
6
#define P_INT_Mask (volatile unsigned int *)0x702D #define P_INT_Clear (volatile unsigned int *)0x7011 #define NAME_ID 0x100 #define COMMAND_GO_ID 0x101 #define COMMAND_BACK_ID 0x102 #define COMMAND_LEFT_ID 0x103 #define COMMAND_RIGHT_ID 0x104 #define S_NAME 0 //给我取个名字吧 #define S_ACT1 1 //前进 #define S_ACT2 2 //倒车,请注意 #define S_ACT3 3 //左拐 #define S_ACT4 4 //右拐 #define S_RDY 5 //Yeah #define S_AGAIN 6 //请再说一遍 #define S_NOVOICE 7 //没有听到任何声音 #define S_CMDDIFF 8 //说什么暗语呀 #define S_NOISY 8 //说什么暗语呀 #define S_START 9 //准备就绪,开始辨识 #define S_GJG 10 //拐就拐 #define S_DCZY 11 //倒车,请注意 extern unsigned int BSR_SDModel[100]; //外部变量BSR_SDModel[100],辨识器自带
extern void F_FlashWrite1Word(unsigned int addr,unsigned int Value); extern void F_FlashErase(unsigned int sector); unsigned int uiTimeset = 3; //运行时间定时,调整该参数控制运行时间
unsigned int uiTimecont; //运行时间计时
//============================================================= // 语法格式: void Delay(); // 实现功能: 延时 // 参数: 无 // 返回值: 无
//============================================================= void Delay() { unsigned int i; for(i=0;i<0x3Fff;i++) { *P_Watchdog_Clear=0x0001; } }
//============================================================= // 语法格式: void PlaySnd(unsigned SndIndex,unsigned DAC_Channel); // 实现功能: 语音播放函数
7
// 参数: SndIndex-播放语音资源索引号 // DAC_Channel-播放声道选择 // 返回值: 无
//============================================================= void PlaySnd(unsigned SndIndex,unsigned DAC_Channel) { BSR_StopRecognizer(); //停止识别器 SACM_S480_Initial(1); //初始化为自动播放 SACM_S480_Play(SndIndex, DAC_Channel, 3); //开始播放一段语音 while((SACM_S480_Status()&0x0001)!= 0) //是否播放完毕? { SACM_S480_ServiceLoop(); //解码并填充队列 *P_Watchdog_Clear=0x0001; //清看门狗 } SACM_S480_Stop(); //停止播放 BSR_InitRecognizer(BSR_MIC); //初始化识别器 }
//============================================================= // 语法格式: int TrainWord(int WordID,int SndID); // 实现功能: 训练一条指令 // 参数: WordID-指令编码 // SndID-指令提示音索引号 // 返回值: 无
//============================================================= int TrainWord(unsigned int WordID,unsigned int SndID) { int Result; PlaySnd(SndID,3); //引导训练,播放指令对应动作 while(1) { Result = BSR_Train(WordID,BSR_TRAIN_TWICE); //训练两次,获得训练结果 if(Result==0)break; switch(Result) { case -1: //没有检测出声音 PlaySnd(S_NOVOICE,3); return -1; case -2: //需要训练第二次 PlaySnd(S_AGAIN,3); break; case -3: //环境太吵 PlaySnd(S_NOISY,3);
8
return -3; case -4: //数据库满 return -4; case -5: //检测出声音不同 PlaySnd(S_CMDDIFF,3); return -5; case -6: //序号错误 return -6; default: break; } } return 0; }
//============================================================= // 语法格式: void TrainSD(); // 实现功能: 训练函数 // 参数: 无 // 返回值: 无
//============================================================= void TrainSD() { while(TrainWord(NAME_ID,S_NAME) != 0) ; //训练名称 while(TrainWord(COMMAND_GO_ID,S_ACT1) != 0) ; //训练第1个动作 while(TrainWord(COMMAND_BACK_ID,S_ACT2) != 0) ; //训练第2个动作 while(TrainWord(COMMAND_LEFT_ID,S_ACT3) != 0) ; //训练第3个动作 while(TrainWord(COMMAND_RIGHT_ID,S_ACT4) != 0) ; //训练第4个动作 }
//============================================================= // 语法格式: void StoreSD(); // 实现功能: 存储语音模型函数 // 参数: 无 // 返回值: 无
//============================================================= void StoreSD() { unsigned int ulAddr,i,commandID,g_Ret; F_FlashWrite1Word(0xef00,0xaaaa); F_FlashErase(0xe000); F_FlashErase(0xe100); F_FlashErase(0xe200); ulAddr=0xe000;//******** for(commandID=0x100;commandID<0x105;commandID++) { g_Ret=BSR_ExportSDWord(commandID);
9
while(g_Ret!=0) //模型导出成功? g_Ret=BSR_ExportSDWord(commandID); for(i=0;i<100;i++) //保存语音模SD1(0xe000---0xe063) { F_FlashWrite1Word(ulAddr,BSR_SDModel[i]); ulAddr+=1; } } }
//============================================================= // 语法格式: void StoreSD(); // 实现功能: 装载语音模型函数 // 参数: 无 // 返回值: 无
//============================================================= void LoadSD() { unsigned int *p,k,jk,Ret,g_Ret; p=(int *)0xe000; for(jk=0;jk<5;jk++) { for(k=0;k<100;k++) { Ret=*p; BSR_SDModel[k]=Ret; //装载语音模型 p+=1; } g_Ret=BSR_ImportSDWord(); while(g_Ret!=0) //模型装载成功? g_Ret=BSR_ImportSDWord(); } }
//============================================================= // 语法格式: void GoAhead(); // 实现功能: 前进子函数 // 参数: 无 // 返回值: 无
//============================================================= void GoAhead() //前进 { PlaySnd(S_ACT1,3); //提示 *P_IOB_Data=0x0100; //前进 *P_INT_Mask |= 0x0004; //以下为中断定时操作
10
型
__asm(\"int fiq,irq\"); uiTimecont = 0; }
//============================================================= // 语法格式: void BackUp(); // 实现功能: 后退子函数 // 参数: 无 // 返回值: 无
//============================================================= void BackUp() //倒退 { PlaySnd(S_DCZY,3); //提示 *P_IOB_Data=0x0200; //倒退 *P_INT_Mask |= 0x0004; //以下为中断定时操作 __asm(\"int fiq,irq\"); uiTimecont = 0; }
//============================================================= // 语法格式: void TurnLeft(); // 实现功能: 左转子函数 // 参数: 无 // 返回值: 无
//============================================================= void TurnLeft() //左转 { PlaySnd(S_GJG,3); *P_IOB_Data=0x0900; //右转 Delay(); //延时 *P_IOB_Data=0x0500; //左转 *P_INT_Mask |= 0x0004; //以下为中断定时操作 __asm(\"int fiq,irq\"); uiTimecont = 0; }
//============================================================= // 语法格式: void TurnRight(); // 实现功能: 右转子函数 // 参数: 无 // 返回值: 无
//============================================================= void TurnRight() //右转 { PlaySnd(S_GJG,3); //语音提示 *P_IOB_Data=0x0500; //左转 Delay(); //延时
11
*P_IOB_Data=0x0900; //右转 *P_INT_Mask |= 0x0004; //以下为中断定时操作 __asm(\"int fiq,irq\"); uiTimecont = 0; }
//============================================================= // 语法格式: void Stop(); // 实现功能: 停车子函数 // 参数: 无 // 返回值: 无
//============================================================= void Stop() //停车 { *P_IOB_Data=0x0000; //停车 PlaySnd(S_RDY,3); //语音提示 }
//============================================================= // 语法格式: void BSR(void); // 实现功能: 辨识子函数 // 参数: 无 // 返回值: 无
//============================================================= void BSR(void) { int Result; //辨识结果寄存 Result = BSR_GetResult(); //获得识别结果 if(Result>0) //有语音触发? { *P_IOB_Data=0x0000; //临时停车 switch(Result) { case NAME_ID: //识别出名称命令 Stop(); //停车待命 break; case COMMAND_GO_ID: //识别出第一条命令 GoAhead(); //执行动作一:直走 break; case COMMAND_BACK_ID: //识别出第二条命令 BackUp(); //执行动作二:倒车 break; case COMMAND_LEFT_ID: //识别出第三条命令 TurnLeft(); //执行动作三:左转 break;
12
case COMMAND_RIGHT_ID: //识别出第四条命令 TurnRight(); //执行动作四:右转 break; default: break; } } }
//============================================================= // 语法格式: void IRQ5(void); // 实现功能: 中断服务子函数 // 参数: 无 // 返回值: 无
//============================================================= void IRQ5(void)__attribute__((ISR)); //运动定时控制 void IRQ5(void) { if(uiTimecont++ == uiTimeset) { *P_IOB_Data = 0x0000; } *P_INT_Clear = 0x0004; }
//============================================================= // 语法格式: int main(void); // 实现功能: 主函数 // 参数: 无 // 返回值: 无
//============================================================= int main(void)
{ unsigned int BS_Flag; //Train标志位 *P_IOA_Dir=0xff00; //初始化IOA,IOA0~7下拉输入 *P_IOA_Attrib=0xff00; *P_IOA_Data=0x0000; *P_IOB_Dir=0x0f00; //初始化IOB,IOB8~11同向输出 *P_IOB_Attrib=0x0f00; *P_IOB_Data=0x0000; BSR_DeleteSDGroup(0); //初始化存储器RAM BS_Flag=*(unsigned int *)0xe000; //读存储单元0xe000 if(BS_Flag==0xffff) //没有经过训练(0xe000内容为0xffff) { TrainSD(); //训练
13
}
StoreSD(); }
else { LoadSD(); }
PlaySnd(S_START,3); BSR_InitRecognizer(BSR_MIC); while(1) { BSR(); if((*P_IOA_Data)&0x0004) { F_FlashErase(0xe000); while(1); } }
//存储训练结果(语音模型) //经过训练(0xe000内容为0x0055) //语音模型载入识别器 //开始识别提示 //初始化识别器
//是否重新训练
6.3 语音识别的原理简介 语音识别主要分为“训练”和“识别”两个阶段。在训练阶段,单片机对采集到的语音样本进行分析处理,从中提取出语音特征信息,建立一个特征模型;在识别阶段,单片机对采集到的语音样本也进行类似的分析处理,提取出语音的特征信息,然后将这个特征信息模型与已有的特征模型进行对比,如果二者达到了一定的匹配度,则输入的语音被识别。语音识别的具体流程如下图所示:
14
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- awee.cn 版权所有 湘ICP备2023022495号-5
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务