#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;
}