diff --git a/CHANGELOG.md b/CHANGELOG.md index f453f8b..31a018f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,14 @@ ### Added +#### GPS 支持(esp32c3_moonshine_travelers) +- 启用 GPS 子系统:`HAS_GPS 1`,UART 引脚 `GPS_RX_PIN 20` / `GPS_TX_PIN 21` +- GPS RST(TCA9535 P1.6)和 GPS EN(TCA9535 P1.7)通过 I²C GPIO 扩展器控制 + - 通电时 P1.6、P1.7 默认拉高(GPS 上电 + 释放复位) + - `tca9535GpsReset(bool high)` / `tca9535GpsEn(bool on)` — read-modify-write P1.6/P1.7 + - `main.cpp` 中通过 `GpioUnaryTransformer` 桥接 `gps->enablePin` → `tca9535GpsEn()` +- 配套 GPS 模块:安信可 GP-02(3.3V,NMEA 9600 bps) + #### CN 频段支持 - 新增中国 CN 频段定义:470.0–510.0 MHz,100 信道,`SETTING_MAX_POWER` 宏保护默认 3 dBm - 修改文件:`src/mesh/RadioInterface.cpp`(`RDEF(CN, ...)`) @@ -32,7 +40,7 @@ - 未按满 2 秒松开 → 不拉高 POWER_EN → MOS 断开 → 自动断电 - 关机流程:运行中 P1.3 持续按住 2 秒 → 清空屏幕 → POWER_EN 拉低 → 用户松手后 MOS 断开断电 - 电源状态机:`BOOT_PENDING` → `RUNNING` → `SHUTDOWN_PENDING` -- P1 口配置:`0xEB`(P1.2=输出, P1.3=输入, P1.4=输出) +- P1 口配置:`0x8B`(P1.2=输出, P1.3=输入, P1.4=输出, P1.5=输出, P1.6=输出, P1.7=输出) #### LoRa RST 通过 TCA9535 P1.4 控制 - 新增 `TCA9535GpioHal` 自定义 HAL 子类(在 `src/main.cpp`) @@ -91,4 +99,4 @@ | esp32c3_moonshine | ESP32-C3 | E220-400M30S | 无 | 无 | BUTTON_PIN=9 | — | | esp32c3_moonshine (fw) | ESP32-C3 | E220-400M30S / E22_400M33S | 无 | 无 | BUTTON_PIN=9 | USB CDC, 电池 ADC | | esp32c3_moonshine_mv | ESP32-C3 | RA-01SC-P | SSD1306 | 有 | PCF8574 6 键 | NeoPixel, GPS EN | -| esp32c3_moonshine_travelers | ESP32-C3 | RA-01SC-P | SH1106 | 无 | TCA9535 4×4 矩阵 | 电源管理, LoRa RST via I²C | +| esp32c3_moonshine_travelers | ESP32-C3 | RA-01SC-P | SH1106 | **有** | TCA9535 4×4 矩阵 | 电源管理, LoRa RST via I²C, GPS RST/EN via I²C | diff --git a/code/firmware-2.7.15.567b8ea/src/input/TCA9535ButtonThread.cpp b/code/firmware-2.7.15.567b8ea/src/input/TCA9535ButtonThread.cpp index 5c7a864..3309f1a 100644 --- a/code/firmware-2.7.15.567b8ea/src/input/TCA9535ButtonThread.cpp +++ b/code/firmware-2.7.15.567b8ea/src/input/TCA9535ButtonThread.cpp @@ -58,11 +58,12 @@ bool TCA9535ButtonThread::init() { // =================================================================== // 第一步:配置 P1 口方向 - // P1.2 = 输出(POWER_EN),P1.3 = 输入(POWER_BOOT),P1.4 = 输出(LoRa RST),P1.5 = 输出(状态灯) + // P1.2=输出(POWER_EN), P1.3=输入(POWER_BOOT), P1.4=输出(LoRa RST), + // P1.5=输出(状态灯), P1.6=输出(GPS RST), P1.7=输出(GPS EN) // Configuration 寄存器:1=input, 0=output - // P1.2=bit2=0, P1.3=bit3=1, P1.4=bit4=0, P1.5=bit5=0 → 0xCB (1100 1011) + // P1.2=0, P1.3=1, P1.4=0, P1.5=0, P1.6=0, P1.7=0 → 0x8B (1000 1011) // =================================================================== - if (!writeReg(TCA9535_REG_CONFIG_P1, 0xCB)) { + if (!writeReg(TCA9535_REG_CONFIG_P1, 0x8B)) { LOG_WARN("TCA9535: P1 config write failed"); return false; } @@ -74,6 +75,12 @@ bool TCA9535ButtonThread::init() // P1.5 状态灯默认熄灭(高电平) tca9535StatusLed(false); + // P1.6 GPS RST 默认释放(高电平 = 正常工作) + tca9535GpsReset(true); + + // P1.7 GPS EN 默认打开(高电平 = GPS 上电) + tca9535GpsEn(true); + // =================================================================== // 第二步:开机检测 — 等待用户持续按住 P1.3 达 2 秒 // 物理按键已使 MOS 导通(ESP32 得电),但 POWER_EN 尚未拉高 diff --git a/code/firmware-2.7.15.567b8ea/src/input/TCA9535ButtonThread.h b/code/firmware-2.7.15.567b8ea/src/input/TCA9535ButtonThread.h index 192f192..4bed1b0 100644 --- a/code/firmware-2.7.15.567b8ea/src/input/TCA9535ButtonThread.h +++ b/code/firmware-2.7.15.567b8ea/src/input/TCA9535ButtonThread.h @@ -85,6 +85,8 @@ #define TCA9535_BIT_P13 (1u << 3) // POWER_BOOT 输入 #define TCA9535_BIT_P14 (1u << 4) // LoRa RST 输出 #define TCA9535_BIT_P15 (1u << 5) // 状态指示灯输出(低电平点亮) +#define TCA9535_BIT_P16 (1u << 6) // GPS RST 输出 +#define TCA9535_BIT_P17 (1u << 7) // GPS EN 输出(高电平有效) /** * 通过 I²C 控制 TCA9535 P1.2 上的电源使能(POWER_EN)。 @@ -189,6 +191,57 @@ static inline bool tca9535StatusLed(bool on) return (Wire.endTransmission() == 0); } +/** + * 通过 I²C 控制 TCA9535 P1.6 上的 GPS RST。 + * @param high true=释放复位(高电平),false=触发复位(低电平) + */ +static inline bool tca9535GpsReset(bool high) +{ + Wire.beginTransmission(TCA9535_I2C_ADDR); + Wire.write(TCA9535_REG_OUTPUT_P1); + if (Wire.endTransmission(false) != 0) + return false; + if (Wire.requestFrom((uint8_t)TCA9535_I2C_ADDR, (uint8_t)1) != 1) + return false; + uint8_t p1Out = Wire.read(); + + if (high) + p1Out |= TCA9535_BIT_P16; // 拉高 = 释放复位 + else + p1Out &= ~TCA9535_BIT_P16; // 拉低 = 触发复位 + + Wire.beginTransmission(TCA9535_I2C_ADDR); + Wire.write(TCA9535_REG_OUTPUT_P1); + Wire.write(p1Out); + return (Wire.endTransmission() == 0); +} + +/** + * 通过 I²C 控制 TCA9535 P1.7 上的 GPS EN。 + * 高电平有效:拉高 = GPS 上电,拉低 = GPS 断电。 + * @param on true=上电(高电平),false=断电(低电平) + */ +static inline bool tca9535GpsEn(bool on) +{ + Wire.beginTransmission(TCA9535_I2C_ADDR); + Wire.write(TCA9535_REG_OUTPUT_P1); + if (Wire.endTransmission(false) != 0) + return false; + if (Wire.requestFrom((uint8_t)TCA9535_I2C_ADDR, (uint8_t)1) != 1) + return false; + uint8_t p1Out = Wire.read(); + + if (on) + p1Out |= TCA9535_BIT_P17; // 拉高 = GPS 上电 + else + p1Out &= ~TCA9535_BIT_P17; // 拉低 = GPS 断电 + + Wire.beginTransmission(TCA9535_I2C_ADDR); + Wire.write(TCA9535_REG_OUTPUT_P1); + Wire.write(p1Out); + return (Wire.endTransmission() == 0); +} + /** * 电源管理状态机 */ diff --git a/code/firmware-2.7.15.567b8ea/src/main.cpp b/code/firmware-2.7.15.567b8ea/src/main.cpp index ecbcc6d..d011b26 100644 --- a/code/firmware-2.7.15.567b8ea/src/main.cpp +++ b/code/firmware-2.7.15.567b8ea/src/main.cpp @@ -955,6 +955,16 @@ void setup() gps = GPS::createGps(); if (gps) { gpsStatus->observe(&gps->newStatus); +#ifdef TCA9535_GPS_HAS_CTRL + // 替换 enablePin 为 TCA9535 P1.7(GPS EN),I²C 控制 + // createGps() 创建了空的 GpioVirtPin,替换为实际的 TCA9535 驱动 + class GpioTca9535GpsEnPin : public GpioPin { + public: + void set(bool value) override { tca9535GpsEn(value); } + } *tca9535GpsEnPin = new GpioTca9535GpsEnPin(); + new GpioUnaryTransformer(gps->enablePin, tca9535GpsEnPin); + // GPS 已在 TCA9535 init 中上电(P1.7=高),无需额外操作 +#endif } else { LOG_DEBUG("Run without GPS"); } diff --git a/code/firmware-2.7.15.567b8ea/variants/esp32c3/diy/esp32c3_moonshine_travelers/variant.h b/code/firmware-2.7.15.567b8ea/variants/esp32c3/diy/esp32c3_moonshine_travelers/variant.h index dbed402..81d3046 100644 --- a/code/firmware-2.7.15.567b8ea/variants/esp32c3/diy/esp32c3_moonshine_travelers/variant.h +++ b/code/firmware-2.7.15.567b8ea/variants/esp32c3/diy/esp32c3_moonshine_travelers/variant.h @@ -16,9 +16,9 @@ #define I2C_SDA 0 #define I2C_SCL 1 -#define HAS_GPS 0 -#define GPS_RX_PIN 21 -#define GPS_TX_PIN 20 +#define HAS_GPS 1 +#define GPS_RX_PIN 20 +#define GPS_TX_PIN 21 #define BATTERY_PIN 2 @@ -35,6 +35,8 @@ // 开机:持续按住 2 秒 → POWER_EN 拉高维持供电 // 关机:运行中持续按住 2 秒 → POWER_EN 拉低断电 // - P1.4 LoRa RST 输出(通过 I²C 控制 RadioLib 复位序列) +// - P1.6 GPS_RST 输出(通过 tca9535GpsReset() 控制,init 中释放) +// - P1.7 GPS_EN 输出(高电平有效,通过 enablePin 桥接到 TCA9535) // - 中断引脚 GPIO5,低电平有效,下降沿触发 // ----------------------------------------------------------------------- #define HAS_TCA9535_BUTTON @@ -85,6 +87,11 @@ #define TCA9535_LORA_RST_REG TCA9535_REG_OUTPUT_P1 // P1 输出寄存器 #define TCA9535_LORA_RST_BIT (1u << 4) // P1.4 +// GPS RST (P1.6) 和 GPS EN (P1.7) 通过 TCA9535 I²C 控制 +// 不定义 PIN_GPS_RESET/PIN_GPS_EN 为虚拟引脚(避免 GpioHwPin 访问无效 GPIO) +// 改为在 main.cpp 中 createGps() 后替换 enablePin 为 TCA9535 GpioPin +#define TCA9535_GPS_HAS_CTRL 1 + #define LORA_SCK 10 #define LORA_MISO 6 #define LORA_MOSI 7