最近打算做个语音的项目,找到了深圳雷龙发展的LSY201B这款语音模块,写出来安利一下
程序源码:SuiXinSc/Speech-Module (github.com)
或者进入Q群找我获取
目录
一,简要介绍:
硬件参数:
1,处理器:
2,外设:
3,蓝牙:
4,音频:
软件参数:
使用体验:
二,模块定制:
三,测试:
四,应用:
五,总结:
一,简要介绍:
LSYT201B是深圳雷龙发展推出的一款蓝牙离线语音模块,某宝上价格为20元,性价比很高。 详情页
硬件参数:
1,处理器:
基于YT2228芯片,32位处理器,240MHz的频率,支持FPU,内部FLASH为2M,拥有64个中断向量以及4级别中断优先级。
2,外设:
全速USB设备,支持USB1.1
四个多功能16位定时器,支持捕获和PWM模式
三个16位PWM发生器用于电机驱动
三个全双工基本UART,UARTO 和 UART1支持DMA模式
两个SPI接口支持主机模式和设备模式
一个硬件IIC接口,支持主机模式和设备模式
内置Cap Sense Key控制器
10位ADC模拟采样
所有GPIO支持外部唤醒/中断
3,蓝牙:
支持蓝牙V5.3 +BR+EDR +BLE 规范
满足CLASS1,CLASS2 和 CLASS3输送功率的要求
支持GFSK 和 π/4 DQPSK所有数据包类型
提供最大发射功率+6 DBM
接收器最小灵敏度-90 DBM
快速ADC增强动态范围
支持A2DP1.3.2\AVCTP1.4\AVDTP1.3\AVRCP1.6.2\HFP 1.8\SPP 1.2\RFCOMM 1.1\PNP1.3\HID 1.1.1\SDP CORE5.3\L2CAP CORE 5.3
4,音频:
两通道16-bit DAC,SNR>=95dB
一通道16-bit ADC,SNR>=90dB
采样率支持:8KHz/11.025KHz/16KHz/22.05KHz/24KHz/32KHz/44.1KHz/48KHz
一个模拟 MIC 放大器,内置MIC偏置发生器
在 DAC 路径上支持无输出电容模式,单端和差分模式
软件参数:
支持远场拾音,环境降噪,蓝牙控制,小语种识别,支持15个唤醒+免唤醒,最大支持150个关键词,USB音频输出,UART通信,在Windows/Linux下,还支持USB录音功能。支持智云译芯平台,有配套的小程序,在智能家居方面拥有完善的生态。
使用体验:
LSYT201B这款模块确实很好用,拾音非常灵敏,在客厅中用比较小的声音也能捕获到,而且应用非常简单,只需要配置串口即可使用,大大缩短了开发周期。
二,模块定制:
确定好模块词条后,发送给官方定制。词条模板如下:
这个模板可以找官方要,官方有技术人员负责
三,测试:
拿到定制的模块后,先连接好电源(5v),然后接上串口,选择以16进制显示和以16进制发送,接收自动断帧,开始测试
说出唤醒词,看到串口返回了我们定义的数据
再说一下关键词试一下,发现也能返回对应的数据
然后等待10s,发现语音模块正常播放了结束语,串口也接收到了结束数据,模块进入待机模式
四,应用:
LSYT201B的使用非常简单,完全不需要了解任何语音识别有关的技术或是算法,只需一个串口便可以使用,所以先配置一个有两个串口的项目(一个与模块通信,一个与PC通信),由于我要用到舵机,所以加了一个PWM,这两个我前面都讲过了,要注意的是与语音模块通信的那个串口波特率要设置为9600,以及串口中断的优先级要设置一下
PWM:传送门;串口:传送门
另外一点,要想让舵机有较高精度,尽量将预分频减小,自动重装值调大,使得占空比的调节尽量平滑,我这里主频为72MHz,预分频为 36-1,要想得到 50Hz的频率,自动重装值就需要 40000-1
CubeMX配置的过程我直接跳过,直接进入Keil
串口重定向,这里把串口一作为与主机通信的端口
//发送的重定向,重定向以后可以使用printf等函数
int fputc(int ch, FILE *f)
{HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);return ch;
}//接收的重定向,重定向以后可以使用scanf等函数
int fgetc(FILE *f)
{ int ch;HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, 1000); return (ch);
}
接着写一个操纵舵机的程序,关于舵机的操纵我在讲PWM那一篇也讲过了,有兴趣的可以看看
//线性映射
int Linear_Mapping(int now,int as,int ae,int bs,int be){return now*(be-bs)/(ae-as)+bs;
}void Servo_Control(int angle){if(angle>180){angle=180;}else if(angle<0){angle=0;} //约束角度数据__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,Linear_Mapping(angle,0,180,40000*0.025,40000*0.125)); //使用映射法计算计数值
}
函数声明:
int Linear_Mapping(int now,int as,int ae,int bs,int be);
void Servo_Control(int angle);
在主程序中添加测试程序(别忘了勾选微库)
观察到电脑上串口调试助手在每次循环发送一个Hello PC,同时舵机在 0~180度之间旋转,接下来就是对语音模块的操作了
分别在根目录下Code文件夹中Src和Inc文件夹建立lsyt201b.c 和 lsyt201b.h 两个文件,并将 lsyt201b.c 添加到Keil中并打开,添加如下代码:
lsyt201b.c:
#include "lsyt201b.h"
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
#include "usart.h"//定义数据数组
uint8_t Host_RXbuffur[Host_DataSize]={0};
uint8_t LSYT_RXbuffur[LSYT_DataSize]={0};//定义解析标志位
int A_flag = 0;int DataSize = LSYT_DataSize;//串口的空闲接收中断
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart,uint16_t Size){__HAL_UNLOCK(huart); //解锁串口状态if(huart == &huart1){ //如果是主机发送的数据printf("%s",Host_RXbuffur); //数据回显HAL_UARTEx_ReceiveToIdle_IT(&huart1,Host_RXbuffur,Host_DataSize-1); //再次开启空闲中断}else if(huart == & huart2){ //如果是模块发来的数据printf("LSYT_Data:");printf("%X %X %X %X %X %X\r\n",LSYT_RXbuffur[0],LSYT_RXbuffur[1],LSYT_RXbuffur[2],LSYT_RXbuffur[3],LSYT_RXbuffur[4],LSYT_RXbuffur[5]);//转发给电脑A_flag = 1;HAL_UARTEx_ReceiveToIdle_IT(&huart2,LSYT_RXbuffur,LSYT_DataSize-1); //再次开启空闲中断}
}uint8_t LSYT_CMD[][6]={{0x0A,0x02,0x00,0x00,0x00,0xED}, //语音:已执行{0x0A,0x02,0x00,0x00,0x01,0xED}, //语音:执行失败{0x0A,0x02,0x00,0x00,0x02,0xED}, //语音:已完成
};//向模块发送命令
int LSYT201B_SendCMD(uint8_t Data){uint8_t* tmp0 = malloc(sizeof(int)*6);switch(Data){case Executed:memcpy(tmp0,LSYT_CMD[0],6);break;case Failed:memcpy(tmp0,LSYT_CMD[1],6);break;case Completed:memcpy(tmp0,LSYT_CMD[2],6);break;default:return ERROR;}int tmp1 = HAL_UART_Transmit(&huart2,tmp0,6,10);free(tmp0);return tmp1;
}//解析模块数据
int LSYT201B_Analysis(uint8_t* result){if(A_flag == 0){return ERROR;}A_flag = 0;if(LSYT_RXbuffur[0] != 0x0A){ //判断数据是否有效return ERROR;}switch(LSYT_RXbuffur[1]){ //依据数据格式处理数据
/*System:*/case 0x43:result[0] = SystemCMD;result[1] = Close;break;case 0x04:result[0] = SystemCMD;result[1] = Start;break;/*CMD:*/case 0x0F:result[0] = NormalCMD;result[1] = LSYT_RXbuffur[4];break;case 0x0B:result[0] = ExtendCMD;result[1] = LSYT_RXbuffur[4];break;default:return ERROR;}return SUCCESS;
}
lsyt201b.h:
#ifndef __LSYT201B_H_
#define __LSYT201B_H_#include "main.h"//宏定义
#define Host_DataSize 512
#define LSYT_DataSize 8#define Start 0x0F
#define Close 0xF0#define Executed 0xA0
#define Failed 0xA1
#define Completed 0xA2#define SystemCMD 0x00
#define NormalCMD 0x01
#define ExtendCMD 0x02//枚举定义命令
enum Normal_CMD{Crotate = 0x00,Urotate,Forward,FallBack,Lshift,Rshift,Rise,Down,Add,Reduce,Origin = 0x10,Reset
};enum Extend_CMD{CMD0 = 0x00,CMD1,CMD2,CMD3,CMD4,CMD5,
};extern uint8_t Host_RXbuffur[Host_DataSize];
extern uint8_t LSYT_RXbuffur[LSYT_DataSize];int LSYT201B_SendCMD(uint8_t Data);
int LSYT201B_Analysis(uint8_t* result);#endif
然后在主程序中编写程序:
循环中代码:
/* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */if(LSYT201B_Analysis(Data) == SUCCESS){switch(Data[0]){case SystemCMD:break;case NormalCMD:switch(Data[1]){case Origin: last = angle; angle = 90;break;case Reset: angle = last;break;case Crotate: angle -= step;break;case Urotate: angle += step;break;case Add:step += 10;LSYT201B_SendCMD(Completed);break;case Reduce:step -= 10;LSYT201B_SendCMD(Completed);break;}break;case ExtendCMD:switch(Data[1]){case CMD0: LSYT201B_SendCMD(Completed);break;/*…………*/}break;}if(angle > 180){angle = 180;}else if(angle < 0){angle = 0;}printf("%d\r\n",angle);}Servo_Control(angle);}/* USER CODE END 3 */
整个 main.c:
/* USER CODE BEGIN Header */
/********************************************************************************* @file : main.c* @brief : Main program body******************************************************************************* @attention** Copyright (c) 2024 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "lsyt201b.h"/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_TIM2_Init();MX_USART1_UART_Init();MX_USART2_UART_Init();/* USER CODE BEGIN 2 */HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);Servo_Control(0);printf("Hello PC\r\n");HAL_UARTEx_ReceiveToIdle_IT(&huart1,Host_RXbuffur,Host_DataSize-1);HAL_UARTEx_ReceiveToIdle_IT(&huart2,LSYT_RXbuffur,LSYT_DataSize-1);int step = 10;int angle = 90;int last = 0;uint16_t Data[2]={0};/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */if(LSYT201B_Analysis(Data) == SUCCESS){switch(Data[0]){case SystemCMD:break;case NormalCMD:switch(Data[1]){case Origin: last = angle; angle = 90;break;case Reset: angle = last;break;case Crotate: angle -= step;break;case Urotate: angle += step;break;case Add:step += 10;LSYT201B_SendCMD(Completed);break;case Reduce:step -= 10;LSYT201B_SendCMD(Completed);break;}break;case ExtendCMD:switch(Data[1]){case CMD0: LSYT201B_SendCMD(Completed);break;/*…………*/}break;}if(angle > 180){angle = 180;}else if(angle < 0){angle = 0;}printf("%d\r\n",angle);}Servo_Control(angle);}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/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();}/** Initializes the CPU, AHB and APB buses clocks*/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();}
}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @brief This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#ifdef USE_FULL_ASSERT
/*** @brief Reports the name of the source file and the source line number* where the assert_param error has occurred.* @param file: pointer to the source file name* @param line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
看效果:
LSYT201B语音模块效果展示
五,总结:
LSYT201B模块具有价格低廉,性能优异,应用简单等优点,更多参数可以在深圳雷龙发展官网自行搜索查看,大家可以入手一个试试。