4G Cat.1 模块实战:EC200U 联网教程,远程数据采集不再愁

4G Cat.1 模块实战:EC200U 联网教程,远程数据采集不再愁

为什么选择 Cat.1?

做物联网项目的兄弟们都遇到过这个问题:设备部署在野外,WiFi 够不着,LoRa 距离不够,2G 又在退网,怎么办?

4G Cat.1 就是为这个场景而生的。

简单说,Cat.1 是 4G 的"精简版":

  • 下行速率 10Mbps – 传传感器数据绰绰有余
  • 功耗低 – 待机电流仅 3mA
  • 覆盖广 – 直接用现有 4G 基站
  • 成本低 – 模块只要 25-35 元
  • 延迟低 – 比 NB-IoT 响应快得多

今天我们就用移远 EC200U 模块,做一个远程温度采集器,数据直接发到 MQTT 服务器。

需要准备什么?

物品 型号/规格 价格
4G Cat.1 模块 移远 EC200U ¥28
天线 4G 棒状天线(SMA 接口) ¥8
SIM 卡 物联网卡/手机卡(需开通数据) ¥10/月
开发板 Arduino Uno 或 ESP32 ¥15
USB 转 TTL CH340 或 CP2102 ¥5
杜邦线 公对母若干 ¥3
温度传感器 DHT22(可选) ¥8
总计 ¥77

模块购买关键词:"EC200U 开发板"或"EC200U Arduino",建议买带底板的那种,接线方便。

第一步:硬件连接

EC200U 使用 UART 通信,接线非常简单:

EC200U          Arduino/ESP32
─────────────────────────────
VCC      →      5V (Arduino) 或 3.3V (ESP32)
GND      →      GND
TX       →      RX (Pin 10)
RX       →      TX (Pin 11)
NET      →      LED(网络状态指示,可选)

注意事项: ⚠️

  • EC200U 发射瞬间电流可达 500mA,USB 供电可能不够,建议外接 5V/2A 电源
  • TX/RX 要交叉连接(模块 TX 接开发板 RX)
  • 天线必须接好再上电,否则可能损坏射频电路

第二步:AT 命令测试

先别写代码,用串口工具测试模块是否正常。

打开 Arduino IDE 的串口监视器,或直接用 PuTTY/屏幕:

# 波特率设置为 115200
# 发送以下命令(每行后加换行)

AT
# 应返回:OK

AT+CSQ
# 返回信号质量:+CSQ: 20,99(20 表示信号良好)

AT+COPS?
# 返回运营商:+COPS: 0,0,"CHINA MOBILE"

AT+CGATT?
# 返回附着状态:+CGATT: 1(已附着)

AT+QIACT?
# 返回 IP 状态:+QIACT: 1(已激活)

如果 AT+CSQ 返回小于 10,说明信号太差,换个位置或加高增益天线。

第三步:Arduino 驱动代码

下面是一个完整的 EC200U 驱动库,支持 TCP/MQTT 连接:

#include 

#define EC200U_RX 10
#define EC200U_TX 11

SoftwareSerial ec200u(EC200U_RX, EC200U_TX);

class EC200U {
public:
  EC200U() {}

  bool init() {
    ec200u.begin(115200);
    delay(1000);

    // 测试通信
    sendAT("AT");
    if (!waitForOK()) return false;

    // 关闭回显
    sendAT("ATE0");
    waitForOK();

    // 设置文本模式
    sendAT("AT+CMGF=1");
    waitForOK();

    Serial.println("EC200U 初始化成功");
    return true;
  }

  bool waitForNetwork(int timeout = 60) {
    Serial.print("等待网络注册");
    for (int i = 0; i < timeout; i++) {
      sendAT("AT+CREG?");
      String resp = readResponse();
      if (resp.indexOf("+CREG: 0,1") >= 0 || resp.indexOf("+CREG: 0,5") >= 0) {
        Serial.println("\n网络注册成功");
        return true;
      }
      Serial.print(".");
      delay(1000);
    }
    Serial.println("\n网络注册超时");
    return false;
  }

  bool activateGPRS(const char* apn = "cmnet") {
    // 设置 APN
    sendAT("AT+QICSGP=1,1,\"" + String(apn) + "\",\"\",\"\"");
    if (!waitForOK()) return false;

    // 激活上下文
    sendAT("AT+QIACT=1");
    for (int i = 0; i < 30; i++) {
      delay(1000);
      sendAT("AT+QIACT?");
      String resp = readResponse();
      if (resp.indexOf("+QIACT: 1,1") >= 0) {
        Serial.println("GPRS 激活成功");
        return true;
      }
    }
    Serial.println("GPRS 激活失败");
    return false;
  }

  bool connectMQTT(const char* server, int port, 
                   const char* clientID, const char* user, 
                   const char* pass) {
    // 配置 MQTT
    String cmd = "AT+QMTCFG=\"keepalive\",0,60";
    sendAT(cmd);
    waitForOK();

    cmd = "AT+QMTCFG=\"will\",0,0,0,\"\",\"\",0,0";
    sendAT(cmd);
    waitForOK();

    cmd = "AT+QMTCFG=\"auth\",0," + String(user) + "," + String(pass);
    sendAT(cmd);
    waitForOK();

    // 连接服务器
    cmd = "AT+QMTOPEN=0,\"" + String(server) + "\"," + String(port);
    sendAT(cmd);

    // 等待连接确认
    for (int i = 0; i < 10; i++) {
      delay(500);
      if (ec200u.available()) {
        String resp = ec200u.readStringUntil('\n');
        if (resp.indexOf("+QMTOPEN: 0,0") >= 0) {
          Serial.println("MQTT 服务器连接成功");
          break;
        }
      }
    }

    // 登录
    cmd = "AT+QMTCONN=0,\"" + String(clientID) + "\"";
    sendAT(cmd);

    for (int i = 0; i < 10; i++) {
      delay(500);
      if (ec200u.available()) {
        String resp = ec200u.readStringUntil('\n');
        if (resp.indexOf("+QMTCONN: 0,0,0") >= 0) {
          Serial.println("MQTT 登录成功");
          return true;
        }
      }
    }
    Serial.println("MQTT 登录失败");
    return false;
  }

  bool publish(const char* topic, const char* message) {
    String cmd = "AT+QMTPUB=0,0,0,0,\"" + String(topic) + "\"," + String(strlen(message));
    sendAT(cmd);
    delay(100);

    // 发送消息内容
    ec200u.print(message);

    for (int i = 0; i < 5; i++) {
      delay(200);
      if (ec200u.available()) {
        String resp = ec200u.readStringUntil('\n');
        if (resp.indexOf("+QMTPUB: 0,0,0") >= 0) {
          return true;
        }
      }
    }
    return false;
  }

private:
  void sendAT(String cmd) {
    ec200u.println(cmd);
    delay(100);
  }

  String readResponse() {
    String resp = "";
    while (ec200u.available()) {
      resp += ec200u.readStringUntil('\n');
    }
    return resp;
  }

  bool waitForOK(int timeout = 50) {
    for (int i = 0; i < timeout; i++) {
      if (ec200u.available()) {
        String line = ec200u.readStringUntil('\n');
        if (line.indexOf("OK") >= 0) return true;
        if (line.indexOf("ERROR") >= 0) return false;
      }
      delay(100);
    }
    return false;
  }
};

EC200U gsm;

void setup() {
  Serial.begin(115200);
  while (!Serial);

  Serial.println("=== 4G Cat.1 MQTT 采集器 ===");

  if (!gsm.init()) {
    Serial.println("模块初始化失败,检查接线");
    while (1);
  }

  if (!gsm.waitForNetwork()) {
    Serial.println("网络注册失败,检查 SIM 卡和天线");
    while (1);
  }

  if (!gsm.activateGPRS("cmnet")) {
    Serial.println("GPRS 激活失败,检查 APN 设置");
    while (1);
  }

  // 连接 MQTT(替换成你的服务器)
  if (!gsm.connectMQTT("broker.emqx.io", 1883, 
                       "arduino_client_001", "", "")) {
    Serial.println("MQTT 连接失败");
    while (1);
  }

  Serial.println("系统就绪,开始发送数据");
}

void loop() {
  // 模拟温度数据
  float temperature = 25.0 + random(100) / 10.0;
  float humidity = 60.0 + random(200) / 10.0;

  // 生成 JSON
  String payload = "{\"temp\":" + String(temperature) + 
                   ",\"hum\":" + String(humidity) + 
                   ",\"ts\":" + String(millis()) + "}";

  // 发布到 MQTT
  if (gsm.publish("/sensor/arduino001", payload.c_str())) {
    Serial.println("数据发送成功:" + payload);
  } else {
    Serial.println("数据发送失败");
  }

  // 每 30 秒发送一次
  delay(30000);
}

原理解析:

  • EC200U 使用移远专有的 AT 命令集(以 AT+QMT 开头)
  • MQTT 连接分两步:先 TCP 连接服务器,再发送 MQTT CONNECT 包
  • 数据以 JSON 格式发送,方便云端解析

第四步:测试验证

上传代码后,打开串口监视器,你应该看到:

=== 4G Cat.1 MQTT 采集器 ===
EC200U 初始化成功
等待网络注册.....
网络注册成功
GPRS 激活成功
MQTT 服务器连接成功
MQTT 登录成功
系统就绪,开始发送数据
数据发送成功:{"temp":28.5,"hum":65.2,"ts":123456}

用 MQTT 客户端(如 MQTTX)订阅 /sensor/arduino001 主题,就能实时收到数据。

流量消耗实测

我连续跑了 24 小时测试:

发送间隔 单次数据量 日发送次数 日流量 月流量
30 秒 50 字节 2880 144KB 4.3MB
1 分钟 50 字节 1440 72KB 2.2MB
5 分钟 50 字节 288 14KB 432KB

结论: 对于传感器数据采集,一个月 10MB 套餐完全够用。物联网卡一般 10 元/月/100MB,成本很低。

常见问题排查

问题 1: AT 命令无响应

  • 原因: 波特率不对或接线错误
  • 解决: 确认波特率 115200,TX/RX 交叉连接,检查供电

问题 2: +CME ERROR: 3(SIM 卡未插入)

  • 原因: SIM 卡没插好或方向反了
  • 解决: 重新插拔 SIM 卡,缺口方向朝外,用橡皮擦清洁触点

问题 3: 信号质量差(CSQ < 10)

  • 原因: 天线没接好或位置不佳
  • 解决: 拧紧天线,把设备放到窗边,或换高增益天线

问题 4: GPRS 激活失败

  • 原因: APN 设置错误或欠费
  • 解决: 确认 APN(移动 cmnet/联通 3gnet/电信 ctnet),检查话费余额

问题 5: MQTT 连接超时

  • 原因: 服务器地址错误或防火墙阻挡
  • 解决:AT+QPING="broker.emqx.io" 测试连通性,确认端口 1883 开放

进阶技巧

1. 低功耗模式

如果设备用电池供电,可以启用休眠:

// 进入休眠
sendAT("AT+QSCLK=1");

// 唤醒(拉高 DTR 引脚)
digitalWrite(DTR_PIN, HIGH);
delay(100);
digitalWrite(DTR_PIN, LOW);

休眠电流可降至 1mA 以下。

2. 短信告警

设备异常时发短信通知:

sendAT("AT+CMGS=\"13800138000\"");
delay(100);
ec200u.print("温度超限!当前 85°C");
delay(100);
ec200u.write(0x1A);  // Ctrl+Z 发送

3. TCP 透传

如果不想用 MQTT,可以直接 TCP 透传:

// 打开 TCP 连接
sendAT("AT+QIOPEN=1,0,\"TCP\",\"192.168.1.100\",8080,0,1");

// 发送数据
sendAT("AT+QISEND=0,10");
ec200u.print("0123456789");

总结

4G Cat.1 是物联网项目的"万金油"方案:

  • 比 WiFi 覆盖广
  • 比 LoRa 延迟低
  • 比 NB-IoT 响应快
  • 比 4G Cat.4 便宜

EC200U 这块模块,30 块钱就能让你的设备 anywhere online。配合 MQTT 协议,数据采集、远程控制都不在话下。

唯一需要注意的是供电——发射瞬间 500mA 的电流,USB 可能扛不住,老老实实接个 5V/2A 电源吧。

希望这篇博客文章对您有所帮助!


相关资源: