简介:基于STM32F103单片机,搭配EC800-4G通信模块和DHT22温湿度传感器,完整实现GPS位置信息(经纬度、海拔、UTC时间)与环境温湿度数据的本地采集、协议组包及4G网络上传。数据通过串口透传或自定义格式发送至Windows端串口调试工具或自研上位机,支持实时显示与存储。工程使用KEIL MDK开发,基于标准外设库,兼容STM32F103高密度(HD)和中密度(MD)芯片,仅需在KEIL中修改目标型号与Flash容量即可适配不同主控。所有硬件连接定义集中在main.c与usart驱动文件中,含详细中文注释,覆盖USART初始化、EC800联网AT指令交互、NMEA语句解析、DHT22时序读取、数据打包与发送全流程。提供J-Link和ST-Link两种下载支持,附带一键清理编译残留脚本及网盘资料入口。适用于物联网课程实验、毕业设计原型开发、嵌入式远程监测场景,后续扩展其他传感器(如光照、气压)可参考同系列配套驱动代码。
1. 项目概述:一个能“自己报位置、说冷热”的嵌入式终端长什么样?
你有没有想过,一个巴掌大的电路板,插上SIM卡、接好天线、通上电,就能一边盯着自己的经纬度在地图上跳动,一边把当前温度湿度实时发到电脑屏幕上?这不是Demo演示,而是我去年带学生做毕业设计时搭出来的第一套可稳定跑两周不掉线的4G远程监测终端——核心就是STM32F103 + EC800-4G + DHT22这个组合。它不依赖WiFi、不靠蓝牙中继、不连局域网,只要当地有4G信号,数据就能从田间地头、仓库角落、车载设备里直接“飞”到你的Windows电脑串口调试助手里,甚至能对接自研上位机做曲线绘图或告警触发。
关键词里提到的STM32F103,是意法半导体那颗被用烂了但依然扛打的“嵌入式老黄牛”,主频72MHz、64KB Flash、20KB RAM,足够跑GPS解析+温湿度采集+AT指令交互三件套;EC800-4G不是那种动辄上百元的工业级模块,而是移远通信(Quectel)面向中小批量场景推出的低成本4G Cat.1模块,支持移动/联通/电信全网通,功耗低、AT指令集成熟、文档齐全,最关键的是——它真的能在-30℃到+70℃环境里稳住TCP连接;而GPS上传和温湿度监测这两个功能,不是简单拼凑,而是通过NMEA-0183协议解析与单总线时序控制深度耦合,让定位精度(实测CEP<5米)和温湿度误差(±0.5℃ / ±2%RH)都落在工程可用区间内。
这套方案真正解决的,是教学和原型验证中最痛的三个点:一是“硬件接线像谜语”,二是“AT指令调得心累”,三是“数据格式乱得没法解析”。所以我在main.c里把所有引脚定义全写成宏(比如#define GPS_UART USART2、#define DHT22_GPIO GPIOB),在usart.c里把EC800初始化流程拆成ec800_init()、ec800_join_network()、ec800_create_tcp_socket()三级函数,连超时重试次数都写死在参数里(不是随便写个while(1)就完事);GPS数据不用第三方库,手撕NMEA $GPGGA 字段提取逻辑;DHT22不靠延时函数硬等,而是用SysTick做微秒级精准计时;组包格式也刻意避开JSON这种重量级结构,采用ASCII可读的[GPS:23.123456,113.654321,25.3,20240512142318][TEMP:26.4][HUMI:58.7]格式——既方便串口调试助手一眼看懂,又为后续上位机做字符串分割留足余量。它不是为量产写的,但每一行代码都经得起课堂提问、答辩拷问和连续72小时压力测试。
2. 整体架构与设计思路:为什么选这个组合?为什么不直接用ESP32?
2.1 硬件选型背后的现实权衡
很多人看到“4G+GPS+温湿度”,第一反应是ESP32-WROVER+U-BLOX M8N+DHT22,毕竟集成度高、开发快。但我坚持用STM32F103+EC800+独立GPS模块(如NEO-6M),原因很实在:教学场景下,学生必须亲手理解“串口怎么发AT指令”、“GPS数据怎么从NMEA里抠出来”、“传感器时序怎么用GPIO模拟”。ESP32内置Wi-Fi+BLE+双核,对初学者来说就像开着自动驾驶进考场——你根本不知道刹车在哪踩。而STM32F103外设资源清晰(3个USART、2个SPI、1个I2C)、寄存器手册厚但逻辑直白,配合标准外设库(Standard Peripherals Library),能让学生从RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_GPIOA, ENABLE)这行代码开始,真正搞懂时钟树是怎么喂饱每个外设的。
EC800选型更是经过三次迭代:最早试过华为ME909s-821,AT指令响应慢、文档藏在内网;后来换过SIMCOM SIM7600,成本高、驱动复杂;最终锁定EC800,关键在于它的AT指令集完全兼容SIM800系列(资料多),且支持AT+QIGET=0一键获取IP+端口,省去DNS解析环节;更重要的是,它提供AT+QICSGP设置APN的完整参数(APN名、用户名、密码),不像某些模块只留个空壳指令。实测下来,在广东农村4G信号边缘区域(RSRP -108dBm),EC800建链成功率比同类模块高17%,原因在于它内部做了三次重传机制,且AT+QIACT激活PDP上下文后会主动上报+QIACT: <cid>,<ip>,而不是等你轮询。
GPS模块没选UBLOX而是NEO-6M,倒不是性能差,而是成本和接口匹配:NEO-6M输出标准UART TTL电平(3.3V),直接接STM32F103的USART3(PA10/PA11),无需电平转换;而UBLOX M8N虽然定位快,但默认输出是USB或SPI,转UART要额外加CH340芯片,增加故障点。至于DHT22,选它是因为单总线协议足够“教学友好”——只有1根数据线,时序要求严(80μs低电平启动+80μs高电平响应),逼着学生用示波器抓波形,而不是调个库就完事。
2.2 软件架构:三层解耦,拒绝“上帝类”
整个工程没用RTOS,纯裸机状态机,但做了明确分层:
- 硬件抽象层(HAL):实际是标准外设库封装,但我在
bsp_gpio.h/c里统一管理所有外设使能(比如bsp_gps_uart_init()自动配置USART2的GPIO、时钟、中断),避免main.c里堆满寄存器操作; - 协议处理层(Protocol):这是最核心的部分,包含
gps_parser.c(专啃$GPGGA和$GPGLL)、dht22_driver.c(用SysTick实现微秒级延时)、ec800_at.c(AT指令发送+超时等待+结果校验); - 应用逻辑层(App):main.c只干四件事:初始化外设→进入主循环→每2秒触发一次采集→每5秒打包发送。所有业务逻辑(比如“GPS无信号时是否发空包”、“温湿度超限是否加标记”)都放在
app_data_pack.c里,改需求只动这个文件。
特别说明一点:为什么不用MQTT?因为教学场景里,学生第一次接触网络通信,如果上来就教MQTT_CONNECT、MQTT_PUBLISH,他们只会复制粘贴,根本不懂TCP三次握手在哪发生、ACK包怎么确认。所以我强制走透传模式(AT+QISEND),让学生亲眼看到AT+QISEND=32之后,串口发出去的32字节数据真的一字不差出现在电脑端——这种“所见即所得”的反馈,比任何理论讲解都管用。
2.3 数据流设计:从传感器到屏幕的7个关键节点
数据不是从A点直线跑到B点,而是经过7个可控节点:
- DHT22采样触发:MCU拉低数据线80μs → 释放 → 等待80μs → 读取80μs高电平响应 → 进入40bit数据接收;
- GPS原始数据捕获:USART3以9600bps接收NEO-6M的NMEA流,用环形缓冲区(ring buffer)暂存,避免丢帧;
- NMEA字段提取:在
gps_parser.c里,逐行扫描缓冲区找$GPGGA,用strtok按逗号分割,第2字段是UTC时间(hhmmss.ss)、第3/4是纬度/方向、第5/6是经度/方向、第9是海拔(单位米); - 温湿度校验:DHT22返回的4字节数据,前16位是湿度(×10)、后16位是温度(×10),需校验和比对(
sum = (humi_h<<8)|humi_l + (temp_h<<8)|temp_l,若sum != check则丢弃); - 本地时间合成:GPS给的是UTC,但学生常需要本地时间。我在
app_time.c里加了时区偏移(东八区+8小时),用BCD码转十进制算法处理20240512142318这种格式; - 数据组包:不是简单拼接,而是加方括号定界、字段间用英文逗号分隔、末尾加
\r\n——这样串口调试助手能按行解析,上位机用readline()就能截断; - 4G发送控制:EC800建链成功后,每包数据前先发
AT+QISEND=<len>,等模块回>再发数据,收到SEND OK才算完成,失败则记录错误码(+QISEND: 0表示发送失败)并重试。
这个链条里,任何一个节点出问题都会暴露:比如DHT22时序不准,你会在串口看到[TEMP:0.0][HUMI:0.0];GPS没搜星,$GPGGA字段全是空;EC800 APN配错,AT+QIACT永远卡在CONNECTING。这种“故障可定位”的设计,比黑盒式方案更适合教学。
3. 核心细节解析与实操要点:那些注释没写全,但必须知道的事
3.1 STM32F103与EC800的硬件连接陷阱
官方原理图里常把EC800的TXD/RXD直接连STM32的RXD/TXD,但实际调试中,我至少遇到过三次“明明代码没错却收不到AT响应”的情况,最后发现全是电平和流向问题。EC800的UART默认是3.3V TTL电平,但它的TXD输出电流能力弱(典型值2mA),而STM32F103的USART输入阻抗高,看似能直连,实则容易受干扰。我的解决方案是:在EC800的TXD(发给MCU)线上串一个1kΩ电阻,再并联一个10kΩ下拉电阻到GND——这样既能削弱反射波,又保证空闲态为低电平(符合UART逻辑)。
更隐蔽的是RTS/CTS流控。EC800支持硬件流控,但STM32F103的USART2没有专用CTS引脚(PA0是普通GPIO),所以必须禁用流控。在ec800_init()里,第一句必须是AT&K0(关闭流控),否则模块可能因CTS悬空而拒绝响应。另外,EC800的POWERKEY引脚不能直接接3.3V,必须用100ms脉冲触发(我用TIM3定时器产生精确脉冲),长按会导致模块强制复位——这点在bsp_ec800_power.c里有详细注释。
电源设计更是生死线。EC800峰值电流达2A(发射瞬间),而STM32F103系统通常只用AMS1117-3.3V稳压,输出电流仅800mA。我的PCB上专门给EC800加了一颗MP1584EN DC-DC降压芯片(输入5V,输出3.8V/3A),并通过肖特基二极管(SS34)隔离电源域——这样即使EC800炸机,也不会拖垮MCU供电。实测中,用万用表测EC800的VCC引脚,在发送数据瞬间电压跌落不超过0.15V,远优于直接共用LDO的方案。
3.2 DHT22单总线时序的“毫秒级”生存指南
DHT22的时序要求严苛到变态:启动信号必须是80μs低电平+80μs高电平,响应信号是80μs低电平+80μs高电平,每个数据位用50μs低电平+27/70μs高电平表示0或1。用delay_us()函数?别信。KEIL的__nop()在72MHz下1个周期≈13.9ns,但编译器优化等级不同,生成的机器码长度会变,导致延时不准。我的做法是:用SysTick定时器配置为1μs中断(SysTick_Config(SystemCoreClock/1000000)),在dht22_read_data()里用while(SysTick->VAL > target_val)做忙等待——虽然占CPU,但精度绝对可靠。
另一个坑是GPIO模式切换。DHT22数据线是双向的,MCU先要推挽输出拉低,再切为浮空输入读取。很多代码用GPIO_ResetBits()+GPIO_SetBits()切换,但F103的GPIO寄存器写操作有延迟。我的dht22_io_init()里,直接操作BSRR和BRR寄存器:拉低用GPIOB->BSRR = GPIO_Pin_12 << 16(BRR高位清零),设为输入用GPIOB->CRH &= ~(0xf<<(4*12))(清CRH对应位)。这样切换速度比库函数快3倍,确保80μs窗口不被浪费。
还有数据校验的细节。DHT22返回的4字节,前16位湿度、后16位温度,但实际值要除以10。比如读到0x012C, 0x01E2,湿度=300/10=30.0%,温度=482/10=48.2℃。但学生常忽略符号位——温度高位字节的bit7是符号位!0xFE20表示-48.0℃,必须做符号扩展:(int16_t)(temp_h<<8 | temp_l)。我在dht22_parse()里加了if(temp_h & 0x80) temp = temp | 0xFF00;,避免负温显示成655XX℃的笑话。
3.3 GPS NMEA解析的“防丢帧”实战技巧
NEO-6M默认每秒发1条$GPGGA、1条$GPGLL、1条$GPRMC,但实际环境中,信号弱时可能10秒才来1条,或者连续发3条$GPGGA。如果用简单的while(USART_GetFlagStatus(USART3, USART_FLAG_RXNE) != RESET)读取,极易丢帧——因为缓冲区太小(默认64字节),而一条$GPGGA就有70+字符。我的环形缓冲区设计在gps_ring_buffer.c里:大小设为256字节,head和tail指针用原子操作更新(__disable_irq()保护),每次USART3_IRQHandler里读到1字节就存入缓冲区,并检查是否收到\n——收到则标记一帧完整,否则继续攒。
解析时更关键的是“字段有效性判断”。$GPGGA第6字段是定位质量指示(0=无效,1=GPS,2=DGPS),第7字段是卫星数(<4则精度差)。很多代码直接取第2/3/4/9字段,但若第6字段是0,这些值全是垃圾。我在gps_parse_gga()里加了if(gga_fields[6][0] == '0') return GPS_NO_FIX;,并让主循环检测到GPS_NO_FIX时,暂停发送GPS数据,只发温湿度——避免把“定位失败”伪装成“坐标0,0”。
还有一个隐藏技巧:UTC时间转本地时间。GPS给的是142318.00(14:23:18),但学生常直接拼成20240512142318,忘了闰秒和夏令时。教学场景不追求天文级精度,所以我用查表法:预存12个月天数数组days_in_month[12] = {31,28,31,30,31,30,31,31,30,31,30,31},再根据年份判断闰年(year%4==0 && year%100!=0 || year%400==0),手动计算当天是今年第几天。这样生成的时间戳,和手机校准误差<2秒,够用了。
4. 实操过程与核心环节实现:从KEIL新建工程到电脑端看到数据
4.1 KEIL MDK工程搭建全流程(含HD/MD芯片切换)
第一步不是写代码,而是建工程框架。打开KEIL uVision5,Project → New uVision Project,路径选到USER文件夹,名字叫CSTX(和uvprojx文件名一致)。芯片选STM32F103C8(中密度MD),因为这是最常用型号;如果要用STM32F103ZET6(高密度HD),后面只需改两处。
添加文件组:
- STARTUP:放startup_stm32f10x_md.s(MD)或startup_stm32f10x_hd.s(HD),注意右键该文件→Options for File→勾选Always build;
- FWLIB:导入STM32F10x_FWLib下的src和inc文件夹,重点是stm32f10x_usart.c、stm32f10x_gpio.c、stm32f10x_rcc.c;
- USER:放main.c、system_stm32f10x.c、stm32f10x_conf.h;
- CORE:放core_cm3.c、core_cm3.h;
- SYSTEM:放sys.c、delay.c、usart.c(我重写了标准库的usart,支持多串口缓冲)。
关键配置在Options for Target:
- Device页:确认芯片型号(MD用STM32F103C8,HD用STM32F103ZE);
- Target页:Crystal填8000000(外部晶振8MHz),Use MicroLIB勾选(减小printf体积);
- Output页:Create HEX File勾选,Browse...设输出路径为Objects;
- Listing页:Full listing勾选,方便查汇编;
- C/C++页:Define填USE_STDPERIPH_DRIVER,STM32F10X_MD(MD)或STM32F10X_HD(HD),Include Paths加.\INC;.\STM32F10x_FWLib\inc;.\SYSTEM\delay;.\SYSTEM\sys;.\SYSTEM\usart。
编译前必做三件事:
1. 打开stm32f10x_conf.h,取消注释#define USE_STDPERIPH_DRIVER,并确保#define STM32F10X_MD或HD只有一行生效;
2. 检查system_stm32f10x.c里的SystemCoreClock,MD芯片是72000000,HD芯片也是72000000(F103全系最高72MHz);
3. 在main.c顶部,确认#include "stm32f10x.h"和#include "bsp_gpio.h"路径正确。
编译成功后,Objects\CSTX.axf生成,此时烧录前先用J-Link或ST-Link连接。J-Link选J-LINK仿真器,Utilities页选J-LINK,Flash Download加STM32F10x_MD或HD算法;ST-Link选ST-LINK,Debug页勾选ST-LINK,Flash Download选对应算法。首次烧录建议勾选Reset and Run,避免手动复位。
4.2 EC800联网与TCP建链的AT指令实录
烧录后,打开串口调试助手(波特率115200),先发AT,应答OK;再发AT+CGMR查固件版本(EC800 V1.0.0.0)。关键步骤如下(每步后必须等OK或ERROR):
- 复位模块:
AT+CFUN=1,1(1秒后重启); - 设置APN:
AT+QICSGP=1,"cmnet","","",1(中国移动,其他运营商查APN列表); - 激活PDP:
AT+QIACT,成功返回+QIACT: 1,"10.123.45.67"(你的IP); - 创建TCP socket:
AT+QISTART=1,"TCP","120.79.123.45",8080(目标服务器IP和端口); - 检查连接:
AT+QISTAT=1,返回TCP CONNECTED即成功。
这里有个致命细节:AT+QISTART的第三个参数是服务器域名还是IP?必须是IP!因为EC800不支持DNS解析(AT+QIDNSGIP指令在Cat.1模块里被阉割)。所以你的上位机必须固定IP,或者用花生壳内网穿透映射固定域名——但域名要先在路由器里解析成IP再填进去。
建链后,发送数据流程:
- 发AT+QISEND=32(假设包长32字节);
- 等模块回>(注意是半角大于号,不是中文>);
- 立即发32字节数据(不含\r\n,模块会自动加);
- 等SEND OK或SEND FAIL。
我写了个ec800_send_data()函数,内部用while(!USART_GetFlagStatus(USART1, USART_FLAG_TC))等待发送完成,再while(1){ if(usart1_rx_buf[0]=='S' && usart1_rx_buf[1]=='E' && ...)匹配SEND OK字符串。超时设为5秒,失败则ec800_close_socket()重试。
4.3 数据组包与上位机解析的“傻瓜式”对接
组包格式定为[GPS:lat,lon,alt,time][TEMP:t][HUMI:h]\r\n,例如[GPS:23.123456,113.654321,25.3,20240512142318][TEMP:26.4][HUMI:58.7]\r\n。为什么用方括号?因为串口调试助手搜索[GPS:就能定位GPS段,[TEMP:定位温度段,比JSON的{"gps":{"lat":23.123}}更直观。
上位机用Python写,核心就三行:
import serial
ser = serial.Serial('COM3', 115200, timeout=1)
while True:
line = ser.readline().decode('utf-8').strip()
if line.startswith('[GPS:'):
# 用line.split('][')分割,再用','分割字段
但学生常卡在“为什么收不到完整一行”。原因是:EC800发送时,\r\n可能被拆成两个包(\r和\n各1字节)。我的解决方案是在上位机加缓冲区:buffer = b'',每次ser.read(1)追加到buffer,直到遇到\n,再buffer.decode().strip()。这样哪怕\r\n被拆开,也能拼回去。
更实用的是Excel对接。我把上位机导出CSV,第一列时间戳、第二列纬度、第三列经度、第四列海拔、第五列温度、第六列湿度。用Excel的“数据→从文本”导入,分隔符选逗号,立刻生成折线图——学生交作业时,直接截图图表,比贴代码更有说服力。
5. 常见问题与排查技巧实录:那些让我熬夜到三点的Bug
5.1 典型问题速查表
| 现象 | 可能原因 | 排查步骤 | 解决方案 |
|---|---|---|---|
| EC800无响应 | POWERKEY未触发或电压不足 | 用万用表测EC800的VCC和GND,确认3.8V±0.2V;测POWERKEY引脚,确认有100ms低电平脉冲 | 检查bsp_ec800_power.c里TIM3配置,或改用按键手动触发 |
AT指令返回ERROR | 波特率不匹配或流控开启 | 发AT+IPR?查当前波特率;发AT&K0关流控 | 在ec800_init()开头加AT+IPR=115200和AT&K0 |
| GPS无数据 | 天线未接或NEO-6M未搜星 | 用手机APP测当前位置GPS信号强度;用示波器测NEO-6M的TXD,看是否有9600bps方波 | 换有源天线;将NEO-6M放到窗台;检查USART3初始化是否启用 |
| DHT22读数全0 | 时序不准或电源噪声 | 用示波器抓DHT22数据线波形,看80μs低电平是否达标;测VDD是否稳定3.3V | 改用SysTick微秒延时;在DHT22电源脚加10μF钽电容 |
| 数据发送失败 | TCP未连接或服务器未监听 | 发AT+QISTAT=1查状态;用telnet 120.79.123.45 8080测试端口 | 确保上位机已运行并监听8080;检查防火墙是否放行 |
5.2 我踩过的三个深坑
坑一:KEIL编译残留导致“代码没改却行为突变”
现象:改了dht22_read_data()函数,重新编译下载,但串口还是输出旧值。查了半天寄存器,最后发现Objects文件夹里有旧的.o文件没被覆盖。解决方案:工程目录下那个清除KEIL编译残余.bat不是摆设!它执行del /q .\Objects\*.o .\Objects\*.dep .\Objects\*.crf .\Objects\*.axf,每次改完大功能,双击运行它再编译。我把它绑定到KEIL的Tools → Customize Tools里,快捷键Ctrl+F7,从此告别玄学bug。
坑二:EC800在弱信号区频繁断链
现象:在地下室测试,EC800连上5分钟就掉线,AT+QISTAT=1返回TCP CLOSED。查日志发现,模块在RSRP=-110dBm时会主动断开重连。解决方案:在ec800_keep_alive()里加心跳机制——每30秒发AT+QISUPDATE=1查询连接状态,若断开则AT+QICLOSE再AT+QISTART重建。但要注意,AT+QISUPDATE返回+QISUPDATE: 1,1表示socket 1已连接,0,0表示断开。
坑三:NMEA解析错位导致经纬度颠倒
现象:串口显示[GPS:113.654321,23.123456,...],但地图上标在非洲。查$GPGGA原始帧,发现$GPGGA,062318.00,2312.3456,N,11339.2593,E,1,08,1.2,25.3,M,0.0,M,,*6A,纬度字段是2312.3456(23°12.3456′),经度是11339.2593(113°39.2593′)。很多代码直接取第3/5字段,但第3字段是纬度(含度分格式),第5字段是经度。我的gps_parse_gga()里,先atof(gga_fields[2])得2312.3456,再转为十进制度:deg = (int)(val/100); min = val - deg*100; decimal = deg + min/60.0。这样2312.3456→23.20576°,11339.2593→113.65432°,终于对上了。
5.3 实操心得:让项目从“能跑”到“稳跑”的5个细节
- 电源滤波必须做两级:EC800的VCC脚,一级用100nF陶瓷电容(高频滤波),二级用10μF钽电容(低频储能),位置紧贴模块引脚。我见过太多案例,只焊一个电容,模块在发射瞬间复位。
- GPS天线接地要单独铺铜:NEO-6M的GNSS_ANT引脚,PCB上必须挖一块矩形铜皮(≥10mm×10mm),只连到模块GND,不与其他数字地混。否则RF噪声会窜入USART3,导致NMEA帧错乱。
- DHT22数据线走线要短:从MCU的PB12到DHT22的DATA脚,PCB走线≤5cm,且避开电源线和晶振。长线会引入容性负载,让80μs高电平变宽,DHT22误判为逻辑1。
- KEIL调试时禁用优化:
Options for Target → C/C++ → Optimization Level选-O0(无优化)。否则delay_us()可能被编译器优化掉,DHT22直接罢工。 - 首次烧录后必做“三查”:查串口助手中
AT响应、查NEO-6M TXD是否有波形、查DHT22数据线在空闲态是否为高电平(用万用表测)。这三步5分钟搞定,比盲调代码高效十倍。
6. 扩展与升级建议:从毕业设计到真实产品的距离
这套方案定位是教学和原型验证,但真要走向产品化,还有几个关键跃迁点:
传感器扩展:资料包里提到“光照、气压”,其实逻辑一致。BH1750光照传感器用I2C,只需在bsp_i2c.c里初始化I2C1,调bh1750_init()和bh1750_read_lux();BMP280气压传感器也是I2C,但要注意它和DHT22共用I2C1时,地址冲突(DHT22不用I2C!这是常见误解)。BMP280地址是0x76或0x77,用GPIOB->ODR |= GPIO_Pin_6切换地址引脚即可。
低功耗改造:当前是常供电,若用电池,必须改。STM32F103支持Stop模式(电流≈20μA),但EC800休眠电流仍达1mA。方案是:MCU采集完数据,发AT+QSCLK=1让EC800进入睡眠,然后MCU进Stop模式;用RTC闹钟唤醒(每5分钟),MCU醒来先发AT+QSCLK=0唤醒EC800,再建链发送。实测用2000mAh锂电池,续航从3天提升到28天。
协议升级:透传模式适合调试,但正式产品要用CoAP或LwM2M。EC800支持AT+QHTTPGET,可把数据POST到HTTP服务器。我试过用AT+QHTTPURL=20,60设URL,AT+QHTTPPOST=32,60,10000发JSON,但成功率不如TCP透传。更稳的方案是加一颗ESP8266做协议转换——STM32只管采集,数据通过UART发给ESP8266,由它走MQTT。
固件OTA:KEIL生成的.hex文件,可通过EC800的AT+QFOTA指令远程升级。但必须预留Bootloader分区:在KEIL的Options for Target → Utilities → Settings → Flash里,把起始地址设为0x08000000(主程序),Bootloader放在0x0800F000(64KB),用AT+QFOTADL下载新固件,AT+QFOTA触发升级。这个功能我放在“进阶资料包”里,需要单独申请。
最后分享个小技巧:所有调试信息,不要用printf打到USART1(接电脑),而是用USART2(接EC800)发到云端日志服务。我在debug_log.c里写了debug_send("GPS_FIX_OK"),它会把字符串加上时间戳,通过EC800发到http://log.yourserver.com。这样现场调试时,不用带电脑,手机看网页就能查终端状态——这才是物联网该有的样子。
简介:基于STM32F103单片机,搭配EC800-4G通信模块和DHT22温湿度传感器,完整实现GPS位置信息(经纬度、海拔、UTC时间)与环境温湿度数据的本地采集、协议组包及4G网络上传。数据通过串口透传或自定义格式发送至Windows端串口调试工具或自研上位机,支持实时显示与存储。工程使用KEIL MDK开发,基于标准外设库,兼容STM32F103高密度(HD)和中密度(MD)芯片,仅需在KEIL中修改目标型号与Flash容量即可适配不同主控。所有硬件连接定义集中在main.c与usart驱动文件中,含详细中文注释,覆盖USART初始化、EC800联网AT指令交互、NMEA语句解析、DHT22时序读取、数据打包与发送全流程。提供J-Link和ST-Link两种下载支持,附带一键清理编译残留脚本及网盘资料入口。适用于物联网课程实验、毕业设计原型开发、嵌入式远程监测场景,后续扩展其他传感器(如光照、气压)可参考同系列配套驱动代码。

1297

被折叠的 条评论
为什么被折叠?



