十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32+SIM800C温湿度GPS数据上报OneNet云平台全流程解析

STM32+SIM800C温湿度GPS数据上报OneNet云平台全流程解析 简介工程包基于SIM800C模块与STM32微控制器是一套物联网通信代码包面向嵌入式开发初学者及物联网项目设计者解决将温湿度与GPS数据上传至OneNet云平台的问题。工程源码包含DHT11温湿度采集、ADC模拟量读取、USART串口收发、TIMER定时控制、SIM800C无线通信、IIC总线驱动、GPS数据解析和OLED显示等模块覆盖从底层外设到上层协议对接的完整链路。资源共87个文件压缩包约1.08MB其中主要有C语言源文件、H头文件、uvproj工程文件以及用于编译和调试的o、crf、lst、axf、map、hex等中间输出文件便于直接打开工程查看或烧录验证。整体目录按驱动分层组织结构清晰适合参考学习。已有3578人浏览学习。通过该资源可以快速掌握AT指令操作、数据帧拼接、云平台接入流程等核心环节并配合作者博客进一步理解实际项目中的排错与调试方法。1. SIM800C STM32 把温湿度和 GPS 数据打进 OneNet这条链路为什么还值得拆预算只够买几十块的模块、手上没有 4G Cat.1 现货、又想把 DHT11 温湿度和 GPS 经纬度数据持续往 OneNet 云平台推最直接的做法仍然是 SIM800C 走 GPRS。这套 MDK 工程把 DHT11 采集、GPS NMEA 解析、OLED 本地显示、SIM800C 拨号建链、HTTP POST 上报串成了完整闭环工程里每个外设模块都被拆成了独立文件能直接从代码看到数据从传感器到云平台的每一层是怎么接的。适合刚学完 STM32 标准库、想把手头传感器数据真正推到云平台上画折线图的人。2. OneNet 接入方式选型与设备侧参数准备OneNet 老平台对低资源 MCU 主要提供 HTTP、EDP、MQTT 三条接入路径。MQTT 需要在 MCU 里实现协议栈和心跳保活逻辑EDP 是 OneNet 私有协议调试资料相对少HTTP 最直接TCP 连上 80 端口、按固定格式 POST 一段 JSON 就完成一次上报SIM800C 的 AT 指令天然适合这种“请求-响应”模式。这套工程走的就是 HTTPURL 结构为/devices/{device_id}/datapoints?type3body 是装载温湿度、经纬度的 JSON 数组。动手改代码之前先把 OneNet 平台侧的参数准备好否则后面每一条 HTTP 请求都会在鉴权上卡住。2.1 创建产品与设备协议类型直接决定上报 URL登录 OneNet 控制台在“多协议接入”里创建产品协议类型选择 HTTP。这里有个很容易忽略的点OneNet 新版平台和旧版租户平台的入口略有差异但/datapoints?type3这个旧版 HTTP 接口在存量设备上仍保持兼容。创建完产品后添加设备系统会分配一个数字形式的设备 ID这个 ID 要填进 URL 路径里。APIKey 建议使用设备级 APIKey 而不是产品级权限范围小出问题时能从返回码精确区分是哪台设备的问题。创建完设备后进入“数据流管理”新建四个数据流temp、humi、lat、lng名称不要用大写字母OneNet 对数据流 ID 区分大小写Temp和temp是两个不同的流后面 JSON 里写错一个字符云平台就多一条错误日志。把这几个参数抄到工程头文件的宏定义里后面 HTTP 报文拼接会直接引用。2.2 用 curl 先验证平台通不通在烧录到板子之前建议先在电脑上用 curl 模拟 SIM800C 的 HTTP POST确认平台侧的 DeviceID、APIKey、数据流 ID 都是可用的。这一步用不了五分钟却能把“硬件问题”和“平台参数问题”彻底分开。curl -X POST \ http://api.heclouds.com/devices/506123456/datapoints?type3 \ -H api-key: AbC12345 \ -H Content-Type: application/json \ -d {datastreams:[{id:temp,datapoints:[{value:26.4}]},{id:humi,datapoints:[{value:58.2}]}]}curl 的-H指定 HTTP 头api-key必须与 OneNet 上生成的字符串完全一致注意复制时别带空格或换行-d是请求体里面id对应数据流 IDvalue对应数据点值。返回{errno:0,error:succ}说明平台侧链路是通的可以在数据流页面看到刚写入的数据点。如果返回errno非 0先把第 2.1 节的表格逐项核对一遍再碰板子。2.3 工程里需要预填的参数清单整理成一张表替换工程头文件里的宏时逐项对照。参数示例值出现位置DEVICE_ID506123456HTTP 请求行/devices/{id}/datapointsAPI_KEYAbC12345HTTP 头api-keyHOSTapi.heclouds.comHTTP 头HostPORT80SIM800CATCIPSTART连接端口数据流 IDtemp/humi/lat/lngJSON 体中id字段这几个参数里最容易出错的是 APIKey 末尾的字符OneNet 生成的 Key 经常以结尾在 C 字符串里直接写#define API_KEY AbC12345即可不用转义。DeviceID 是数字字符串拼接 URL 时用sprintf格式化进去。3. SIM800C 建链流程与 AT 指令状态机SIM800C 本身就是一个完整的 TCP/IP 协议栈STM32 要做的只是通过串口向它发送 AT 指令。这套工程里 STM32 与 SIM800C 的交互是典型的主从状态机STM32 发指令、等响应、根据响应内容决定下一步动作。模块从开机到能发 HTTP 请求中间要经过 SIM 卡读取、驻网、附着 GPRS、建立 TCP 连接、进入透传五个阶段任何一步返回 ERROR后面都是白等。建议先不看 STM32 代码用 USB 转 TTL 直接连模块把整条 AT 链路手工跑通。3.1 硬件接线与 SIM800C 上电时序SIM800C 供电电压范围是 3.4V 到 4.4V峰值电流在 GSM 发射瞬间能到 2A用 STM32 板上的 3.3V LDO 直接供电会导致模块重启。常见做法是外接 4V/2A 电源或锂电池并在模块电源引脚并一个 470uF 电解电容和 100nF 陶瓷电容。STM32 与 SIM800C 的串口交叉连接STM32 的 TX 接 SIM800C 的 RXDSTM32 的 RX 接 SIM800C 的 TXD共地。SIM800C 的逻辑电平是 2.8VSTM32 是 3.3V直接连问题不大保守一点可以在 TXD 路径上串一个 1K 电阻限流。SIM800C 上电后不会立刻进入 AT 指令接收状态PWRKEY 引脚需要外部拉低至少 1 秒。工程里的做法是 GPIO 控制三极管拉低 PWRKEY延时后再拉高。上电后模块的 NETLIGHT 指示灯慢闪表示已找到网络快闪表示还在搜网不闪说明模块没启动成功。3.2 驻网、附着 GPRS 与 TCP 透传的 AT 序列以下指令序列在串口调试助手里逐条发送并确认返回值全部走通后再看代码。AT # 同步返回 OK ATE0 # 关闭回显让后面解析简单 ATCPIN? # 返回 READY 表示 SIM 卡已识别 ATCREG? # 返回 0,1 表示已注册到 GSM 网络 ATCGATT? # 返回 0,1 表示 GPRS 已附着 ATCGDCONT1,IP,CMNET # 设置 APN 为 CMNET ATCIPMODE1 # 开启透传模式 ATCIPSTARTTCP,api.heclouds.com,80 # 建立 TCP 连接 # 返回 CONNECT OK 后 ATCIPSEND # 返回 后进入透传开始发送 HTTP 报文ATCPIN?返回 ERROR 要先检查 SIM 卡座触点ATCREG?长时间返回0,0说明天线没接好或信号弱ATCGDCONT里的CMNET是移动公网 APN如果是物联网专用卡这里要换成卡商提供的 APN 名称。ATCIPMODE1是关键它让模块进入透传模式ATCIPSEND之后所有的串口数据都会原样通过 TCP 连接发出去不再需要逐条 AT 指令封装。退出透传的方法是发送三个加号之间间隔超过一秒模块会退回指令模式。3.3 STM32 串口驱动把 AT 应答映射成状态工程里 SIM800C 挂在 USART3 上STM32 串口中断把模块返回的数据存进环形缓冲区主循环里的状态机按阶段匹配关键字符串。核心逻辑可以抽象成下面这段uint8_t Sim800C_State STATE_SYNC; void Sim800C_Task(void) { char *resp Get_Buffer(); // 从串口缓冲区取一段响应 switch (Sim800C_State) { case STATE_SYNC: UART3_SendString(AT\r\n); if (strstr(resp, OK)) Sim800C_State STATE_CREG; break; case STATE_CREG: UART3_SendString(ATCREG?\r\n); if (strstr(resp, 0,1)) Sim800C_State STATE_CGATT; break; case STATE_CIPSTART: UART3_SendString(ATCIPSTART\TCP\,\api.heclouds.com\,\80\\r\n); if (strstr(resp, CONNECT OK)) Sim800C_State STATE_SEND; break; default: break; } }每个状态只负责发一条指令并匹配一个关键字匹配失败时保留当前状态等待下一次超时重试。要注意 SIM800C 的响应可能有回车换行和前缀空格strstr只要包含目标串就认为成功。透传环节不能用这种轮询方式进透传后串口收到的任何数据都是 TCP 对端的响应需要直接交给 HTTP 报文解析流程处理。4. STM32 侧数据采集与 HTTP 报文拼接链路通了以后真正的工程量落在两个地方一是把 DHT11 和 GPS 模块的数据可靠读出来二是把这些数据拼成 OneNet 认可的 HTTP 报文。工程文件里 SYSTEM 目录放底层驱动SIM800C、GPS、DHT11、OLED 各自成文件夹main.c 里的执行顺序是初始化外设 → 读 DHT11 → 读 GPS → 拼 HTTP → SIM800C 上报。下面按这个顺序拆开看。4.1 外设分配与工程目录定位按工程里的默认配置外设分配如下模块接口STM32 引脚DHT11单总线 GPIOPA6GPSUSART2PA2 / PA3SIM800CUSART3PB10 / PB11OLED软件 IICPB8 / PB9LED 指示灯GPIO 推挽PC13GPS 和 SIM800C 分属两个串口DHT11 用普通 GPIO 模拟时序OLED 用软件 IIC整套方案不依赖硬件 I2C 和高级定时器换到 STM32F103C8T6 时只需要把 GPS 串口相关引脚改为重映射即可。工程里stm32f10x_md.s说明目标芯片是中等容量型号标准外设库版本对应 Keil 里 Device 选择的 STM32F103 系列。4.2 DHT11 温湿度读取与校验DHT11 是单总线器件数据线需要外接 4.7K 上拉电阻。读取一次数据的时序是主机拉低 18ms 以上发起起始信号然后释放总线DHT11 拉低响应后再输出 40bit 数据。工程里的读取代码核心如下uint8_t DHT11_Read_Data(float *temp, float *humi) { uint8_t buf[5] {0}, crc 0; GPIO_ResetBits(GPIOA, GPIO_Pin_6); Delay_Ms(20); // 起始信号至少18ms GPIO_SetBits(GPIOA, GPIO_Pin_6); Delay_Us(30); // 释放总线等待响应 if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) SET) return 1; // 无响应 for (uint8_t i 0; i 5; i) for (uint8_t j 0; j 8; j) buf[i] (buf[i] 1) | DHT11_Read_Bit(); crc buf[0] buf[1] buf[2] buf[3]; if (crc ! buf[4]) return 2; // 校验失败 *humi buf[0] buf[1] / 10.0f; *temp buf[2] buf[3] / 10.0f; return 0; }DHT11_Read_Bit()的判定依据是高电平持续时间DHT11 先拉低 50us再拉高 26us 表示 0拉高 70us 表示 1。用延时函数在电平跳变后采样两次即可区分。校验公式是前四个字节之和的低 8 位等于第五个字节返回值 1 是器件无响应返回值 2 是数据被干扰主循环里对这两个错误要做重试处理不要直接把脏数据拼进 JSON。4.3 GPS NMEA 解析与坐标转换GPS 模块通过 USART2 持续输出 NMEA 0183 协议语句其中$GPRMC包含经纬度和定位状态推荐首选解析它。一条典型的 GPRMC 语句如下$GPRMC,083559.00,A,2235.1234,N,11356.5678,E,0.00,0.00,010181,,,A*5F字段按逗号分隔第 2 个字段是定位状态A表示有效定位V表示丢星第 3 和第 4 个字段是纬度及南北半球第 5 和第 6 个字段是经度及东西半球。NMEA 坐标格式是“度分”形式需要转换成十进制才能被 OneNet 折线图友好显示。float Convert_NMEA_To_Decimal(float ddmm) { int degree (int)(ddmm / 100); float minute ddmm - degree * 100; return degree minute / 60.0f; }例如2235.1234解析为北纬22 35.1234 / 60 22.58539度。工程里一般用strstr定位$GPRMC再用strtok或手工指针逐字段提取。注意 GPS 模块冷启动时定位可能要几十秒到几分钟这段时间 GPRMC 的状态位一直是V后续上报逻辑必须过滤掉无效坐标。4.4 HTTP 报文组装与 Content-Length 对齐OneNet 的 HTTP 接口要求请求头里带 Content-Length 且长度必须与请求体字节数完全一致。Content-Length 偏长或偏短服务器会一直等待剩余数据直到超时这是 SIM800C 上报失败最常见的原因。工程里的拼接逻辑如下char json[256]; uint16_t json_len sprintf(json, {\datastreams\:[{\id\:\temp\,\datapoints\:[{\value\:%.1f}]}, {\id\:\humi\,\datapoints\:[{\value\:%.1f}]}, {\id\:\lat\,\datapoints\:[{\value\:%.6f}]}, {\id\:\lng\,\datapoints\:[{\value\:%.6f}]}]}, temperature, humidity, latitude, longitude); char http_req[320]; sprintf(http_req, POST /devices/%s/datapoints?type3 HTTP/1.1\r\n Host: api.heclouds.com\r\n api-key: %s\r\n Content-Type: application/json\r\n Content-Length: %d\r\n\r\n %s, DEVICE_ID, API_KEY, json_len, json);json_len是 sprintf 的返回值表示写入 JSON 数组的实际字节数%.6f保证经纬度精度到小数点后 6 位大约 0.1 米的分辨率。HTTP 头和请求体之间必须有一空行也就是上面对应的\r\n\r\n。拼接完成后用strlen(http_req)看一眼总长度如果大于 SIM800C 单次ATCIPSEND的发送上限可以分两次CIPSEND但更省事的做法是把温湿度、经纬度拆成两条 HTTP 请求每条都独立计算 Content-Length。提示sprintf 里的转义引号\很容易漏写拼接完后建议在串口把http_req完整打出来对着协议逐字检查一遍再上模块。5. SIM800C 与 OneNet 联调排错看响应、看灯、看数据流这一章把调试时最容易踩的三个坑单独拎出来每个都有明确的排查路径。5.1 上板之前先用 USB 转 TTL 打通 AT 链路STM32 主控和 SIM800C 之间隔着一层代码出问题时很难分清楚是 AT 指令发错还是模块没驻网。我一般会在新板子上电后先断开 STM32 的 TX用 USB 转 TTL 直接接 SIM800C 的串口把第 3.2 节的 AT 指令序列手工发一遍。重点看两个返回ATCREG?是否返回0,1以及ATCIPSTART是否返回CONNECT OK。如果前者一直返回0,0把天线换成外置吸盘天线放到窗边再试如果ATCIPSTART返回ERROR检查第 3.2 节最后一个指令序列里CIPSTART后面的双引号是否被串口工具转义成了中文引号。链路手工跑通后再接回 STM32 调试代码层面。5.2 OneNet 返回码与 HTTP 状态码对照HTTP 请求发出去后SIM800C 透传模式会原样返回 OneNet 的响应常见的有下面几种响应内容含义排查方向{errno:0,error:succ}数据点写入成功去数据流页面看折线图{errno:17,error:...}鉴权失败检查 api-key 是否多余空格或复制错误{errno:21,error:...}参数错误检查请求体 JSON 格式和 datastreams 结构HTTP/1.1 404 Not Found路径或设备 ID 错误检查 DeviceID 是否填成了产品 IDHTTP/1.1 400 Bad RequestHost 头未识别检查 HTTP 报文第一行是否带了/datapoints?type3errno:17是这套工程里出现频率最高的错误一半是因为 APIKey 末尾的没复制全另一半是字符串里混入了\r\n。在代码里把API_KEY宏附近的换行符删干净用串口调试助手逐字节查看实际发送的 HTTP 头。如果是新注册的 OneNet Studio 平台旧版api.heclouds.com设备接入不支持在 Studio 产品里直接创建需要回到物联网平台旧版入口操作。5.3 丢星状态下不要上报无效 GPS 坐标GPS 模块在隧道、高架桥下或者阴天GPRMC 状态位会从A变回V此时经纬度数据是上一次定位的缓存或者全零。工程里上报前要加一道过滤只有当状态位是A时才把 lat 和 lng 拼进 JSON状态位为V时只上报温湿度两个数据流或者把经纬度直接替换成0.0。如果不过滤OneNet 折线图上会出现一条从零点到实际位置的斜线把整张图拉偏。字符串里提取状态位时注意 GPRMC 第 2 个字段是A或V用strstr找到$GPRMC后跳过 18 个字符再判断即可。另外 GSM 天线和 GPS 天线在布局时尽量拉开 10cm 以上距离GPRS 发射瞬间会明显抬高 GPS 模块的噪声底贴太近会导致刚刚收星成功的信号又被压掉。本文还有配套的精品资源点击获取
返回列表