基于STM32的智能手表:GPS定位与GSM短信上报实战解析
简介:本资源是一套完整的基于STM32的嵌入式智能手表开发方案,面向电子类专业本科生、嵌入式初学者及课程设计/毕业设计实践者,解决GPS定位采集、GSM远程通信与人机交互集成等典型单片机综合应用问题。压缩包共233个文件,涵盖36个C源码与38个头文件(含LCD、GPS、GSM驱动及主控逻辑)、21张电路图与系统框图JPG、20余份Keil工程文件(.uvproj/.axf/.hex等),以及开题报告、答辩技巧、参考论文、芯片手册、器件清单等13份DOC类文档和8份PDF技术资料;另有5段MP4演示视频直观展示短信上报与手电筒功能。资源包大小77.97MB,目录结构按硬件模块与文档类型分层组织,便于快速定位核心代码与原理图。目前已有1768人学习下载,提供从硬件搭建、程序烧录、AT指令调试到功能验证的全流程支撑,特别适合开展ARM嵌入式系统课程实践与创新项目开发。 最近在整理嵌入式项目资料时,翻到一个挺有代表性的设计:基于STM32单片机的智能手表,核心功能就两个——GPS定位和GSM短信上报。用大白话说,就是让手表里集成一块GPS模块负责拿当前经纬度,单片机作为大脑把坐标解析出来,再通过GSM模块以短信形式发送到预设手机号。这其实是嵌入式入门里非常经典的一条技术链路,把GPS、GSM、单片机三个东西串在一起,能一次性练到串口通信、协议解析、AT指令控制、电源管理这些底层基本功。
这套方案的落地场景很直接:老人小孩防走失、户外徒步应急、个人物品防丢,甚至骑行记录。和手机App上报坐标不同,短信上报不依赖Wi-Fi、不依赖网络连接、也不需要安装软件,只要附近有移动通信信号,对方手机就能收到一条带坐标的短信。对于做毕业设计、电子竞赛或者想系统入门物联网开发的朋友来说,这个项目是非常合适的练手对象。这篇文章我就把这个项目从硬件选型、电路设计、NMEA语句解析、AT指令发短信,到实际调试踩坑的完整过程拆开讲一遍,希望能给正在做类似东西的朋友一些参考。
1. 项目整体设计与方案选型
1.1 这套方案到底解决什么问题
先说应用场景。智能手表如果只做显示时间,那和普通电子表没有区别,真正有价值的是“定位”和“报警”。把GPS模块塞进手表,设备就能知道自己在哪里;再把GSM模块加进来,设备就能把位置信息主动发出去。这就解决了两个核心问题:一是定位,二是远程通知。
举个最简单例子,家里老人出门遛弯,戴着手表,如果家人想知道老人当前位置,可以回拨或发送指令,手表自动把坐标短信发给家人;或者老人遇到紧急情况按一下按键,手表立刻把定位短信发送给预设号码。整个过程不需要老人操作复杂界面,一按就完事。这个场景下,短信相比网络上报有两个不可替代的优势:不受手机App限制,任何手机都能收;不依赖目标设备联网,GSM信号覆盖范围远大于Wi-Fi。
从学习角度看,这个项目的难点不在单一模块,而在于把多个模块组合成系统。GPS模块输出一串字符流,单片机能听懂并提取关键信息;GSM模块收到指令后能正确拨号发短信;中间还要保证电源稳定、串口不丢数据。任何一个环节出错,整个链路就不通。这种“模块协作”的经验,是单纯跑一个LED灯或者做一个计数器学不到的。
1.2 三个核心器件的选型逻辑
主控选STM32F103C8T6,这个芯片在嵌入式圈子里几乎是“万金油”般的存在。72MHz主频、64KB Flash、20KB RAM,双串口、I2C、SPI、ADC全都有,LQFP48封装手工焊接也没问题,价格还便宜。对比一下,如果用51单片机来做,两个串口要模拟扩展,解析NMEA语句的运算量也偏紧,不是说不能做,而是开发效率明显低。如果选ESP32,虽然性能更强还带Wi-Fi和蓝牙,但纯做GSM短信上报其实用不到网络功能,功耗和成本反而更高。
GPS模块我选的是NEO-6M方案的模块,市面上非常多,串口输出NMEA 0183格式数据,波特率默认9600,定位精度一般在2.5米左右。这类模块自带陶瓷天线,有些还支持外接有源天线,比较适合手表这种小体积设备。也有用ATK-SIM28的,本质上是同一类东西,选哪个看手里有什么。
GSM模块选了SIM800C。这颗模块支持GSM/GPRS四频段,短信、电话、TCP/IP都有,最关键的是AT指令体系极其成熟,网上资料一抓一大把。类似的还有SIM900A、A6、A7等,指令基本兼容。SIM800C尺寸小巧,2.8V逻辑电平,适合电池供电的可穿戴设备。有一点要提前说清楚:现在运营商对2G网络的策略处处有别,如果你所在区域GSM信号覆盖不佳或者退网,可以把模块替换成支持短信功能的4G Cat.1模块(比如Air724UG),AT指令体系相近,软件改动不大。
1.3 数据链路与模块划分
整个系统的数据流是这样的:GPS天线接收卫星信号,NEO-6M模块解析后通过串口输出NMEA语句,STM32的UART1接收这些字符流,在内存中提取出经纬度、UTC时间、卫星数量;用户按下上报按键后,STM32把经纬度拼成一条短信内容,通过UART2向SIM800C发送AT指令,SIM800C把短信发到预设手机号;同时,0.96寸OLED屏实时显示定位状态和坐标信息,蜂鸣器或LED用于上报成功提示。
模块划分上,建议把系统拆成四个独立单元:定位单元(GPS模块及天线)、通信单元(GSM模块及SIM卡座)、主控与人机交互单元(STM32、OLED、按键、蜂鸣器)、电源管理单元(锂电池、充电芯片、LDO稳压)。为什么要拆分?因为调试时每个单元都可以单独验证。GPS单元用串口助手看NMEA输出,通信单元直接用USB转TTL接SIM800C发AT指令,单独都通了再组合,问题定位会快得多。
2. 硬件电路设计要点
2.1 关键器件清单
先列一个完整的物料清单,方便对照准备:
| 功能 | 器件型号 | 作用 | 备注 |
|---|---|---|---|
| 主控 | STM32F103C8T6 | 数据解析、逻辑控制 | 双串口必备 |
| GPS模块 | NEO-6M / ATK-SIM28 | 获取经纬度 | UART输出NMEA |
| GSM模块 | SIM800C | 短信收发 | 支持AT指令 |
| 显示屏 | 0.96寸OLED SSD1306 | 显示定位信息 | I2C接口 |
| 锂电池充电 | TP4056模块 | 给电池充电 | MicroUSB输入 |
| LDO稳压 | AMS1117-3.3 | 3.7V锂电池转3.3V | 给MCU/GPS/OLED |
| 电池 | 聚合物锂电池 3.7V 1000mAh | 系统供电 | 容量越大续航越长 |
| 按键 | 轻触开关 | 触发短信上报 | 两个以上更好 |
| 蜂鸣器 | 有源蜂鸣器 | 状态提示 | 低电平触发 |
这里多说一句,STM32的最小系统板(蓝板)可以直接用,上面自带LDO和USB转串口,初版验证完全够。但如果你想做真正的手表PCB,建议自己画板,把最小系统、GPS、GSM、OLED接口集成到一块,这样体积能小很多。
2.2 供电系统设计:最常见的失败点
这个项目里90%的“模块不工作”问题,最终都能追溯到供电。尤其GSM模块,发送短信瞬间的电流峰值能到2A,这是整个系统里最需要注意的地方。如果天真地认为3.3V LDO能同时喂饱STM32、GPS和GSM,那短信一发送,LDO输出电压瞬间跌落,GSM模块直接掉电重启,甚至STM32也会复位。
正确的供电方案是分区供电:锂电池直接接SIM800C的VBAT引脚,因为SIM800C的工作电压范围是3.4V到4.4V,锂电池3.7V标称值刚好落在区间内。在VBAT引脚旁并联一个大容量电容,比如1000uF铝电解电容加100nF陶瓷电容,用于吸收发射瞬间的电流尖峰。STM32、GPS、OLED则统一用AMS1117-3.3从锂电池降压得到3.3V,与GSM的电源完全分开。这样GSM那边电压怎么波动,都不会影响单片机。
实际验证时,用万用表测VBAT发送瞬间的电压,如果压降超过0.3V,说明储能电容不够,加大到2200uF再试。还有一个细节:GSM模块的电源线要尽量短且粗,如果飞线连接,至少用AWG24以上线径,细线电阻大,大电流下压降很可观。
2.3 天线、电平与接口定义
天线布局是硬件上另一个容易忽视的地方。GPS信号本身非常弱,天线必须朝向天空方向,周围尽量不要被金属遮挡;手表形态下,GPS天线最好放在表盘最上层,PCB上要留出净空区,不要在正上方铺铜或者放排针。GSM天线则要远离GPS天线,至少隔开3cm以上,否则GSM发射时的射频信号会直接干扰GPS接收,导致搜星困难。
电平匹配上,SIM800C的UART高电平是2.8V,STM32的是3.3V,实际上STM32识别2.8V为高电平没有问题,SIM800C也能识别3.3V高电平输入,但稳妥起见,最好在STM32到SIM800C的TX线上串一个1K电阻分压,或者直接用模块板载的电平转换电路。GPS模块输出是3.3V电平,和STM32直接对接没问题。
串口和引脚分配建议这样安排:UART1(PA9/PA10)接GPS模块,因为GPS数据是持续输出的,独立串口方便管理;UART2(PA2/PA3)接SIM800C,用于发送AT指令和接收响应;I2C(PB6/PB7)接OLED;PB0接上报按键,PB1接屏幕开关;PC13接蜂鸣器或LED。
3. 软件实现与关键代码
3.1 开发环境与串口分配
软件部分我推荐用STM32CubeMX生成初始化代码,配合HAL库,Keil MDK编译。有些朋友习惯用标准库,也行,这项目逻辑不复杂,核心是串口数据处理和AT指令状态机。
CubeMX里开启USART1和USART2,均配置为异步模式,波特率:GPS模块设为9600(NEO-6M默认),GSM模块设为9600(SIM800C出厂默认可能不同,用AT+IPR?查询确认)。两个串口都开启中断接收,收到的字节存入各自的环形缓冲区。在HAL库中,串口接收完成回调函数里做一件事:把字节写入缓冲区,然后重新启动下一次接收。注意不要在中断回调里做耗时的字符串解析,否则会丢数据。
GPS模块上电后每秒输出一串语句,用环形缓冲区缓存,主循环里定期检查缓冲区是否有完整的$GPGGA帧;GSM模块响应是事件式的,发一条AT指令等一个回应,适合用简单的状态机或者超时等待。初始化顺序是:系统时钟、GPIO、串口、OLED,然后延时2秒等待GSM模块开机,再发送“AT”同步指令,最后才进入主循环等待GPS数据。
3.2 GPS NMEA协议解析
NMEA 0183是GPS模块最通用的输出协议,里面的$GPGGA语句包含了定位所需的核心信息。一条典型的$GPGGA语句长这样:
$GPGGA,092750.000,5321.6802,N,00630.3372,W,1,8,1.03,61.7,M,55.2,M,,*76字段按逗号分隔,关键信息:字段1是UTC时间(时分秒),字段2和3是纬度(ddmm.mmmm格式,N/S),字段4和5是经度(dddmm.mmmm格式,E/W),字段6是定位状态(0=未定位,1=单点定位,2=差分定位),字段7是卫星数量。只有字段6是1或2的时候,坐标才是有效的,否则直接丢弃。
解析代码可以这样写:
char *p = strstr(gps_buf, "$GPGGA"); if (p != NULL) { char utc_time[10] = {0}; char lat_str[12] = {0}, lon_str[12] = {0}; char lat_dir = 0, lon_dir = 0; int sats = 0, fix_status = 0; sscanf(p, "$GPGGA,%[^,],%[^,],%c,%[^,],%c,%d,%d", utc_time, lat_str, &lat_dir, lon_str, &lon_dir, &fix_status, &sats); if (fix_status > 0) { // 转换 ddmm.mmmm -> dd.dddddd float lat = convert_to_degrees(atof(lat_str)); float lon = convert_to_degrees(atof(lon_str)); if (lat_dir == 'S') lat = -lat; if (lon_dir == 'W') lon = -lon; // 保存全局变量,供短信上报使用 } }这里有个新手必踩的坑:GPS模块输出的经纬度是“度分”格式,比如5321.6802,意思是53度21.6802分,必须先转成十进制小数度才能直接给地图链接用。转换公式很简单:十进制度 = 整数部分 + (小数部分 / 60)。上面的convert_to_degrees函数就是在做这件事。
我在调试时习惯在OLED上同时显示原始语句长度和解析出的经纬度,如果解析成功立刻能看到数值变化,比憋在串口里看日志直观很多。
3.3 GSM短信上报AT指令链路
GSM模块控制是另一套逻辑,完全基于AT指令。SIM800C上电后先要等它注册到网络,时间不一定,几秒到几十秒都可能。通过AT+CREG?查询注册状态,返回+CREG: 0,1表示已注册本地网络,0,5表示已漫游。不确认注册成功就发短信,基本都会返回ERROR。
短信发送的标准流程分三步:
- AT+CMGF=1,设置短信为文本模式(Text Mode)。
- AT+CMGS="接收方手机号",模块返回“>”提示符。
- 发送短信内容,末尾追加十六进制0x1A(对应Ctrl+Z),表示输入结束。
代码实现可以封装成一个函数:
void send_sms(const char *phone, const char *msg) { char cmd[64]; sprintf(cmd, "AT+CMGS=\"%s\"\r\n", phone); uart2_send_string(cmd); HAL_Delay(300); // 等待模块返回'>'提示符 uart2_send_string(msg); HAL_Delay(100); uint8_t end_mark = 0x1A; uart2_send_byte(&end_mark); }真实项目中这个函数不能这么粗糙,必须在发送后检查模块是否返回“+CMGS: xxx”的OK响应。比较稳妥的做法是发送完0x1A后,等待串口返回OK或者ERROR,用一个超时循环 + 标志位判断。如果返回ERROR,重试两三次,还不行就提示用户检查信号或SIM卡。
短信内容拼接是最后一步,建议把时间、经纬度、卫星数和地图链接都放进去,收信人拿到短信不用猜就知道是设备发的位置。链接格式最通用的是Google Maps:
http://maps.google.com/?q=纬度,经度对方手机收到短信后直接点链接,浏览器打开地图就能看到位置,非常方便。有人问中文短信怎么发,文本模式对中文支持不好,要么用PDU模式,要么短信内容只用英文和数字,后者省事得多。
4. 调试实录:我踩过的坑
4.1 GPS搜星慢或者搜不到星
这个问题在第一次上电调试时几乎必现。GPS冷启动后第一次定位需要比较长时间,视环境而定,开阔地带2到5分钟,室内可能永远定不到。我第一次在阳台测试,连续等了6分钟才有坐标,当时差点以为模块坏了。后来总结的经验是:拿到模块先别接单片机,用USB转TTL直接连电脑,串口助手看NMEA输出,这样能最快确认模块本身没问题。
如果室外等了很久还是没有定位成功,检查这几项:
- 天线是否朝天,周围有没有金属遮挡物。
- 串口波特率是不是9600,有些模块默认115200。
- 是否有源天线供电问题,如果模块有源天线接口,需要额外提供3.3V馈电。
- 查看$GPGSV语句中可见卫星数量,如果为0表示天线没搜到星,考虑换位置。
还有一个容易犯的错:解析时没检查定位状态位。模块即使没定位成功,也会输出$GPGGA,只是状态位为0。如果不加判断就把无效坐标发出去,收信人收到的是类似“0.000000,0.000000”这种废数据,体验很差。
4.2 GSM模块频繁重启和短信发送失败
GSM模块重启是供电不足的典型表现。现象是给模块上电后,还没等发AT指令,模块就反复开关机,或者一发送短信就重启。这时候别急着改代码,先检查VBAT电压。用示波器或者万用表测发送瞬间的电压,如果压降超过0.3V,十有八九是电源问题。我调试时刚开始用一根长长杜邦线从AMS1117拉电给SIM800C,信号一发射电压跌到2.8V,模块直接掉电,后来改成电池直供并加上2200uF电容,问题立刻消失。
短信发送失败还有一个隐蔽原因:模块开机后网络没注册好。SIM800C上电后,最好轮询AT+CREG?直到返回已注册,再执行后面的短信流程。如果上来就发AT+CMGS,模块返回ERROR,很多人误以为是SIM卡坏了,其实只是网络还没就绪。另外AT+CSQ可以查信号强度,返回值范围0到31,低于10说明信号很弱,短信大概率发不出去。
SIM卡接触不良也是常见坑。模块上的SIM卡座是推拉式的,如果卡没插到位,返回的CME ERROR会是“SIM not inserted”。调试时可以在卡座旁边加两颗固定螺丝,或者用绝缘胶带按压住SIM卡,减少虚接概率。
4.3 串口乱码、程序卡死
串口乱码八成是波特率不匹配。GPS模块虽然默认9600,但有些二手模块的被改过配置,先串口助手扫一遍波特率确认。另外注意模块和单片机的共地问题,两个设备之间除了TX/RX,还要把GND连起来,否则电平参考不一致,数据极容易错乱。
程序卡死在调试过程中也很折磨人。最常见原因是在串口中断里做了耗时操作,比如HAL_UART_Receive_IT的回调里直接调用printf函数,或者进行字符串解析,这些处理时间太长,导致其他中断或数据接收被阻塞。我的建议是中断里只做数据缓冲区的写入,解析全部放到主循环里处理。环形缓冲区的大小也要留意,GPS一帧最长约100字节,缓冲区至少给256字节,防止接收溢出导致数据被覆盖。
还有一点,程序里使用HAL_Delay时要小心,如果GSM模块响应很慢,而你在某个状态里死等,不设置超时,整个系统就卡死了。所有AT指令收发环节都建议设计超时跳出的逻辑。
5. 手表化改造与使用建议
5.1 OLED显示与人机交互
手表形态下,OLED不仅是显示设备,还是交互反馈窗口。我的方案里OLED一屏分三行显示:第一行定位状态和卫星数,第二行经纬度,第三行北京时间。GPS输出的UTC时间比北京时间慢8小时,显示时记得转换。
按键交互可以设计成两种模式:短按一次,屏幕点亮并显示当前定位信息,不发送短信;长按3秒,触发短信上报并震动或蜂鸣提示。这样既能避免误触频繁发短信,又能让用户随时查看状态。人机交互的细节往往决定一个作品的使用体验,纯功能堆叠没有任何输出反馈的设备,用起来非常困惑。
功耗方面,手表最耗电的是屏幕和GSM模块。OLED可以通过命令控制全部熄灭,平时默认灭屏,只有按键按下才点亮,亮几秒后自动关。GPS模块也不是开机就一直供电,可以设计一个MOS管控制其电源,需要定位时才上电,定位成功后就关掉。GSM模块在非上报时段可以进入睡眠模式(AT+CSCLK=1),能明显降低待机电流。实测1000mAh电池,如果每天上报几次,待机两三天问题不大。
5.2 合法使用场景与稳定运行建议
这个项目能做的事情很多,但使用场景必须合法合规,只能用于自己拥有或得到授权的设备,比如给家里老人小孩做的防走失终端、自己的户外应急定位器、车载防丢追踪器等。任何未经他人同意、偷偷跟踪定位的行为都是违法的,这一点必须遵守。
稳定性方面,长期运行的设备要加看门狗。GSM模块偶尔会死机,AT指令无响应,此时让STM32给GSM模块重新上电或者发送复位指令,比手动断电方便得多。软件上可以每30秒轮询一次GPS数据,超过一定时间没有有效定位,就提示用户检查天线。短信上报也要做防抖,连续按键的时间间隔至少10秒,避免用户连按导致发送多条重复短信,浪费话费。
最后建议把原理图和PCB工程文件保留好。这个项目的硬件电路并不复杂,但它是理解“传感器 + 主控 + 无线通信”这套架构的绝佳样本。后续想扩展什么都容易,加心率传感器做健康监测、加震动马达做消息提醒、加蜂鸣器做SOS报警,各个模块的接口都预留出来,扩展空间非常大。
整个项目做下来,我最大的体会是:无论方案看着多简单,实际调试时总会遇到文档里没写的问题。GPS冷启动那几分钟的焦躁、GSM模块第一次发短信时因为没等网络注册而返回ERROR的无奈,这些坑踩过一遍才能真正记住。这个项目整体成本不超过100块,但把串口通信、协议解析、电源设计、人机交互完整地串了一遍。
如果你正在做类似的设备,我给一个最实际的建议:先模块级调试,再整机联调。GPS单独测通、GSM单独测通、OLED单独点亮,然后再把它们组合起来。千万别一上来就把所有模块焊到一块板子上,出了问题都不知道该查谁。每一步都验证完再往前走,这个项目大概率能在两天内跑通。
本文还有配套的精品资源,点击获取
