语音模块学习——LSYT201B模组(实际操作篇)

目录

一、定制词条

二、直接用串口通信

三、使用单片机通信


理论篇在这,依旧是深圳雷龙发展的语音模块。

http://t.csdnimg.cn/2SzJL

一、定制词条

因为我想后面加到我的毕设上加个语音模块,所以定制的词条都是和芯测相关的。

|-----------|--------|--------|-------------------|
| 动作 | 词条 | 播报 | 串口输出(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对应去操作什么器件。我这里就直接解析并且打印了。

相关推荐
南宫生38 分钟前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
sanguine__1 小时前
Web APIs学习 (操作DOM BOM)
学习
数据的世界013 小时前
.NET开发人员学习书籍推荐
学习·.net
四口鲸鱼爱吃盐3 小时前
CVPR2024 | 通过集成渐近正态分布学习实现强可迁移对抗攻击
学习
OopspoO5 小时前
qcow2镜像大小压缩
学习·性能优化
A懿轩A6 小时前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列
居居飒6 小时前
Android学习(四)-Kotlin编程语言-for循环
android·学习·kotlin
kkflash36 小时前
提升专业素养的实用指南
学习·职场和发展
1 9 J7 小时前
数据结构 C/C++(实验五:图)
c语言·数据结构·c++·学习·算法
6.948 小时前
Scala——身份证号码查询籍贯
学习·scala