STM32+GPRS物联网通信:Air208S模块实战(4/10)
本文介绍了基于STM32和Air208S GPRS模块的物联网通信方案。重点分析了GPRS模块选型(相比WiFi/4G/NB-IoT的优势)、Air208S特点(内置协议栈简化开发)、硬件连接要点(电源设计、引脚配置)以及AT指令使用流程(从模块检测到TCP数据传输)。文章通过对比表格和流程图,展示了GPRS在低频小数据场景下的适用性,并详细说明了Air208S模块的快速开发优势,为物联网设备联网
·
STM32+GPRS物联网通信:Air208S模块实战(4/10)
作者:宋一平
分类:嵌入式 / 物联网 / 通信技术
预计阅读:15分钟
一、GPRS模块选型
1.1 为什么选GPRS?
在物联网项目中,设备联网有多种选择:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| WiFi | 速度快、成本低 | 需要路由器、功耗高 | 室内有WiFi环境 |
| 4G/Cat1 | 速度快、覆盖广 | 成本高、功耗大 | 需要高速传输 |
| GPRS | 覆盖广、成本低、功耗低 | 速度慢、2G退网风险 | 低频小数据传输 ✅ |
| NB-IoT | 功耗极低、覆盖深 | 模组贵、移动性差 | 静态设备 |
| LoRa | 远距离、自组网 | 需要网关、无运营商 | 私有网络 |
本项目选择GPRS的理由:
- 数据量小(加注记录上报,几十字节)
- 频率低(每次加注后上报一次)
- 成本敏感(设备要批量部署)
- 覆盖要求(设备可能在地下室)
1.2 常见GPRS模块对比
| 模块 | 厂商 | 特点 | 价格 |
|---|---|---|---|
| SIM800C | SIMCom | 资料多、生态成熟 | ¥15-20 |
| SIM900A | SIMCom | 老款、性价比高 | ¥12-15 |
| Air208S | 中移物联 | 自带协议栈、开发简单 | ¥20-25 |
| Air202 | 中移物联 | Air208S简化版 | ¥15-18 |
| EC20 | 移远 | 4G模块,兼容2G | ¥50-60 |
1.3 为什么选Air208S?
Air208S的核心优势:
┌─────────────────────────────────────────────────────┐
│ Air208S 模块 │
│ │
│ ✅ 内置TCP/IP协议栈,无需自己实现 │
│ ✅ 支持MQTT/HTTP等应用协议 │
│ ✅ AT指令简单,开发效率高 │
│ ✅ 低功耗模式,适合电池供电 │
│ ✅ 全国2G覆盖,移动/联通双网 │
│ │
└─────────────────────────────────────────────────────┘
与传统GPRS模块对比:
传统方案(SIM800C):
MCU → AT指令 → GPRS模块 → 自己实现TCP/IP → 服务器
Air208S方案:
MCU → AT指令 → Air208S → 内置TCP/IP → 服务器
↑
简化开发难度
二、硬件连接
2.1 Air208S引脚说明
| 引脚 | 功能 | 说明 |
|---|---|---|
| VCC | 电源 | 3.4V-4.2V,峰值电流2A |
| GND | 地 | 与MCU共地 |
| TXD | 发送 | 接MCU的RX |
| RXD | 接收 | 接MCU的TX |
| PWR_KEY | 开机 | 拉低1秒开机 |
| RESET | 复位 | 拉低复位 |
| SIM_DET | SIM卡检测 | 插卡检测 |
2.2 接线图
┌─────────────────────────────────────────────────────┐
│ │
│ STM32F103 │
│ ┌──────────┐ ┌──────────────┐ │
│ │ │ │ │ │
│ │ PA2 │◄────────│ TXD │ │
│ │ (RXD) │ │ │ │
│ │ │ │ Air208S │ │
│ │ PA3 │────────►│ RXD │ │
│ │ (TXD) │ │ │ │
│ │ │ │ │ │
│ │ PB0 │────────►│ PWR_KEY │ │
│ │ (GPIO) │ │ │ │
│ │ │ │ │ │
│ │ 3.3V │ │ VCC │◄── 4.0V │
│ │ GND │◄───────►│ GND │◄── GND │
│ │ │ │ │ │
│ └──────────┘ │ SIM卡槽 │ │
│ │ │ │
│ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────┘
2.3 电源设计要点
GPRS模块发射时电流可达2A,电源设计至关重要:
┌─────────────────────────────────────────────────────┐
│ 电源方案 │
│ │
│ 12V输入 → 降压芯片 → 4.0V输出 → Air208S │
│ (如MP1584) │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 12V │ │ MP1584 │ │ 4.0V │ │
│ │ 输入 │────► │ 降压 │────► │ 输出 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │
│ 大电容(470μF) │
│ │ │
│ GND │
│ │
└─────────────────────────────────────────────────────┘
关键设计:
- 输出电容:≥470μF,应对发射脉冲电流
- 走线宽度:电源线≥2mm,减小压降
- 滤波电容:靠近模块VCC引脚放置
三、AT指令入门
3.1 常用AT指令表
| 指令 | 功能 | 响应 |
|---|---|---|
| AT | 测试通信 | OK |
| ATI | 查询模块信息 | 模块型号 |
| AT+CPIN? | 查询SIM卡状态 | +CPIN: READY |
| AT+CSQ | 查询信号强度 | +CSQ: 20,0 |
| AT+CIPSTART | 建立TCP连接 | OK / ERROR |
| AT+CIPSEND | 发送数据 | > (等待输入) |
| AT+CIPCLOSE | 关闭连接 | OK |
3.2 连接流程
Step 1: 测试通信
─────────────────
发送: AT
响应: OK
Step 2: 检查SIM卡
─────────────────
发送: AT+CPIN?
响应: +CPIN: READY
Step 3: 检查信号强度
─────────────────
发送: AT+CSQ
响应: +CSQ: 20,0
↑
信号强度(0-31,建议>10)
Step 4: 建立TCP连接
─────────────────
发送: AT+CIPSTART="TCP","server.com",8080
响应: OK
CONNECT OK
Step 5: 发送数据
─────────────────
发送: AT+CIPSEND=10
响应: >
发送: 1234567890 (10字节数据)
响应: SEND OK
Step 6: 接收数据
─────────────────
服务器下发时自动收到:
+RECEIVE,10:
1234567890
Step 7: 关闭连接
─────────────────
发送: AT+CIPCLOSE
响应: CLOSE OK
3.3 心跳机制
保持连接需要定时发送心跳包:
┌─────────────────────────────────────────────────────┐
│ 心跳流程 │
│ │
│ MCU 服务器 │
│ │ │ │
│ │──── 心跳包(每60秒) ─────────►│ │
│ │◄─── 心跳响应 ───────────────│ │
│ │ │ │
│ │ 超时未响应? │ │
│ │ │ │ │
│ │ 重连3次 │ │
│ │ │ │ │
│ │ 仍失败? │ │
│ │ │ │ │
│ │ 重启模块 │ │
│ │ │ │
└─────────────────────────────────────────────────────┘
四、代码实现
4.1 模块初始化
/**
* @brief GPRS模块初始化
* @return 0:成功, <0:失败
*/
s8 GPRS_Init(void)
{
u8 retry = 0;
u8 rx_buf[100];
int rx_len = 0;
// 初始化串口(UART2)
UART_INIT(U_2, BOUND_9600, PRI_NONE);
// 开机控制
GPRS_PWR_KEY = 0;
vTaskDelay(1000); // 拉低1秒
GPRS_PWR_KEY = 1;
vTaskDelay(3000); // 等待模块启动
// 测试通信
for (retry = 0; retry < 5; retry++)
{
UARTSend(U_2, "AT\r\n", 4);
vTaskDelay(500);
if (UARTRead(U_2, rx_buf, &rx_len))
{
if (strstr((char *)rx_buf, "OK") != NULL)
{
break; // 通信成功
}
}
}
if (retry >= 5) return -1; // 通信失败
// 检查SIM卡
UARTSend(U_2, "AT+CPIN?\r\n", 10);
vTaskDelay(500);
if (UARTRead(U_2, rx_buf, &rx_len))
{
if (strstr((char *)rx_buf, "READY") == NULL)
{
return -2; // SIM卡错误
}
}
// 检查信号强度
UARTSend(U_2, "AT+CSQ\r\n", 8);
vTaskDelay(500);
if (UARTRead(U_2, rx_buf, &rx_len))
{
// 解析信号强度
// +CSQ: 20,0
u8 csq = ParseCSQ(rx_buf);
if (csq < 10) return -3; // 信号太弱
}
return 0; // 初始化成功
}
4.2 TCP连接
/**
* @brief 建立TCP连接
* @param server 服务器地址
* @param port 端口号
* @return 0:成功, <0:失败
*/
s8 GPRS_Connect(char *server, u16 port)
{
u8 cmd[100];
u8 rx_buf[100];
int rx_len = 0;
// 构造AT指令
sprintf((char *)cmd, "AT+CIPSTART=\"TCP\",\"%s\",%d\r\n", server, port);
// 发送连接命令
UARTSend(U_2, cmd, strlen((char *)cmd));
// 等待响应(最多10秒)
for (u8 i = 0; i < 20; i++)
{
vTaskDelay(500);
if (UARTRead(U_2, rx_buf, &rx_len))
{
if (strstr((char *)rx_buf, "CONNECT OK") != NULL)
{
return 0; // 连接成功
}
if (strstr((char *)rx_buf, "ERROR") != NULL)
{
return -1; // 连接失败
}
}
}
return -2; // 超时
}
4.3 发送数据
/**
* @brief 发送数据
* @param data 数据缓冲区
* @param len 数据长度
* @return 0:成功, <0:失败
*/
s8 GPRS_Send(u8 *data, u16 len)
{
u8 cmd[32];
u8 rx_buf[100];
int rx_len = 0;
// 发送数据长度
sprintf((char *)cmd, "AT+CIPSEND=%d\r\n", len);
UARTSend(U_2, cmd, strlen((char *)cmd));
// 等待 ">" 提示符
vTaskDelay(100);
if (UARTRead(U_2, rx_buf, &rx_len))
{
if (strstr((char *)rx_buf, ">") == NULL)
{
return -1; // 未收到提示符
}
}
// 发送数据
UARTSend(U_2, data, len);
// 等待发送完成
vTaskDelay(500);
if (UARTRead(U_2, rx_buf, &rx_len))
{
if (strstr((char *)rx_buf, "SEND OK") != NULL)
{
return 0; // 发送成功
}
}
return -2; // 发送失败
}
4.4 接收数据
/**
* @brief 接收数据(非阻塞)
* @param buf 接收缓冲区
* @param max_len 最大长度
* @return 接收到的数据长度,0表示无数据
*/
u16 GPRS_Receive(u8 *buf, u16 max_len)
{
u8 rx_buf[200];
int rx_len = 0;
if (UARTRead(U_2, rx_buf, &rx_len))
{
// 解析接收格式: +RECEIVE,10:1234567890
if (strstr((char *)rx_buf, "+RECEIVE") != NULL)
{
// 提取数据长度
char *p = strchr((char *)rx_buf, ':');
if (p != NULL)
{
p++; // 跳过冒号
u16 data_len = strlen(p);
if (data_len > max_len) data_len = max_len;
memcpy(buf, p, data_len);
return data_len;
}
}
}
return 0;
}
4.5 完整通信流程
/**
* @brief 上传加注记录
* @param record 记录数据
* @return 0:成功, <0:失败
*/
s8 Upload_Record(char *record)
{
s8 ret;
// 1. 建立连接
ret = GPRS_Connect("api.example.com", 8080);
if (ret != 0)
{
return -1; // 连接失败
}
// 2. 发送数据
ret = GPRS_Send((u8 *)record, strlen(record));
if (ret != 0)
{
GPRS_Close();
return -2; // 发送失败
}
// 3. 等待响应
vTaskDelay(1000);
u8 rx_buf[100];
if (GPRS_Receive(rx_buf, 100) > 0)
{
// 解析服务器响应
if (strstr((char *)rx_buf, "OK") != NULL)
{
GPRS_Close();
return 0; // 上传成功
}
}
GPRS_Close();
return -3; // 响应异常
}
/**
* @brief 关闭连接
*/
void GPRS_Close(void)
{
UARTSend(U_2, "AT+CIPCLOSE\r\n", 13);
vTaskDelay(500);
}
五、云端对接
5.1 协议设计
本项目采用自定义文本协议,简单易懂:
上传记录格式:
id=00000001|total=20|money=200|price=10|GPSX=118.123456|GPSY=32.123456|
字段说明:
- id: 设备ID
- total: 加注量(单位:100mL)
- money: 金额(单位:分)
- price: 单价(单位:分/100mL)
- GPSX: 经度
- GPSY: 纬度
5.2 服务器响应
成功: OK
失败: ERROR:原因
示例:
OK → 上传成功
ERROR:DB → 数据库错误
ERROR:AUTH → 认证失败
5.3 云平台选择
| 平台 | 特点 | 适用场景 |
|---|---|---|
| 阿里云IoT | 功能全面、生态成熟 | 企业级项目 |
| 腾讯云IoT | 性价比高、文档友好 | 中小项目 |
| OneNET | 移动出品、与Air208S兼容好 | GPRS项目 ✅ |
| 自建服务器 | 完全可控、成本可控 | 特殊需求 |
5.4 本项目架构
┌─────────────────────────────────────────────────────┐
│ 系统架构 │
│ │
│ ┌─────────┐ GPRS ┌─────────┐ │
│ │ 加注机 │ ◄────────────► │ 云服务器 │ │
│ │ (STM32) │ │ (API) │ │
│ └─────────┘ └────┬────┘ │
│ │ │
│ ┌────┴────┐ │
│ │ │ │
│ ┌────┴──┐ ┌────┴──┐ │
│ │ 管理后台│ │ 微信 │ │
│ │ (Web) │ │ 小程序 │ │
│ └───────┘ └───────┘ │
│ │
└─────────────────────────────────────────────────────┘
六、常见问题
Q1:模块不上线?
排查步骤:
- 检查电源:VCC是否在3.4V-4.2V之间?
- 检查SIM卡:SIM卡是否插好?是否欠费?
- 检查信号:AT+CSQ查询,信号是否>10?
- 检查网络:是否支持2G网络?(移动/联通)
// 信号强度判断
u8 csq = ParseCSQ(rx_buf);
if (csq == 99) {
// 99表示未知,可能是天线问题
}
else if (csq < 10) {
// 信号太弱,建议更换天线或位置
}
Q2:连接超时?
可能原因:
- 服务器地址错误:确认域名/端口正确
- 防火墙拦截:检查服务器端口是否开放
- 网络拥塞:GPRS网络质量不稳定,建议重试
// 重试机制
for (u8 retry = 0; retry < 3; retry++)
{
if (GPRS_Connect(server, port) == 0)
{
break; // 连接成功
}
vTaskDelay(5000); // 等待5秒重试
}
Q3:数据丢失?
原因分析:
- 发送未完成:未等待"SEND OK"
- 缓冲区溢出:接收缓冲区太小
- 并发冲突:多任务同时访问串口
解决方案:
// 使用信号量保护
xSemaphoreTake(gprs_sem, 1000);
GPRS_Send(data, len);
xSemaphoreGive(gprs_sem);
Q4:功耗过高?
GPRS模块功耗分析:
| 状态 | 电流 | 说明 |
|---|---|---|
| 待机 | 3mA | 空闲状态 |
| 数据传输 | 200-500mA | 平均电流 |
| 发射峰值 | 2A | 最大电流 |
省电建议:
- 不用时关闭连接
- 使用PSM低功耗模式
- 减少上报频率
七、进阶优化
7.1 断线重连机制
/**
* @brief 自动重连任务
*/
void GPRS_Task(void *pvParameters)
{
while (1)
{
// 检查连接状态
if (gprs_connected == 0)
{
// 尝试重连
if (GPRS_Connect(SERVER, PORT) == 0)
{
gprs_connected = 1;
}
else
{
// 重连失败,重启模块
GPRS_Restart();
}
}
// 发送心跳
if (gprs_connected)
{
GPRS_Send((u8 *)"PING", 4);
}
vTaskDelay(60000); // 60秒检查一次
}
}
7.2 数据缓存与补传
// 掉电保护:未上传记录存EEPROM
typedef struct {
u8 count; // 未上传记录数
u8 records[10][64]; // 最多缓存10条
} RecordCache;
// 上传成功后清除
void Clear_Record(u8 index)
{
memset(cache.records[index], 0, 64);
cache.count--;
}
// 启动时检查并补传
void Check_Cache(void)
{
for (u8 i = 0; i < cache.count; i++)
{
if (Upload_Record(cache.records[i]) == 0)
{
Clear_Record(i);
}
}
}
7.3 MQTT协议(可选)
如需更专业的物联网协议,可使用MQTT:
// Air208S支持MQTT指令
AT+MQTTCONNECT="broker.com",1883,"client_id","user","pass",1
AT+MQTTSUB="topic",0
AT+MQTTPUB="topic",0,0,"message"
八、总结
8.1 Air208S使用要点
| 要点 | 说明 |
|---|---|
| 电源设计 | 4.0V输出,≥470μF电容 |
| 通信测试 | 先用串口助手验证AT指令 |
| 错误处理 | 超时重试+断线重连 |
| 数据保护 | EEPROM缓存未上传记录 |
| 心跳保活 | 定时发送心跳包 |
8.2 GPRS vs 其他方案
| 场景 | 推荐方案 |
|---|---|
| 低频小数据 | GPRS ✅ |
| 高频大数据 | 4G/Cat1 |
| 室内有WiFi | WiFi |
| 静态低功耗 | NB-IoT |
8.3 本项目通信特点
- 低频上报:每次加注后上传一次
- 数据量小:单条记录约60字节
- 可靠性高:重试+缓存+补传机制
- 成本低:GPRS模块约¥20
九、源码获取
本文完整源码已收录至「STM32物联网项目资料包」
资料包包含:
- ✅ GPRS通信完整代码(初始化/连接/收发)
- ✅ 玻璃水加注机完整工程
- ✅ 外设驱动代码模板
- ✅ 调试技巧文档
- ✅ 常见问题FAQ
获取方式:
- 点赞 + 收藏本文
- 私信我,备注「资料」免费领取
作者:宋一平 | 嵌入式/物联网技术分享
转载请注明出处
更多推荐
所有评论(0)