【逗老师的无线电】BI1FQO手搓笔记:STM32直驱4G模组,打造极致精简MMDVM热点
1. 从云DTU到硬核改造的进化之路
第一次接触MMDVM热点时,我用的是现成的4G DTU模块。这种"傻瓜式"方案确实省心——插上SIM卡,配置虚拟串口,五分钟就能让热点板联网。但用久了就发现痛点:DTU模块体积堪比火柴盒,额外供电线缆像蜘蛛网,整体功耗接近3W。最要命的是每次断电后,TCP连接配置都会丢失,必须重新用电脑发送AT指令。
后来尝试移远EC200模组直接对接热点板,尺寸缩小到邮票大小,功耗直降到1W以下。但AT指令配置流程依然繁琐:
- 开机后手动发送
AT+QICSGP=1,1,"UNINET"设置APN - 用
AT+QIACT=1激活网络 - 最后
AT+QIOPEN建立TCP连接
某次野外通联时,我突然意识到:既然热点板主控是STM32F103,为什么不让它自己搞定这些操作?于是开始了这场"去掉中间商"的硬核改造。
2. STM32直驱4G模组的硬件魔术
2.1 引脚改造手术
大多数MMDVM热点板的UART1默认连接树莓派GPIO,我们需要将其改接到4G模组。以常见的HS_Hat热点板为例:
| 热点板引脚 | STM32F103引脚 | 4G模组引脚 |
|---|---|---|
| GPIO14(TXD) | PA9 | UART_RX |
| GPIO15(RXD) | PA10 | UART_TX |
| GND | GND | GND |
实际操作时,建议用热风枪吹下排针,直接飞线连接。我曾因偷懒使用杜邦线,结果车辆颠簸导致接触不良,闹出"幽灵断网"的笑话。
2.2 电源优化方案
4G模组的瞬时电流可能超过500mA,推荐两种供电方案:
- 方案A:改造热点板3.3V LDO,更换为SY8089等2A级DCDC
- 方案B:从USB 5V直接取电,增加LC滤波电路(实测可降低射频干扰)
我的EC800模组在方案B下,通话时电压波动仅0.05V,比原厂设计更稳定。
3. 开发环境搭建的避坑指南
3.1 非典型Arduino配置
虽然使用Arduino IDE开发,但需要特殊配置:
- 安装
STM32duino核心包 - 选择开发板类型:
Generic STM32F1 series - 具体参数设置:
Board: STM32F103C8 Upload method: Serial CPU Speed: 72MHz Optimize: Smallest (default)
特别注意:必须勾选Upload Reset: Hardware Reset,否则刷机成功率不到50%。这个坑让我浪费了三小时查线路,最后发现是软件配置问题。
3.2 串口下载的玄学
热点板没有USB转串口芯片,需要外接USB-TTL工具。关键步骤:
- 将BOOT0引脚(热点板GPIO20)拉高
- 按复位键进入烧录模式
- 快速点击Arduino的上传按钮
如果总是超时,试试调整tools/Upload Speed为115200。我在Linux下实测57600更稳定,可能与驱动有关。
4. 固件魔改实战
4.1 MMDVM_HS代码解剖
juribeparada的原始固件中,关键流程在SerialPort.cpp:
void CSerialPort::process() { // 原有串口数据处理 if (m_buffer[0] == 0xE0) handleHostFrame(); }我们在IO.cpp的初始化阶段插入4G配置代码:
void CIO::startup() { // 新增4G初始化 g4G.init(); // 原有初始化 beginADF7021(); ... }4.2 AT指令状态机实现
最核心的G4Module类实现:
class G4Module { public: void init() { m_state = STATE_INIT; m_lastCmdTime = millis(); } void process() { switch(m_state) { case STATE_INIT: if (sendAT("AT")) { m_state = STATE_CHECK_SIM; } break; case STATE_CHECK_SIM: if (sendAT("AT+CPIN?")) { if (strstr(m_buffer, "READY")) { m_state = STATE_SET_APN; } } break; // 更多状态处理... } } private: bool sendAT(const char* cmd) { Serial.print(cmd); Serial.print("\r\n"); m_lastCmdTime = millis(); return true; } enum States { STATE_INIT, STATE_CHECK_SIM, STATE_SET_APN, STATE_ACTIVATE, STATE_CONNECT, STATE_RUNNING }; char m_buffer[256]; States m_state; uint32_t m_lastCmdTime; };实测发现移远模组启动需要3秒,因此每个状态需设置超时重试机制。我的方案是每秒重发指令,最多尝试5次。
5. 终极优化技巧
5.1 功耗控制黑科技
通过修改ADF7021.cpp的射频控制逻辑,在无通信时关闭射频前端:
void CADF7021::setIdle() { writeRegister(0x0C, 0x01); // 低功耗模式 digitalWrite(m_pttPin, LOW); }配合4G模组的AT+QSCLK=1指令,整体待机功耗从1.2W降至0.3W。
5.2 看门狗增强稳定性
在main.cpp中添加硬件看门狗:
void setup() { IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); IWDG_SetPrescaler(IWDG_Prescaler_256); IWDG_SetReload(0xFFF); IWDG_ReloadCounter(); IWDG_Enable(); } void loop() { IWDG_ReloadCounter(); // 主循环代码 }这个改进让我的热点在-20℃低温下连续运行30天无重启。记得在AT指令等待循环中也加入喂狗操作,否则网络差时会意外复位。
6. 成品实测数据
最终版性能指标:
- 尺寸:48mm×32mm(不含天线)
- 重量:18g
- 工作电流:
- 待机:80mA @3.7V
- 通话峰值:300mA @3.7V
- 建联时间:冷启动平均4.2秒
- 通信延迟:DMR帧往返平均126ms
在北京市区实测,连续8小时DMR通话零掉线。最远在怀柔山顶与天津HAM通联,信号报告5/9。
