为什么选择 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 电源吧。
希望这篇博客文章对您有所帮助!
相关资源: