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

发布于:2025-06-27 ⋅ 阅读:(16) ⋅ 点赞:(0)

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

}


网站公告

今日签到

点亮在社区的每一天
去签到