查看: 1797|回复: 6

TW_TTS语音合成系列教程——TW_TTS和其它单片机串口通讯范例

[复制链接]

27

主题

715

帖子

4629

积分

版主

Rank: 7Rank: 7Rank: 7

积分
4629
发表于 2026-1-9 16:40:35 | 显示全部楼层 |阅读模式
本帖最后由 hcm0915 于 2026-1-20 14:50 编辑

概述:

  • TW_TTS共有六个引脚,分别是——地:G,电源:V(5V),输入:R,输出:T,喇叭+:SPK+(红线),喇叭-:SPK-(黑线)

注意: a. 语音模块使用 G、V、R 三引脚连接方案时,支持对语音合成播放模式的控制

           b. 语音模块使用 G、V、R、T 四引脚连接方案时,满足原方案应用的同时,还具备语音合成芯片状态的查询功能  

image.png


  • 支持简体中文及英文单字母合成,兼容GB2312和UTF-8编码能智能解析标点、多音字与数字,还可通过标记自定义发音和停顿,单次合成文本不超4K字节。
  • 模块提供10级音量、语速、语调可调,默认中等档位,同时支持暂停、继续、停止合成等控制指令,操作灵活,满足不同场景下的语音输出需求。
  • 内置15种提示音效,含5首铃声、5首信息提示音和5首警示音,分类清晰,可直接调用对应音效,丰富语音交互的多样性。
  • 采用9600波特率的串口协议,1位起始位、8位数据位、1位停止位且无校验,通讯参数明确,连接上位机或MCU便捷。

语音合成模块指令协议表
可以通过连接电脑进行串口指令调试:
image.png
image.png

指令类型
指令格式(十六进制)
参数说明
播放实例(好好搭搭)
0xFD 0x00 0x0A 0x01 0x00 0xBA 0xC3 0xBA 0xC3 0xB4 0xEE 0xB4 0xEE
固定指令,用于播放 “好好搭搭” 音频
音量调整
0xFD 0x00 0x06 0x01 0x01 0x5B 0x76 0x(30-39) 0x5D
0x30-0x39对应音量 [v0]-
[v9]- v0音量最小,v9
音量最大- 默认音量 v5(对应 0x35)
语速调整
0xFD 0x00 0x06 0x01 0x01 0x5B 0x73 0x(30-39) 0x5D
0x30-0x39 对应语速
[s0]-[s9]- s0语速最快,s9语速最慢- 默认语速 s5(对应 0x35)
语调调整
0xFD 0x00 0x06 0x01 0x01 0x5B 0x74 0x(30-39) 0x5D
- 0x30-0x39 对应语调 [t0]-[t9]- t0语调最低,t9
语调最高- 默认语调 t5(对应 0x35)
停止合成
0xFD 0x00 0x01 0x02
无额外参数
暂停合成
0xFD 0x00 0x01 0x03
无额外参数
继续合成
0xFD 0x00 0x01 0x04
无额外参数
铃声播放
0xFD 0x00 0x08 0x01 0x01 0x72 0x69 0x6E 0x67 0x5F 0x(31-35)
0x31-0x35对应铃声 1-5
提示音播放
0xFD 0x00 0x0B 0x01 0x01 0x6D 0x65 0x73 0x73 0x61 0x67 0x65 0x5F 0x(31-35)
0x31-0x35对应提示音 1-5
警示音播放
0xFD 0x00 0x09 0x01 0x01 0x61 0x6C 0x65 0x72 0x74 0x5F 0x(31-35)
0x31-0x35 对应警示音 1-5
查询播放状态
0xFD 0x00 0x01 0x21
无额外参数
播放状态返回值
-
0x4E:播放中
0x4F:空闲状态


STC89C52--C51

电路连接:
image.png

单片机的P3_0引脚(RX)连接语音合成模块的T引脚,单片机的P3_1引脚(TX)连接语音合成模块的R引脚
范例: C51串口控制播放语音

image.png

程序效果:

语音合成模块接入电源上电以后,C51单片机收到指令,控制语音合成播放“初始化完成”之后循环播放”你好“

STM32

电路连接:


image.png

STM32的PA9(TX)引脚接TW_TTS的(R)引脚,STM32的PA10(RX)引脚接TW_TTS的(T)引脚。

范例: stm32串口控制播放语音
TW_TTS.c
  1. #include "usart.h"         
  2. #include "TW_TTS.h"
  3. #include <string.h>
  4. // static  TTS_PLAY[] = {0xfd, 0x00, 0x0a, 0x01, 0x00, 0xba, 0xc3, 0xba, 0xc3, 0xb4, 0xee, 0xb4, 0xee};
  5. static uint8_t  TTS_VOLUME_CMD[] = {0xfd, 0x00, 0x06, 0x01, 0x01, 0x5b, 0x76, 0x30, 0x5d};
  6. static uint8_t  TTS_SPEED_CMD[] = {0xfd, 0x00, 0x06, 0x01, 0x01, 0x5b, 0x73, 0x30, 0x5d};
  7. static uint8_t  TTS_TONE_CMD[] = {0xfd, 0x00, 0x06, 0x01, 0x01, 0x5b, 0x74, 0x30, 0x5d};
  8. static uint8_t  TTS_STOP_CMD[] = {0xfd, 0x00, 0x01, 0x02};
  9. static uint8_t  TTS_PAUSE_CMD[] = {0xfd, 0x00, 0x01, 0x03};
  10. static uint8_t  TTS_RESUME_CMD[] = {0xfd, 0x00, 0x01, 0x04};
  11. static uint8_t  TTS_QUERY_CMD[] = {0xFD, 0x00, 0x02, 0x21, 0x00};
  12. void tts_writeData(unsigned char *DAT, unsigned char len)
  13. {
  14.         HAL_UART_Transmit(&huart1,DAT,len,100);
  15. }
  16. /**
  17. * @brief 播放函数
  18. * @param str 播放内容(字符串)
  19. */
  20. void TTS_play(unsigned char* str)
  21. {
  22.     unsigned  char  Frame_Info[50];
  23.     uint16_t str_len = 0;
  24.     str_len = strlen((char*)str);
  25.    
  26.     if (str_len == 0 || str_len > 4094) {
  27.         return;
  28.     }
  29.     Frame_Info[0] = 0xFD ;                        
  30.     Frame_Info[1] = 0x00 ;                        
  31.     Frame_Info[2] = str_len + 2;               
  32.     Frame_Info[3] = 0x01 ;                        
  33.     Frame_Info[4] = 0x00;
  34.     // // 设置帧头后的数据长度字段
  35.     Frame_Info[1] = (str_len + 2) >> 8;
  36.     Frame_Info[2] = (str_len + 2) & 0xFF;
  37.     // 发送帧头
  38.                 memcpy(&Frame_Info[5], str, str_len);
  39.                
  40.     tts_writeData(Frame_Info, 5+str_len);
  41.                
  42. }
  43. /**
  44. * @brief 设置音量
  45. * @param vol 音量值,范围0-9,默认5
  46. */
  47. void TTS_volume(uint8_t vol)
  48. {
  49.     uint8_t volume_buf[9];
  50.     uint8_t i;
  51.    
  52.     if (vol > 9)
  53.     {
  54.         vol = 9;
  55.     }
  56.    
  57.     // 复制常量数据到临时数组
  58.     for(i = 0; i < 9; i++)
  59.     {
  60.         volume_buf = TTS_VOLUME_CMD;
  61.     }
  62.    
  63.     volume_buf[7] = 0x30 + vol;
  64.     tts_writeData(volume_buf, 9);
  65. }
  66. /**
  67. * @brief 设置播放速度
  68. * @param speed 速度值,范围0-9,默认5
  69. */
  70. void TTS_speed(uint8_t speed)
  71. {
  72.     uint8_t speed_buf[9];
  73.     uint8_t i;
  74.    
  75.     if (speed > 9)
  76.     {
  77.         speed = 9;
  78.     }
  79.    
  80.     // 复制常量数据到临时数组
  81.     for(i = 0; i < 9; i++)
  82.     {
  83.         speed_buf = TTS_SPEED_CMD;
  84.     }
  85.    
  86.     speed_buf[7] = 0x30 + speed;
  87.     tts_writeData(speed_buf, 9);
  88. }
  89. /**
  90. * @brief 设置语调
  91. * @param tone 语调值,范围0-9,默认5
  92. */
  93. void TTS_tone(uint8_t tone)
  94. {
  95.     uint8_t tone_buf[9];
  96.     uint8_t i;
  97.    
  98.     if (tone > 9)
  99.     {
  100.         tone = 9;
  101.     }
  102.    
  103.     // 复制常量数据到临时数组
  104.     for(i = 0; i < 9; i++)
  105.     {
  106.         tone_buf = TTS_TONE_CMD;
  107.     }
  108.    
  109.     tone_buf[7] = 0x30 + tone;
  110.     tts_writeData(tone_buf, 9);
  111. }
  112. /**
  113. * @brief 播报警示音
  114. * @param alert 警示音标号,1-5
  115. */
  116. void TTS_alert(uint8_t alert)
  117. {
  118.     unsigned char str[8];
  119.    
  120.     if (alert < 1)
  121.     {
  122.         alert = 1;
  123.     }
  124.     else if (alert > 5)
  125.     {
  126.         alert = 5;
  127.     }
  128.    
  129.     // 直接构造字符串,避免使用字符串常量
  130.     str[0] = 'a';
  131.     str[1] = 'l';
  132.     str[2] = 'e';
  133.     str[3] = 'r';
  134.     str[4] = 't';
  135.     str[5] = '_';
  136.     str[6] = 0x30 + alert;
  137.     str[7] = '\0';
  138.    
  139.     TTS_play(str);
  140. }
  141. /**
  142. * @brief 播报信息提示音
  143. * @param msg 标号,1-5
  144. */
  145. void TTS_play_msg(uint8_t msg)
  146. {
  147.     unsigned char str[10];
  148.    
  149.     if (msg < 1)
  150.     {
  151.         msg = 1;
  152.     }
  153.     else if (msg > 5)
  154.     {
  155.         msg = 5;
  156.     }
  157.    
  158.     str[0] = 'm';
  159.     str[1] = 'e';
  160.     str[2] = 's';
  161.     str[3] = 's';
  162.     str[4] = 'a';
  163.     str[5] = 'g';
  164.     str[6] = 'e';
  165.     str[7] = '_';
  166.     str[8] = 0x30 + msg;
  167.     str[9] = '\0';
  168.    
  169.     TTS_play(str);
  170. }
  171. /**
  172. * @brief 播放铃声
  173. * @param ring 标号,1-5
  174. */
  175. void TTS_play_ring(uint8_t ring)
  176. {
  177.     unsigned char str[7];
  178.    
  179.     if (ring < 1)
  180.     {
  181.         ring = 1;
  182.     }
  183.     else if (ring > 5)
  184.     {
  185.         ring = 5;
  186.     }
  187.    
  188.     str[0] = 'r';
  189.     str[1] = 'i';
  190.     str[2] = 'n';
  191.     str[3] = 'g';
  192.     str[4] = '_';
  193.     str[5] = 0x30 + ring;
  194.     str[6] = '\0';
  195.    
  196.     TTS_play(str);
  197. }
  198. /**
  199. * @brief 停止播放
  200. */
  201. void TTS_stop(void)
  202. {
  203.     uint8_t TW_tts_buf[4];
  204.     uint8_t i;
  205.    
  206.     // 复制常量数据到临时数组
  207.     for(i = 0; i < 4; i++)
  208.     {
  209.         TW_tts_buf = TTS_STOP_CMD;
  210.     }
  211.    
  212.     tts_writeData(TW_tts_buf, 4);
  213. }
  214. /**
  215. * @brief 暂停播放
  216. */
  217. void TTS_pause(void)
  218. {
  219.     uint8_t TW_tts_buf[4];
  220.     uint8_t i;
  221.    
  222.     // 复制常量数据到临时数组
  223.     for(i = 0; i < 4; i++)
  224.     {
  225.         TW_tts_buf = TTS_PAUSE_CMD;
  226.     }
  227.    
  228.     tts_writeData(TW_tts_buf, 4);
  229. }
  230. /**
  231. * @brief 继续播放
  232. */
  233. void TTS_resume(void)
  234. {
  235.     uint8_t TW_tts_buf[4];
  236.     uint8_t i;
  237.    
  238.     // 复制常量数据到临时数组
  239.     for(i = 0; i < 4; i++)
  240.     {
  241.         TW_tts_buf = TTS_RESUME_CMD;
  242.     }
  243.    
  244.     tts_writeData(TW_tts_buf, 4);
  245. }
  246. /**
  247. * @brief 读取CITW-TTS芯片当前播放状态
  248. */
  249. uint8_t TTS_queryState(uint8_t response)
  250. {
  251.     uint8_t query_buf[5];
  252.     uint8_t i;
  253.    
  254.     // 复制常量数据到临时数组
  255.     for(i = 0; i < 5; i++)
  256.     {
  257.         query_buf = TTS_QUERY_CMD;
  258.     }
  259.    
  260.     // 发送查询命令
  261.     tts_writeData(query_buf, 5);
  262.    
  263.     // 短暂延时等待响应
  264.     HAL_Delay(10);
  265.     // 检查串口接收标志
  266.    
  267.     if (response == 0x4E)
  268.     {
  269.         return TTS_STATE_PLAYING; // 播放中
  270.     }
  271.     else if (response == 0x4F)
  272.     {
  273.         return TTS_STATE_IDLE;    // 空闲
  274.     }
  275.     else if (response == 0x4A)
  276.     {
  277.         return TTS_STATE_INIT;   // 初始化
  278.     }
  279.     else if (response == 0x41)
  280.     {
  281.         return TTS_STATE_CHECK;   // 检查
  282.     }
  283.     else
  284.     {
  285.         return TTS_STATE_ERROR;   // 查询失败(命令错误)
  286.     }
  287. }
复制代码
TW_TTS.h
  1. #ifndef __TW_TTS_H
  2. #define __TW_TTS_H
  3. #define TTS_STATE_ERROR   0   // 查询失败(命令错误)
  4. #define TTS_STATE_PLAYING 1   // 播放中(对应芯片返回0x4E)
  5. #define TTS_STATE_IDLE    2   // 空闲(对应芯片返回0x4F)
  6. #define TTS_STATE_INIT    3   // 初始化(对应芯片返回0x4A)
  7. #define TTS_STATE_CHECK   4   // 检查(对应芯片返回0x41)
  8. void tts_writeData(unsigned char *DAT, unsigned char len);
  9. void TTS_play(unsigned char* str);
  10. void TTS_volume(uint8_t vol);
  11. void TTS_speed(uint8_t speed);
  12. void TTS_tone(uint8_t tone);
  13. void TTS_alert(uint8_t alert);
  14. void TTS_play_msg(uint8_t msg);
  15. void TTS_play_ring(uint8_t ring);
  16. void TTS_stop(void);
  17. void TTS_pause(void);
  18. void TTS_resume(void);
  19. uint8_t TTS_queryState(uint8_t response);
  20. #endif
  21. uart.c
  22. /**
  23.   ******************************************************************************
  24.   * @file    usart.c
  25.   * @brief   This file provides code for the configuration
  26.   *          of the USART instances.
  27.   ******************************************************************************
  28.   * @attention
  29.   *
  30.   * <h2><center>© Copyright (c) 2025 STMicroelectronics.
  31.   * All rights reserved.</center></h2>
  32.   *
  33.   * This software component is licensed by ST under BSD 3-Clause license,
  34.   * the "License"; You may not use this file except in compliance with the
  35.   * License. You may obtain a copy of the License at:
  36.   *                        opensource.org/licenses/BSD-3-Clause
  37.   *
  38.   ******************************************************************************
  39.   */
  40. /* Includes ------------------------------------------------------------------*/
  41. #include "usart.h"
  42. /* USER CODE BEGIN 0 */
  43. /* USER CODE END 0 */
  44. UART_HandleTypeDef huart1;
  45. UART_HandleTypeDef huart2;
  46. /* USART1 init function */
  47. void MX_USART1_UART_Init(void)
  48. {
  49.   huart1.Instance = USART1;
  50.   huart1.Init.BaudRate = 9600;
  51.   huart1.Init.WordLength = UART_WORDLENGTH_8B;
  52.   huart1.Init.StopBits = UART_STOPBITS_1;
  53.   huart1.Init.Parity = UART_PARITY_NONE;
  54.   huart1.Init.Mode = UART_MODE_TX_RX;
  55.   huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  56.   huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  57.   if (HAL_UART_Init(&huart1) != HAL_OK)
  58.   {
  59.     Error_Handler();
  60.   }
  61. }
  62. /* USART2 init function */
  63. void MX_USART2_UART_Init(void)
  64. {
  65.   huart2.Instance = USART2;
  66.   huart2.Init.BaudRate = 9600;
  67.   huart2.Init.WordLength = UART_WORDLENGTH_8B;
  68.   huart2.Init.StopBits = UART_STOPBITS_1;
  69.   huart2.Init.Parity = UART_PARITY_NONE;
  70.   huart2.Init.Mode = UART_MODE_TX_RX;
  71.   huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  72.   huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  73.   if (HAL_UART_Init(&huart2) != HAL_OK)
  74.   {
  75.     Error_Handler();
  76.   }
  77. }
  78. void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
  79. {
  80.   GPIO_InitTypeDef GPIO_InitStruct = {0};
  81.   if(uartHandle->Instance==USART1)
  82.   {
  83.   /* USER CODE BEGIN USART1_MspInit 0 */
  84.   /* USER CODE END USART1_MspInit 0 */
  85.     /* USART1 clock enable */
  86.     __HAL_RCC_USART1_CLK_ENABLE();
  87.     __HAL_RCC_GPIOA_CLK_ENABLE();
  88.     /**USART1 GPIO Configuration
  89.     PA9     ------> USART1_TX
  90.     PA10     ------> USART1_RX
  91.     */
  92.     GPIO_InitStruct.Pin = GPIO_PIN_9;
  93.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  94.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  95.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  96.     GPIO_InitStruct.Pin = GPIO_PIN_10;
  97.     GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  98.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  99.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  100.     /* USART1 interrupt Init */
  101.     HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
  102.     HAL_NVIC_EnableIRQ(USART1_IRQn);
  103.   /* USER CODE BEGIN USART1_MspInit 1 */
  104.   /* USER CODE END USART1_MspInit 1 */
  105.   }
  106.   else if(uartHandle->Instance==USART2)
  107.   {
  108.   /* USER CODE BEGIN USART2_MspInit 0 */
  109.   /* USER CODE END USART2_MspInit 0 */
  110.     /* USART2 clock enable */
  111.     __HAL_RCC_USART2_CLK_ENABLE();
  112.     __HAL_RCC_GPIOA_CLK_ENABLE();
  113.     /**USART2 GPIO Configuration
  114.     PA2     ------> USART2_TX
  115.     PA3     ------> USART2_RX
  116.     */
  117.     GPIO_InitStruct.Pin = GPIO_PIN_2;
  118.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  119.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  120.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  121.     GPIO_InitStruct.Pin = GPIO_PIN_3;
  122.     GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  123.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  124.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  125.     /* USART2 interrupt Init */
  126.     HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
  127.     HAL_NVIC_EnableIRQ(USART2_IRQn);
  128.   /* USER CODE BEGIN USART2_MspInit 1 */
  129.   /* USER CODE END USART2_MspInit 1 */
  130.   }
  131. }
  132. void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
  133. {
  134.   if(uartHandle->Instance==USART1)
  135.   {
  136.   /* USER CODE BEGIN USART1_MspDeInit 0 */
  137.   /* USER CODE END USART1_MspDeInit 0 */
  138.     /* Peripheral clock disable */
  139.     __HAL_RCC_USART1_CLK_DISABLE();
  140.     /**USART1 GPIO Configuration
  141.     PA9     ------> USART1_TX
  142.     PA10     ------> USART1_RX
  143.     */
  144.     HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
  145.     /* USART1 interrupt Deinit */
  146.     HAL_NVIC_DisableIRQ(USART1_IRQn);
  147.   /* USER CODE BEGIN USART1_MspDeInit 1 */
  148.   /* USER CODE END USART1_MspDeInit 1 */
  149.   }
  150.   else if(uartHandle->Instance==USART2)
  151.   {
  152.   /* USER CODE BEGIN USART2_MspDeInit 0 */
  153.   /* USER CODE END USART2_MspDeInit 0 */
  154.     /* Peripheral clock disable */
  155.     __HAL_RCC_USART2_CLK_DISABLE();
  156.     /**USART2 GPIO Configuration
  157.     PA2     ------> USART2_TX
  158.     PA3     ------> USART2_RX
  159.     */
  160.     HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);
  161.     /* USART2 interrupt Deinit */
  162.     HAL_NVIC_DisableIRQ(USART2_IRQn);
  163.   /* USER CODE BEGIN USART2_MspDeInit 1 */
  164.   /* USER CODE END USART2_MspDeInit 1 */
  165.   }
  166. }
  167. /* USER CODE BEGIN 1 */
  168. /* USER CODE END 1 */
  169. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码
main.c
  1. /* USER CODE BEGIN Header */
  2. /**
  3.   ******************************************************************************
  4.   * @file           : main.c
  5.   * @brief          : Main program body
  6.   ******************************************************************************
  7.   * @attention
  8.   *
  9.   * <h2><center>© Copyright (c) 2025 STMicroelectronics.
  10.   * All rights reserved.</center></h2>
  11.   *
  12.   * This software component is licensed by ST under BSD 3-Clause license,
  13.   * the "License"; You may not use this file except in compliance with the
  14.   * License. You may obtain a copy of the License at:
  15.   *                        opensource.org/licenses/BSD-3-Clause
  16.   *
  17.   ******************************************************************************
  18.   */
  19. /* USER CODE END Header */
  20. /* Includes ------------------------------------------------------------------*/
  21. #include "main.h"
  22. #include "usart.h"
  23. #include "gpio.h"
  24. #include "TW_TTS.h"
  25. /* Private includes ----------------------------------------------------------*/
  26. /* USER CODE BEGIN Includes */
  27. uint8_t rec1Byte;
  28. uint8_t rec2Byte;
  29. /* USER CODE END Includes */
  30. /* Private typedef -----------------------------------------------------------*/
  31. /* USER CODE BEGIN PTD */
  32. /* USER CODE END PTD */
  33. /* Private define ------------------------------------------------------------*/
  34. /* USER CODE BEGIN PD */
  35. /* USER CODE END PD */
  36. /* Private macro -------------------------------------------------------------*/
  37. /* USER CODE BEGIN PM */
  38. /* USER CODE END PM */
  39. /* Private variables ---------------------------------------------------------*/
  40. /* USER CODE BEGIN PV */
  41. /* USER CODE END PV */
  42. /* Private function prototypes -----------------------------------------------*/
  43. void SystemClock_Config(void);
  44. /* USER CODE BEGIN PFP */
  45. /* USER CODE END PFP */
  46. /* Private user code ---------------------------------------------------------*/
  47. /* USER CODE BEGIN 0 */
  48. /* USER CODE END 0 */
  49. /**
  50.   * @brief  The application entry point.
  51.   * @retval int
  52.   */
  53. int main(void)
  54. {
  55.   /* USER CODE BEGIN 1 */
  56.   /* USER CODE END 1 */
  57.   /* MCU Configuration--------------------------------------------------------*/
  58.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  59.   HAL_Init();
  60.   /* USER CODE BEGIN Init */
  61.   /* USER CODE END Init */
  62.   /* Configure the system clock */
  63.   SystemClock_Config();
  64.   /* USER CODE BEGIN SysInit */
  65.   /* USER CODE END SysInit */
  66.   /* Initialize all configured peripherals */
  67.   MX_GPIO_Init();
  68.   MX_USART1_UART_Init();
  69.   MX_USART2_UART_Init();
  70.   /* USER CODE BEGIN 2 */
  71.         HAL_UART_Receive_IT(&huart1, &rec1Byte, sizeof(rec1Byte));//打开串口接收中断
  72.         HAL_UART_Receive_IT(&huart2, &rec2Byte, sizeof(rec2Byte));//打开串口接收中断
  73.   /* USER CODE END 2 */
  74.   /* Infinite loop */
  75.   /* USER CODE BEGIN WHILE */
  76.         TTS_volume(1);
  77.   while (1)
  78.   {
  79.                
  80.     /* USER CODE END WHILE */
  81.     /* USER CODE BEGIN 3 */
  82.                 if(TTS_queryState(rec1Byte)==TTS_STATE_INIT)
  83.                 {
  84.                         HAL_Delay(100);
  85.                         TTS_play("初始化完成");
  86.                         HAL_Delay(2000);
  87.                 }
  88.                 TTS_play("好好搭搭");
  89. HAL_Delay(2000);
  90.   }
  91.   /* USER CODE END 3 */
  92. }
  93. /**
  94.   * @brief System Clock Configuration
  95.   * @retval None
  96.   */
  97. void SystemClock_Config(void)
  98. {
  99.   RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  100.   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  101.   /** Initializes the RCC Oscillators according to the specified parameters
  102.   * in the RCC_OscInitTypeDef structure.
  103.   */
  104.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  105.   RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  106.   RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  107.   RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  108.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  109.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  110.   RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  111.   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  112.   {
  113.     Error_Handler();
  114.   }
  115.   /** Initializes the CPU, AHB and APB buses clocks
  116.   */
  117.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  118.                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  119.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  120.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  121.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  122.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  123.   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  124.   {
  125.     Error_Handler();
  126.   }
  127. }
  128. /* USER CODE BEGIN 4 */
  129. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  130. {
  131.                 if (huart == &huart1)
  132.                 {
  133.        HAL_UART_Transmit(&huart2, &rec1Byte, 1, 100);
  134.                 }
  135.                
  136.                 HAL_UART_Receive_IT(&huart1, &rec1Byte, 1);
  137.                
  138.                 if (huart == &huart2)
  139.                 {
  140.        HAL_UART_Transmit(&huart2, &rec2Byte, 1, 100);
  141.                 }
  142.                 HAL_UART_Receive_IT(&huart2, &rec2Byte, 1);
  143. }
  144. /* USER CODE END 4 */
  145. /**
  146.   * @brief  This function is executed in case of error occurrence.
  147.   * @retval None
  148.   */
  149. void Error_Handler(void)
  150. {
  151.   /* USER CODE BEGIN Error_Handler_Debug */
  152.   /* User can add his own implementation to report the HAL error return state */
  153.   __disable_irq();
  154.   while (1)
  155.   {
  156.   }
  157.   /* USER CODE END Error_Handler_Debug */
  158. }
  159. #ifdef  USE_FULL_ASSERT
  160. /**
  161.   * @brief  Reports the name of the source file and the source line number
  162.   *         where the assert_param error has occurred.
  163.   * @param  file: pointer to the source file name
  164.   * @param  line: assert_param error line source number
  165.   * @retval None
  166.   */
  167. void assert_failed(uint8_t *file, uint32_t line)
  168. {
  169.   /* USER CODE BEGIN 6 */
  170.   /* User can add his own implementation to report the file name and line number,
  171.      ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  172.   /* USER CODE END 6 */
  173. }
  174. #endif /* USE_FULL_ASSERT */
  175. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码
程序效果:

语音合成模块上电播放:“初始化完成”,之后每两秒播放一次“好好搭搭”

串口1用于控制语音合成模块,串口2查看语音合成播放的信息。


Arduino
电路连接:
image.png

Arduino端程序
范例:Arduino控制语音合成播放
  1. #include "Arduino.h"
  2. #include "Wire.h"
  3. #include "Servo.h"
  4. #include "SoftwareSerial.h"
  5. #include "TW_TTS.h"
  6. TW_TTS syn;
  7. void setup()
  8. {
  9.   syn.begin();
  10. }
  11. void loop()
  12. {
  13.   if(syn.tts_queryState()==TTS_STATE_INIT){
  14.     syn.tts_play("初始化完成");
  15.     delay(2000);
  16.   }
  17.   syn.tts_play("你好");
  18.   delay(2000);
  19. }
复制代码
程序效果:
语音合成模块上电播放:“初始化完成”,之后每两秒播放一次“你好”

esp32
电路连接:
image.png

esp32c3的引脚0(TX)连接语音合成模块的R引脚,esp32c3的引脚1(RX)连接语音合成模块的T引脚
范例: esp32实时天气时钟播报(好搭 Block 案例)
image.png

image.png

image.png

image.png

范例: esp32实时天气时钟播报(字符代码编程案例)
TW_TTS.py
  1. from machine import UART
  2. from machine import Pin
  3. TTS_STATE_ERROR = 0   
  4. TTS_STATE_PLAYING = 1   
  5. TTS_STATE_IDLE = 2   
  6. TTS_STATE_INIT = 3   
  7. TTS_STATE_CHECK = 4   
  8. '''
  9. 协议格式
  10. 帧头    数据长度     命令字    编码参数     文本
  11. 0xfd    0x00 0xLL   0x01      0x00        text(n字节)
  12. '''
  13. class TW_TTS:
  14.     #全局变量,保存编码格式
  15.     #0x00:GB2312编码,目前只支持GB2312
  16.     global code_type
  17.     code_type = 0x0
  18.     def __init__(self,tx_pin,rx_pin):
  19.         self.uart = UART(1, baudrate=9600, tx=tx_pin, rx=rx_pin, timeout=10)
  20.     #向芯片发送数据
  21.     def write(self,dat):
  22.         if type(dat) == type('a'):
  23.             self.uart.write(dat)
  24.         else:
  25.             self.uart.write(bytes(dat))
  26.     #设置文字编码
  27.     def set_code(self,code):
  28.         global code_type
  29.         code_type = code
  30.    
  31.     #播放语音
  32.     def play(self, str):
  33.         global code_type
  34.         asr_tts_buf = [0xfd,0x00,0x00,0x01,code_type]
  35.         #最大支持4K字节文本
  36.         asr_tts_buf[1] = (len(str) + 2)//256        
  37.         asr_tts_buf[2] = (len(str) + 2)%256            
  38.         asr_tts_buf.extend(str)
  39.         # print(asr_tts_buf)
  40.         self.uart.write(bytes(asr_tts_buf))
  41.     #设置音量,vol:音量:0-9,默认5,音量0为静音
  42.     def volume(self,vol):
  43.         volume_buf = [0xfd,0x00,0x06,0x01,0x01,0x5b,0x76,0x30,0x5d]
  44.         volume_buf[7] = (0x30 + vol)
  45.         self.uart.write(bytes(volume_buf))
  46.    
  47.     #设置语音播报速度 0-9,默认5
  48.     def speed(self,spd):
  49.         speed_buf = [0xfd,0x00,0x06,0x01,0x01,0x5b,0x73,0x30,0x5d]
  50.         speed_buf[7] = (0x30 + spd)
  51.         self.uart.write(bytes(speed_buf))      
  52.    
  53.     #设置语音播报语调 0-9,默认5
  54.     def tone(self,tone):
  55.         speed_buf = [0xfd,0x00,0x06,0x01,0x01,0x5b,0x74,0x30,0x5d]
  56.         speed_buf[7] = (0x30 + tone)
  57.         self.uart.write(bytes(speed_buf))   
  58.     #播报警示音,index:1-5
  59.     def play_alert(self,index):
  60.         if index > 5:
  61.             index = 5
  62.         str = "alert_" + chr(0x30+index)
  63.         self.set_code(0)
  64.         self.play(bytes(str,'utf_8'))
  65.         self.set_code(code_type)
  66.     #播报信息提示音,index:1-5
  67.     def play_msg(self,index):
  68.         if index > 5:
  69.             index = 5
  70.         str = "message_" + chr(0x30+index)
  71.         self.play(bytes(str,'utf_8'))
  72.     #播报铃声,index:1-5
  73.     def play_ring(self,index):
  74.         if index > 5:
  75.             index = 5
  76.         str = "ring_" + chr(0x30+index)
  77.         self.set_code(0)
  78.         self.play(bytes(str,'utf_8'))
  79.         self.set_code(code_type)
  80.     #停止播报
  81.     def stop(self):
  82.         buf = [0xfd,0x00,0x01,0x02]
  83.         self.uart.write(bytes(buf))  
  84.     #暂停播报
  85.     def pause(self):
  86.         buf = [0xfd,0x00,0x01,0x03]
  87.         self.uart.write(bytes(buf))         
  88.     #继续播报
  89.     def resume(self):
  90.         buf = [0xfd,0x00,0x01,0x04]
  91.         self.uart.write(bytes(buf))  
  92.     def queryState(self):
  93.         buf = [0xFD, 0x00, 0x02, 0x21, 0x00]
  94.         self.uart.write(bytes(buf))
  95.         response = self.uart.read()  # 返回bytes或None
  96.         
  97.         # 修正:先判断响应是否存在,再提取字节比较
  98.         if response and len(response) > 0:
  99.             resp_byte = response[0]  # 提取响应的第一个字节
  100.             if resp_byte == 0x4E:
  101.                 return TTS_STATE_PLAYING
  102.             elif resp_byte == 0x4F:
  103.                 return TTS_STATE_IDLE
  104.             elif resp_byte == 0x4A:
  105.                 return TTS_STATE_INIT
  106.             elif resp_byte == 0x41:
  107.                 return TTS_STATE_CHECK
  108.         # 无有效响应返回错误状态
  109.         return TTS_STATE_ERROR
复制代码
main.py
  1. from machine import Pin
  2. from machine import UART
  3. from TW_TTS import TW_TTS, TTS_STATE_ERROR, TTS_STATE_PLAYING, TTS_STATE_IDLE, TTS_STATE_INIT, TTS_STATE_CHECK
  4. from board import *
  5. import network
  6. import time
  7. from machine import RTC
  8. import ntptime
  9. import urequests
  10. import json
  11. import ujson
  12. my_wifi = wifi()
  13. rtc = RTC()
  14. def 时间校准():
  15.     global tts_text, 今日风向, 今天夜晚天气现象, 今天白天天气现象, 最高气温, 最低气温, 日, 月, 年, 秒, 分, 时, 今日风速, 星期, daily_list, 后天最高气温, 后天最低气温, 明天最高气温, 明天最低气温, 后台天气现象, 明天天气现象, 今日湿度, results_list, location_list, text_dict, _response
  16.     ntptime.settime(8,"ntp3.aliyun.com")
  17.     年 = rtc.datetime()[0]
  18.     月 = rtc.datetime()[1]
  19.     日 = rtc.datetime()[2]
  20.     星期 = rtc.datetime()[3]
  21.     时 = rtc.datetime()[4]
  22.     分 = rtc.datetime()[5]
  23.     秒 = rtc.datetime()[6]
  24. def 天气判断():
  25.     global tts_text, 今日风向, 今天夜晚天气现象, 今天白天天气现象, 最高气温, 最低气温, 日, 月, 年, 秒, 分, 时, 今日风速, 星期, daily_list, 后天最高气温, 后天最低气温, 明天最高气温, 明天最低气温, 后台天气现象, 明天天气现象, 今日湿度, results_list, location_list, text_dict, _response
  26.     print('获取温度,不同天气显示不同图案', end='')
  27.     _response = urequests.get('http://www.haohaodada.com/project/weather/',headers={},timeout=10)
  28.     text_dict = ujson.loads((_response.text))
  29.     results_list = text_dict.get('results')
  30.     location_list = results_list[0].get('location')
  31.     daily_list = results_list[0].get('daily')
  32.     最高气温 = str(daily_list[0].get('high'))
  33.     最低气温 = str(daily_list[0].get('low'))
  34.     今天白天天气现象 = str(daily_list[0].get('text_day'))
  35.     今天夜晚天气现象 = str(daily_list[0].get('text_night'))
  36.     今日风速 = str(daily_list[0].get('wind_scale'))
  37.     今日风向 = str(daily_list[0].get('wind_direction'))
  38.     今日湿度 = str(daily_list[0].get('humidity'))
  39.     明天天气现象 = str(daily_list[1].get('text_day'))
  40.     后台天气现象 = str(daily_list[2].get('text_day'))
  41.     明天最低气温 = str(daily_list[1].get('low'))
  42.     明天最高气温 = str(daily_list[1].get('high'))
  43.     后天最低气温 = str(daily_list[2].get('low'))
  44.     后天最高气温 = str(daily_list[2].get('high'))
  45. syn=TW_TTS(0,1)
  46. IO09 = BoardPin(9, PinMode.IN, pull=None)
  47. my_wifi.connectWiFi('haoda7', '0123456789')
  48. while not my_wifi.sta.isconnected():
  49.     time.sleep_ms(1)
  50. 时间校准()
  51. 天气判断()
  52. while True:
  53.     时 = rtc.datetime()[4]
  54.     分 = rtc.datetime()[5]
  55.     秒 = rtc.datetime()[6]
  56.     oled.fill(0)
  57.     oled.DispChar(str((''.join([str(x) for x in [年, '年', 月, '/', 日]]))), 0, 0, 1)
  58.     oled.DispChar(str((''.join([str(x2) for x2 in [时, ':', 分, ':', 秒]]))), 0, 16, 1)
  59.     oled.DispChar(str((''.join([str(x3) for x3 in [最低气温, '℃ - ', 最高气温, '℃', '   ', 今天白天天气现象]]))), 0, 32, 1)
  60.     oled.DispChar(str((''.join([str(x4) for x4 in [今日风向, '风   ', 今日风速, 'm/s']]))), 0, 48, 1)
  61.     oled.show()
  62.     if 时 == 0 and 分 == 0 and 秒 == 1:
  63.         print('每日凌晨校准时间', end='')
  64.         syn.set_code(0x04)
  65.         syn.play(bytes('每日凌晨校准时间', 'utf-8'))
  66.         时间校准()
  67.     if 分 % 5 == 0 and 秒 == 0:
  68.         print('每五分钟刷新一次天气', end='')
  69.         syn.set_code(0x04)
  70.         syn.play(bytes('每五分钟刷新一次天气', 'utf-8'))
  71.         天气判断()
  72.     if IO09.read_digital() == 0:
  73.         time.sleep_ms(10)
  74.         if IO09.read_digital() == 0:
  75.             while IO09.read_digital() == 0:
  76.                 pass
  77.             tts_text = ''.join([str(x5) for x5 in ['今天是', 年, '年', 月, '月', 日, '日,', '最低气温', 最低气温, '摄氏度,', '最高气温', 最高气温, '摄氏度,', '今天白天', 今天白天天气现象, ',晚间', 今天夜晚天气现象, ',', 今日风向, '风']])
  78.             syn.set_code(0x04)
  79.             syn.play(bytes(tts_text, 'utf-8'))
复制代码
程序效果:
esp32WiFi连接,实时从网络获取天气数据,通过按键触发播放当前天气数据。
image.png

ASRPRO
电路连接:
image.png

ASRPRO的PA2(TX)引脚接TW_TTS的(R)引脚,ASRPRO的PA3(RX)引脚接TW_TTS的(T)引脚。

范例:ASRPRO控制语音合成播放指定文字
image.png

image.png

程序效果:
通过语音指令触发指定散文文本的 TTS 朗读,支持暂停 / 继续 / 停止等播放控制  。

STC8
电路连接:
image.png

本案例以P5_0为RX,P5_1为TX举例。P5_0与TW_TTS的T连接,P5_1与TW_TTS的R连接注意STC8的电源插脚接到5V,GND引脚互相连接。

范例: STC8串口控制播放语音
image.png

程序效果:
          语音合成模块上电播放:“初始化完成”,之后每两秒播放一次“好好搭搭”

米思齐esp32
电路连接:
image.png

范例: esp32串口控制播放语音
image.png

程序效果:
语音合成模块上电播放:“初始化完成”,语音合成空闲状态播放铃声1,之后每两秒播放一次“好好搭搭”

MIND+ arduino UNO
电路连接:

范例: arduino串口控制播放语音
image.png

程序效果:
上电初始化完成播放:“初始化完成”,模块结束播放状态则播放一段铃声,随后循环播放:“欢迎使用语音合成模块”

TW32F003
电路连接:
image.png

TW32的PA0(TX)引脚接TW_TTS的(R)引脚,TW32的PA1(RX)引脚接TW_TTS的(T)引脚。

范例:TW32F003控制语音合成播放指定文字
image.png

程序效果:
         上电初始化以后,语音合成会发出:“初始化完成”的语音提醒。语音合成当前状态会通过串口打印出来:
image.png

附录
TW_TTS.zip (14.14 MB, 下载次数: 108)
回复

使用道具 举报

0

主题

8

帖子

90

积分

注册会员

Rank: 2

积分
90
发表于 2026-1-17 14:14:11 | 显示全部楼层
不错  一如既往的支持天问!
回复

使用道具 举报

0

主题

2

帖子

28

积分

注册会员

Rank: 2

积分
28
发表于 2026-1-18 20:14:38 | 显示全部楼层
esp32的引脚1(TX0)连接TW_TTS的R引脚,可以正常工作。
esp32的引脚17(TX2)连接TW_TTS的R引脚,积木块选择Serial2,不工作。(即使选择Serial2,实际还是把数据从Serial0发出了)
请问积木块能否自定义 TX RX 引脚呢?
回复

使用道具 举报

1

主题

2

帖子

40

积分

注册会员

Rank: 2

积分
40
发表于 2026-1-19 09:34:19 | 显示全部楼层
本帖最后由 19959302505 于 2026-1-19 09:42 编辑
makergeng 发表于 2026-1-18 20:14
esp32的引脚1(TX0)连接TW_TTS的R引脚,可以正常工作。
esp32的引脚17(TX2)连接TW_TTS的R引脚,积木块选 ...

我们的天问block平台图形话编程暂只支持esp32c3开发板,是可以自定义TX,RX引脚的
回复

使用道具 举报

0

主题

2

帖子

28

积分

注册会员

Rank: 2

积分
28
发表于 2026-1-19 11:56:05 | 显示全部楼层
希望增加Air001开发板的支持
回复

使用道具 举报

4

主题

21

帖子

122

积分

注册会员

Rank: 2

积分
122
发表于 2026-1-21 15:53:13 | 显示全部楼层
我用STC 8怎样读变量的数字
回复

使用道具 举报

0

主题

1

帖子

10

积分

注册会员

Rank: 2

积分
10
发表于 2026-3-4 20:54:55 | 显示全部楼层
请问TTS支持arduinoide吗?支持ESP32-S3吗?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|好好搭搭在线 ( © 好好搭搭在线 浙ICP备19030393号 )

GMT+8, 2026-3-12 12:25 , Processed in 0.122610 second(s), 26 queries .

Powered by Discuz!

© 2001-2026 Comsenz Inc.

快速回复 返回顶部 返回列表