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;

}

相关推荐
xuanzdhc20 分钟前
C++重点知识详解(命名空间,缺省参数,函数重载)
开发语言·c++
软件开发技术深度爱好者28 分钟前
python中学物理实验模拟:凸透镜成像和凹透镜成像
开发语言·python
小猫咪怎么会有坏心思呢43 分钟前
华为OD机试-云短信平台优惠活动-完全背包(JAVA 2024E卷)
java·开发语言·华为od
鱼鱼说测试1 小时前
jmeter工具简单认识
开发语言·python
Hello.Reader1 小时前
Lua 事务双写、RedisGears 异步双写、零停机索引迁移与容量预估
开发语言·lua
虾球xz1 小时前
CppCon 2017 学习:Howling at the Moon: Lua for C++ Programmers
开发语言·c++·学习·lua
monicaaaaan2 小时前
旋转图像C++
开发语言·c++
无影无踪的青蛙2 小时前
[C++] STL数据结构小结
开发语言·数据结构·c++
景彡先生2 小时前
C++中的指针与引用
开发语言·c++
灵性花火2 小时前
Qt + C++ 入门2(界面的知识点)
开发语言·c++·qt