ESP 8266+ TTS 实现对讲机语音播报 时间 和信息

#include <SoftwareSerial.h>

#include <ESP8266WiFi.h>

#include <NTPClient.h>

#include <WiFiUdp.h>

#include "UTF8ToGB2312.h"

//需要改造对讲机耳机连接至 TTS 音响接口

#define SERIAL2_TX 12 //接TTS RX

#define SERIAL2_RX 13 //接TTS TX

#define TTS_MAX_DATA_LENGTH 1024 // 最大支持4K字节

#define CONTROL_PIN 14 // 定义控制引脚为14 接对讲机 PPT

// WiFi设置

const char* ssid = "你的wifi名称";

const char* password = "你的wifi密码";

// NTP时间服务器设置

WiFiUDP ntpUDP;

NTPClient timeClient(ntpUDP, "pool.ntp.org", 28800, 60000); // 北京时间:UTC+8 (28800秒)

EspSoftwareSerial::UART Serial2;

//UTF8ToGB2312 GB; // 实例化UTF8转GB2312转换器

// 枚举类型表示TTS工作状态

enum class TTSState {

IDLE = 0,

BUSY = 1,

ERROR = 2

};

int lastMinute = -1; // 记录上一次检查的分钟数

// 定义播放时间范围(7:00-21:00)

const int START_HOUR = 7;

const int END_HOUR = 21;

// 检查当前时间是否在允许的播放范围内

bool isWithinPlayTime() {

int currentHour = timeClient.getHours();

return (currentHour >= START_HOUR && currentHour <= END_HOUR);

}

void setup() {

digitalWrite(CONTROL_PIN, LOW);

Serial2.begin(115200, SWSERIAL_8N1, SERIAL2_RX, SERIAL2_TX, false);

if (!Serial2) {

Serial.println("Invalid EspSoftwareSerial pin configuration, check config");

while (1) delay(1000); // 保持错误状态

}

Serial.begin(115200);

// 连接WiFi

Serial.println("Connecting to WiFi");

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {

delay(500);

Serial.print(".");

}

Serial.println("\nWiFi connected");

// 初始化NTP客户端

timeClient.begin();

timeClient.update();

delay(3000); // 减少CPU占用

speech("系统初始化成功,当前时间同步完成");

}

void loop() {

// 更新时间

timeClient.update();

// 获取当前时间的分钟数

int currentMinute = timeClient.getMinutes();

int currentHour = timeClient.getHours();

String fenzhong = "";

// // 构建报时消息

// 检查是否为整点或半点,并且与上次检查的分钟数不同

// 检查是否在允许的播放时间段内

if (isWithinPlayTime()) {

if ((currentMinute == 0 || currentMinute == 30) && currentMinute != lastMinute) {

lastMinute = currentMinute;

// 配置控制引脚

pinMode(CONTROL_PIN, OUTPUT);

digitalWrite(CONTROL_PIN, HIGH); // 将引脚14设置为高电平

Serial.println("Control pin 14 set to HIGH");

if(currentMinute == 0){

fenzhong = "整";

}else{

fenzhong = String(currentMinute)+"分";

}

// 添加固定播报内容

String broadcastMessage = "[s6][m0][ring_3]现在时刻[w0][n2]"+String(currentHour)+"点"+fenzhong+"[w0]这里是亳州市业余无线电中继台[w0][n1]439.750下差-5亚音[n1]88.5[w0]世界药都[w0]中国亳州[w0]欢迎您";

// 播报整点/半点消息

speech(broadcastMessage);

// 播报完成后将控制引脚设为低电平

digitalWrite(CONTROL_PIN, LOW);

Serial.println("Control pin 14 set to LOW after speech");

}

}

else{

Serial.print("当前时间 ");

Serial.print(currentHour);

Serial.print(":");

Serial.print(currentMinute);

Serial.println(" 不在播放范围内,跳过语音播报");

}

// 其他任务处理...

delay(3000); // 减少CPU占用

}

// 发送命令到TTS模块

bool sendTTSCommand(const uint8_t* command, uint16_t length) {

if (!command || length == 0 || length > TTS_MAX_DATA_LENGTH) {

Serial.println("Error: Invalid command data");

return false;

}

for (uint16_t i = 0; i < length; i++) {

Serial2.write(command[i]);

}

return true;

}

// 查询TTS合成工作状态

TTSState getTTSState() {

const uint8_t cmd[] = {0xFD, 0x00, 0x01, 0x21};

sendTTSCommand(cmd, sizeof(cmd));

// 等待响应,增加超时机制

unsigned long startTime = millis();

while (Serial2.available() < 1 && (millis() - startTime) < 1000) {

delay(10); // 减少延时,提高响应速度

}

if (Serial2.available() >= 1) {

byte response = Serial2.read();

if (response == 0x4E) return TTSState::BUSY;

if (response == 0x4F) return TTSState::IDLE;

}

return TTSState::ERROR;

}

// 语音合成函数

bool speech(const String& text) {

// 等待TTS空闲

TTSState state;

while ((state = getTTSState()) != TTSState::IDLE) {

Serial.print("TTS status: ");

Serial.println(static_cast<int>(state));

delay(1000); // 避免过于频繁的查询

}

// 转换UTF8到GB2312

String gb2312Text = GB.get(text);

if (gb2312Text.isEmpty()) {

Serial.println("Error: Text conversion failed");

return false;

}

// 计算消息长度

uint16_t textLength = gb2312Text.length();

if (textLength == 0 || textLength > (TTS_MAX_DATA_LENGTH - 6)) {

Serial.println("Error: Text length is invalid");

return false;

}

// 构建完整命令

uint8_t command[TTS_MAX_DATA_LENGTH];

command[0] = 0xFD; // 帧头

// 数据长度(命令+参数+数据)

uint16_t dataLength = textLength + 2;

command[1] = (dataLength >> 8) & 0xFF;

command[2] = dataLength & 0xFF;

command[3] = 0x01; // 命令字节:文本合成

command[4] = 0x01; // 参数:合成模式

// 复制文本数据

memcpy(&command[5], gb2312Text.c_str(), textLength);

// 计算校验和

uint8_t checksum = command[0];

for (uint16_t i = 1; i < textLength + 5; i++) {

checksum ^= command[i];

}

command[textLength + 5] = checksum;

// 发送命令

bool result = sendTTSCommand(command, textLength + 6);

delay(13600); // 等待合成开始,根据实际情况调整

return result;

}

相关推荐
qq_53756267几秒前
跨语言调用C++接口
开发语言·c++·算法
wjs202411 分钟前
DOM CDATA
开发语言
Tingjct12 分钟前
【初阶数据结构-二叉树】
c语言·开发语言·数据结构·算法
猷咪39 分钟前
C++基础
开发语言·c++
IT·小灰灰40 分钟前
30行PHP,利用硅基流动API,网页客服瞬间上线
开发语言·人工智能·aigc·php
快点好好学习吧42 分钟前
phpize 依赖 php-config 获取 PHP 信息的庖丁解牛
android·开发语言·php
秦老师Q42 分钟前
php入门教程(超详细,一篇就够了!!!)
开发语言·mysql·php·db
烟锁池塘柳043 分钟前
解决Google Scholar “We‘re sorry... but your computer or network may be sending automated queries.”的问题
开发语言
是誰萆微了承諾43 分钟前
php 对接deepseek
android·开发语言·php
2601_949868361 小时前
Flutter for OpenHarmony 电子合同签署App实战 - 已签合同实现
java·开发语言·flutter