目录
理论篇在这,依旧是深圳雷龙发展的语音模块。
一、定制词条
因为我想后面加到我的毕设上加个语音模块,所以定制的词条都是和芯测相关的。
|-----------|--------|--------|-------------------|
| 动作 | 词条 | 播报 | 串口输出(9600) |
| 开机播报 | | | 无 |
| 10S自动退出唤醒 | | 有需要再叫我 | 无 |
| 唤醒词 | 你好小龙 | 我在 | FE 04 00 00 02 FD |
| 命令词 | 录制音频 | 开始录制 | FE 04 00 01 03 FD |
| 命令词 | 播放音频 | 开始播放 | FE 04 00 02 04 FD |
| 命令词 | 显示红色 | 显示红色 | FE 04 00 03 05 FD |
| 命令词 | 显示多色 | 显示多色 | FE 04 00 04 06 FD |
| 命令词 | 调节背光 | 调节背光 | FE 04 00 05 07 FD |
| 命令词 | 时钟测试 | 开始测试 | FE 04 00 06 08 FD |
| 命令词 | 四八五测试 | 开始测试 | FE 04 00 07 09 FD |
| 命令词 | 看测试 | 开始测试 | FE 04 00 08 0A FD |
| 命令词 | 按键测试 | 开始测试 | FE 04 00 09 0B FD |
| 命令词 | 查看温度 | 查看温度 | FE 04 00 0A 0C FD |
| 命令词 | 开始网络通信 | 开始网络通信 | FE 04 00 0B 0D FD |
| 命令词 | 关闭网络通信 | 关闭网络通信 | FE 04 00 0C 0E FD |
| 命令词 | 关闭显示器 | 关闭显示器 | FE 04 00 0D 0F FD |
| 命令词 | 打开显示器 | 打开显示器 | FE 04 00 0E 10 FD |
| 命令词 | 查看环境温度 | 查看环境温度 | FE 04 00 0F 11 FD |
| 命令词 | 查看环境湿度 | 查看环境湿度 | FE 04 00 10 12 FD |
| 命令词 | 查看当前位置 | 查看单签位置 | FE 04 00 11 13 FD |
| 命令词 | 前进 | 前进 | FE 04 00 12 14 FD |
| 命令词 | 后退 | 后退 | FE 04 00 13 15 FD |
| 命令词 | 停止 | 停止 | FE 04 00 14 16 FD |
二、直接用串口通信
|------|------|------|------|------|------|
| 起始码 | 长度 | 方向 | 动作ID | SUM | 结束码 |
| 0xFE | 0x04 | 0x00 | 0xXX | 0xXX | 0xFD |
和技术人员沟通电源最好用5V的供电,我直接接串口用PC做了下测试
因为这个接线柱是2.0的所以不能直接用杜邦线,杜邦线是2.54的。所欲我就扒了个皮给他焊上了,防止不同接线柱之间连电,这里需要保留一部分塑料。
随便测了几个指令这里拾音度是真的高很灵敏。比我之前做的那个灵敏。但是还是那个缺点,不能自己改语音指令有点难受。
为了低功耗,所以这类语音模块都是那种唤醒词形式的。像咱们的手机小爱同学,hi,Siri等等这种,我的这个叫你好小龙。
总体来说可定制化很高比那种自己可以拿SDK烧写的要高很多,缺点是没SDK。
音量的调节也比较麻烦需要修改电阻的大小。具体怎么修改到时候可以问技术人员
大概就是修改这两个电阻。
三、使用单片机通信
重点来咯,怎么用单片机实现,之前想着用I.MAX6ULL来着,但是我现在没时间,就用经典c8t6来做个demo吧。很好一年没写32的程序了已经忘的差不多了哈哈。
先说说思路,初始化串口1和串口2.串口2接我们的模块,接收到指令后分析一下转化成对应语句打印到串口1很简单的程序,为什么不真的来控制一下呢,还是那句话,没时间。c8t6最小系统没有板载传感器,连灯泡也就一个。难受的很我要自己焊接,属实麻烦嘿嘿。各位读者朋友见谅哈。作者要做毕设,时间紧任务重呀,用韦东山老师的板子本来以为有移植好的鸿蒙和驱动,我只做服务器客户端还有通信就可用呢。但是被骗了,裸机写的驱动程序,和鸿蒙没有一毛钱关系。我要开发14个驱动程序还要学习鸿蒙应用层开发,以及最难的。把鸿蒙移植到I.MAX6ULL上。所以木有办法咯,抱歉抱歉后面有机会再来好好写写怎么用语音模块。
下面是串口2的驱动程序,基于标准库的,为什么叫ESP8266因为我懒所以拿那个代码改的哈哈。
cpp
/* 函数体 --------------------------------------------------------------------*/
/**
* 函数功能: 初始化ESP8266用到的GPIO引脚
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
static void ESP8266_GPIO_Config ( void )
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
/* 配置 CH_PD 引脚*/
RCC_APB2PeriphClockCmd( ESP8266_RST_CLK, ENABLE );
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/* 配置 RST 引脚*/
GPIO_InitStructure.GPIO_Pin = ESP8266_RST_PIN;
GPIO_Init ( ESP8266_RST_PORT, & GPIO_InitStructure );
/* 拉高WiFi模块的复位重启引脚 */
GPIO_ResetBits( ESP8266_RST_PORT, ESP8266_RST_PIN );
}
/**
* 函数功能: 配置 ESP8266 USART 的 NVIC 中断优先级
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
static void ESP8266_USART_NVIC_Configuration ( void )
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 );
/* Enable the USART2 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = ESP8266_USART_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**
* 函数功能: 初始化ESP8266用到的 USART
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
static void ESP8266_USART_Config ( void )
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* config USART clock */
ESP8266_USART_APBxClock_FUN ( ESP8266_USART_CLK, ENABLE );
ESP8266_USART_GPIO_APBxClock_FUN ( ESP8266_USART_GPIO_CLK | RCC_APB2Periph_AFIO, ENABLE );
/* USART GPIO config */
/* Configure USART Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = ESP8266_USART_TX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(ESP8266_USART_TX_PORT, &GPIO_InitStructure);
/* Configure USART Rx as input floating */
GPIO_InitStructure.GPIO_Pin = ESP8266_USART_RX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(ESP8266_USART_RX_PORT, &GPIO_InitStructure);
/* USART1 mode config */
USART_InitStructure.USART_BaudRate = ESP8266_USART_BAUD_RATE;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(ESP8266_USARTx, &USART_InitStructure);
/* 中断配置 */
USART_ITConfig ( ESP8266_USARTx, USART_IT_RXNE, ENABLE ); //使能串口接收中断
USART_ITConfig ( ESP8266_USARTx, USART_IT_IDLE, ENABLE ); //使能串口总线空闲中断
ESP8266_USART_NVIC_Configuration();
USART_Cmd(ESP8266_USARTx, ENABLE);
/* 清除发送完成标志 */
USART_ClearFlag(ESP8266_USARTx, USART_FLAG_TC|USART_FLAG_TXE|USART_FLAG_RXNE);
}
/**
* 函数功能: 格式化输出,类似于C库中的printf,但这里没有用到C库
* 输入参数: USARTx 串口通道,这里只用到了串口2,即USART2
* Data 要发送到串口的内容的指针
* ... 其他参数
* 返 回 值: 无
* 说 明:典型应用 USART2_printf( USART2, "\r\n this is a demo \r\n" );
* USART2_printf( USART2, "\r\n %d \r\n", i );
* USART2_printf( USART2, "\r\n %s \r\n", j );
*/
void USART_printf(USART_TypeDef * USARTx, char * Data, ... )
{
const char *s;
int d;
char buf[16];
va_list ap;
va_start(ap, Data);
while ( * Data != 0 ) // 判断是否到达字符串结束符
{
if ( * Data == 0x5c ) //'\'
{
switch ( *++Data )
{
case 'r': //回车符
USART_SendData(USARTx, 0x0d);
Data ++;
break;
case 'n': //换行符
USART_SendData(USARTx, 0x0a);
Data ++;
break;
default:
Data ++;
break;
}
}
else if ( * Data == '%')
{ //
switch ( *++Data )
{
case 's': //字符串
s = va_arg(ap, const char *);
for ( ; *s; s++)
{
USART_SendData(USARTx,*s);
while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
}
Data++;
break;
case 'd':
//十进制
d = va_arg(ap, int);
itoa(d, buf, 10);
for (s = buf; *s; s++)
{
USART_SendData(USARTx,*s);
while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
}
Data++;
break;
default:
Data++;
break;
}
}
else USART_SendData(USARTx, *Data++);
while ( USART_GetFlagStatus ( USARTx, USART_FLAG_TXE ) == RESET );
}
}
/**
* 函数功能: 将整形数据转换成字符串
* 输入参数: radix =10 表示10进制,其他结果为0
* value 要转换的整形数
* buf 转换后的字符串
* radix = 10
* 返 回 值: 无
* 说 明:被USART_printf()调用
*/
static char * itoa( int value, char *string, int radix )
{
int i, d;
int flag = 0;
char *ptr = string;
/* This implementation only works for decimal numbers. */
if (radix != 10)
{
*ptr = 0;
return string;
}
if (!value)
{
*ptr++ = 0x30;
*ptr = 0;
return string;
}
/* if this is a negative value insert the minus sign. */
if (value < 0)
{
*ptr++ = '-';
/* Make the value positive. */
value *= -1;
}
for (i = 10000; i > 0; i /= 10)
{
d = value / i;
if (d || flag)
{
*ptr++ = (char)(d + 0x30);
value -= (d * i);
flag = 1;
}
}
/* Null terminate the string. */
*ptr = 0;
return string;
} /* NCL_Itoa */
/**
* 函数功能: ESP8266初始化函数
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
void ESP8266_Init ( void )
{
ESP8266_GPIO_Config ();
ESP8266_USART_Config ();
}
下面是串口1的初始化和输入输出重定向
cpp
void DEBUG_USART_Init(void)
{
/* 定义IO硬件初始化结构体变量 */
GPIO_InitTypeDef GPIO_InitStructure;
/* 定义USART初始化结构体变量 */
USART_InitTypeDef USART_InitStructure;
/* 使能USART时钟 */
DEBUG_USARTx_ClockCmd(DEBUG_USARTx_CLK,ENABLE);
/* 使能USART功能GPIO时钟 */
DEBUG_USARTx_GPIO_ClockCmd(DEBUG_USARTx_TX_CLK | DEBUG_USARTx_RX_CLK | RCC_APB2Periph_AFIO,ENABLE);
/* 调试USART功能GPIO初始化 */
/* 设定USART发送对应IO编号 */
GPIO_InitStructure.GPIO_Pin = DEBUG_USARTx_TX_PIN;
/* 设定USART发送对应IO模式:复用推挽输出 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
/* 设定USART发送对应IO最大操作速度 :GPIO_Speed_50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/* 初始化USART发送对应IO */
GPIO_Init(DEBUG_USARTx_TX_PORT, &GPIO_InitStructure);
/* 设定USART接收对应IO编号 */
GPIO_InitStructure.GPIO_Pin = DEBUG_USARTx_RX_PIN;
/* 设定USART发送对应IO模式:浮空输入 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
/* 其他没有重新赋值的成员使用与串口发送相同配置 */
/* 初始化USART接收对应IO */
GPIO_Init(DEBUG_USARTx_RX_PORT, &GPIO_InitStructure);
/* USART工作环境配置 */
/* USART波特率:115200 */
USART_InitStructure.USART_BaudRate = DEBUG_USARTx_BAUDRATE;
/* USART字长(有效位):8位 */
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
/* USART停止位:1位 */
USART_InitStructure.USART_StopBits = USART_StopBits_1;
/* USART校验位:无 */
USART_InitStructure.USART_Parity = USART_Parity_No ;
/* USART硬件数据流控制(硬件信号控制传输停止):无 */
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
/* USART工作模式使能:允许接收和发送 */
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
/* 初始化USART */
USART_Init(DEBUG_USARTx, &USART_InitStructure);
/* 使能USART */
USART_Cmd(DEBUG_USARTx, ENABLE);
}
/**
* 函数功能: 重定向c库函数printf到USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到调试串口 */
USART_SendData(DEBUG_USARTx, (uint8_t) ch);
/* 等待串口数据发送完毕 */
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
return (ch);
}
/**
* 函数功能: 重定向c库函数getchar,scanf到USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fgetc(FILE *f)
{
/* 等待串口输入数据 */
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(DEBUG_USARTx);
}
主要是中断处理,在中断接收数据并存入缓冲区然后主函数中对缓冲区内容与ID进行比对,最后打印到串口助手。
cpp
void ESP8266_USART_INT_FUN(void)
{
uint8_t ucCh;
count++;
if ( USART_GetITStatus (ESP8266_USARTx, USART_IT_RXNE ) != RESET )
{
// ucCh = USART_ReceiveData(ESP8266_USARTx );
// ucaRxBuf[count] = ucCh;
if ( strEsp8266_Fram_Record .InfBit .FramLength < ( RX_BUF_MAX_LEN - 1 ) ) //预留1个字节写结束符
strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ++ ] = ucCh;
}
if ( USART_GetITStatus(ESP8266_USARTx, USART_IT_IDLE ) == SET ) //数据帧接收完毕
{
if(strEsp8266_Fram_Record .InfBit .FramLength >= 6)
{
ucTcpClosedFlag = 1;
strEsp8266_Fram_Record .InfBit .FramFinishFlag = 1;
strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength++ ] = '\0';
}
ucCh = USART_ReceiveData(ESP8266_USARTx );
//ucTcpClosedFlag = strstr(strEsp8266_Fram_Record .Data_RX_BUF, "CLOSED\r\n" ) ? 1 : 0;
}
else
{
strEsp8266_Fram_Record .InfBit .FramFinishFlag = 0;
//ucTcpClosedFlag = 0;
}
}
稍微修改了一下。
主函数的逻辑大家按照自己的需要去做就行,接收到什么ID对应去操作什么器件。我这里就直接解析并且打印了。