高性价比语音模块:LSYT201B离线语音芯片学习使用

2024-09-20 10:08:14 雷龙发展

  最近打算做个语音的项目,找到了深圳雷龙发展的LSY201B这款语音模块,写出来安利一下

  程序源码:SuiXinSc/Speech-Module (github.com)

  目录

  一,简要介绍:

  硬件参数:

  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

  串口重定向,这里把串口一作为与主机通信的端口

LSYT201B语音模组的使用
雷龙离线语音模块的应用

LSYT201B的使用应用测试
雷龙语音识别芯片有关的技术或是算法

//发送的重定向,重定向以后可以使用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语音模块效果展示

  五,总结:

  LSYT201B模块具有价格低廉,性能优异,应用简单等优点,更多参数可以在深圳雷龙发展官网自行搜索查看,大家可以入手一个试试。

————————————————

【本文转载自CSDN,作者:岁心

服务电话&邮箱

Tel:13691982107(优先)17727831243

QQ:1302648372 | line@longsto.com

对外联系邮箱:info@longsto.com

投诉:ceo@longsto.com |13923450403

地址:深圳市龙华区民治街道展滔科技大厦B座1907室

首页
产品
资讯
联系