Air780E这个开发板玩物联网的应该不陌生合宙出的Cat.1通信模组打电话、发短信、上4G网全都能干是设备联网场景里的万金油。今天我用它来演示一个很基础但又特别常用的功能——短信发送把从硬件接线到代码烧录、再到真机验证的完整流程走一遍。别小看这个功能设备告警、远程管理、业务通知基本都靠它托底。如果你是刚拿到Air780E核心板、或者从普通单片机转过来的开发者这篇文章从头到尾跟着做一遍基本上能顺畅跑通短信发送过程中踩过的坑我也会一并讲清楚。1. 项目背景与方案设计思路1.1 为什么物联网设备还需要短信告警很多人会觉得现在都是手机App、微信公众号推送的时代了谁还用短信真到实际项目里你会发现短信这玩意儿在物联网设备告警场景下几乎没有替代品。设备端出现异常断电、传感器数值越界、门禁被非法打开这些情况第一时间需要的是把事件推给运维人员。App推送依赖客户端常驻后台一旦App被系统回收或者用户换了手机告警就断了而短信直接走运营商网络号码在、信号在就能送达可靠性完全不是一个级别。另外很多设备本身没有屏幕没有按键远程控制就是靠短信指令实现的。比如说野外的一个控制器你发一条携带动作者代码的短信过去它解析之后就能执行对应的操作。这种方案对设备端来说实现成本极低不需要专门搭建服务端天然适合低成本、小体量的物联网项目。Air780E作为Cat.1通信模组内置完整的短信协议栈做这类功能可以说是拿手好戏。1.2 Air780E开发板选型通信模组型开发板好在哪市面上常见的开发板大致分成三类一类是单片机控制类比如51、STM32、ESP32核心是外设控制和逻辑处理一类是Linux应用类类似树莓派、T113、RK3588这种能跑完整系统适合做复杂的边缘计算还有一类就是Air780E所在的通信模组类它的核心优势是有完整的蜂窝网络通信能力并且把功耗、体积、成本控制得比前两类好得多。说到这要提醒一句Air780E严格意义上不是拿来跑Ubuntu、做桌面应用的那种开发板它的定位是通信单元。你想跑Linux系统、做图形界面那是树莓派和T113这类板子的事。Air780E的命门是怎么和设备通信、怎么上网、怎么发短信打电话它把这些通信链路封装成了外设接口和库函数你只需要通过串口或者LuatOS脚本去调就行。对于做物联网终端产品的工程师来说这种方式能极大缩短联网功能的开发周期这也是我选它做短信实战的原因。1.3 LuatOS脚本开发与AT指令对比实战路线怎么选Air780E有两条典型的开发路线一条是传统的AT指令方式通过串口给模组下发文本指令来控制行为另一条是官方主推的LuatOS脚本开发直接在模组内部跑Lua脚本用代码库API操作通信资源。两条路各自有对应的使用者选之前最好先想清楚自己项目的形态。AT指令的典型流程是这样每次都通过串口发文本指令ATCSMS0 # 选择短信格式 ATCMGF1 # 设置为文本模式 ATCMGS10086 # 指定接收号码 test # 输入短信内容然后CtrlZ发送这种方式适合模组外接一个单片机主控的场景主控负责业务逻辑模组当纯收发通道。缺点是每条指令都是文本交互格式、超时、状态机全部要自己管理代码量一大就很容易乱。而LuatOS开发方式直接省掉了这层交互你就在脚本里调用sms.send这样的接口参数填号码和内容返回成功失败就完事调试日志也直接在电脑上看得清清楚楚。我这篇文章选择的是LuatOS路线理由是它更接近现代嵌入式开发习惯代码逻辑一目了然针对短信这种单一功能来说开发效率高很多。如果你后面还想叠加MQTT、HTTP、TCP等网络功能LuatOS生态里都有现成库迁移成本很低。2. 硬件准备与开发环境搭建2.1 硬件清单与接线检查要用Air780E开发板跑通短信功能首先是把手头的硬件准备齐。我的清单很简单Air780E核心板一块带最小系统的那种核心板即可4G LTE天线一根IPEX接口的一张能正常收发短信的SIM卡建议先实名认证好USB转Type-C数据线一根尽量用质量好一点的数据线别用只能充电的那种接线这块其实没太多复杂地方核心板上通常已经把SIM卡槽、天线座、USB口全部引出来了。需要注意的是SIM卡的物理尺寸必须跟板载卡槽匹配Air780E核心板一般用的是Micro或Nano卡槽如果你手头只有老式的标准大卡需要使用卡套转接反过来如果你用Nano卡但卡槽是Micro的就得用卡托。我试过好多次拿到板子插上卡没反应最后发现是卡尺寸不对没接触到位这种低级问题最容易浪费半天时间。天线这块更值得留心。LTE天线接不接、接得牢不牢直接影响网络注册和短信发送成功率。插天线的时候注意IPEX接头要对准卡扣插到底之后稍微旋转一下听咔哒一声才算到位。如果你在室内测试尽量靠近窗户信号会稳定很多。电源方面直接用USB口供电就行但如果你额外挂了传感器之类的负载建议换用5V/2A以上的适配器供电否则可能会出现模组启动时电流过大导致反复重启的情况。模组拨号瞬间的峰值电流不小这点在后面的排查部分我会再细说。2.2 LuaTools安装及USB驱动兼容处理软件环境这边需要用合宙官方的LuaTools工具它是集烧录、调试日志、文件管理一体化的上位机。到合宙官网下载对应版本之后解压即可使用不需要安装步骤绿色软件。不过有个环节容易卡住就是USB驱动。Air780E核心板通过USB连到电脑后系统会识别出一个或者多个串口设备。Windows 10、Windows 11下大部分情况是自动装好驱动的但也有相当一部分机器因为系统安全策略的问题设备管理器里会出现带黄色感叹号的未知设备。遇到这种情况直接去设备管理器里手动更新驱动路径指向LuaTools目录下自带的driver文件夹装完后会看到两个虚拟串口。驱动签名校验如果一直弹窗不给过可以先临时禁用驱动签名强制重启一次系统再装。装好之后打开LuaTools界面左边可以看到当前电脑连接的设备选择Air780E对应的串口下一步就是烧录和日志操作了。这里顺手建议初学者先把串口波特率设置成工具的默认配置不要自己改免得对不上导致日志无法打印。2.3 创建LuatOS工程与固件选择LuaTools里边的新建工程流程比较简单选择芯片型号Air780E工具会把对应的工程模板拉起来。工程里最核心的就是demo_main.lua这是整个项目的入口脚本LuatOS启动后会执行这个文件。固件选择上有一点要注意不是所有官方固件都包含短信功能所需的库。Air780E在LuatOS生态里属于标准Cat.1模组官方发布的正式版本固件一般默认就带sms、mobile、sim这些核心库。但如果你用了很早期的开发版固件或者为了省内存裁剪成精简版的固件就可能没有sms模块的API。稳妥的做法是在官方文档中心对应的Air780E固件说明页里确认一下当前固件版本是否包含短信相关功能。实在不确定的话多看两行说明比烧进去之后才发现少API再返工要省事得多。工程目录下一般还会有lib、model这些文件夹刚上手先不用研究每个文件的含义保持默认结构就行。重点是把demo_main.lua的内容替换成我们需要的短信发送代码然后保存。这个流程初次可能有点懵但整体半小时内就能理顺。3. 短信发送完整代码实现与烧录运行3.1 demo_main.lua完整代码下面这段代码是我在实际项目中整理出来的一个可直接运行的短信发送示例加入了SIM卡检测、网络注册等待、以及最大三次重试的逻辑比单纯糊一个发送调用要健壮得多。复制到你的demo_main.lua里替换原内容即可-- demo_main.lua -- Air780E 短信发送功能示例含SIM卡检测、网络等待、失败重试 local sms require sms local sim require sim local mobile require mobile local sys require sys log.info(main, Air780E 短信发送Demo启动) sys.taskInit(function() -- 第一步等待SIM卡就绪超时30秒 local simReady false for i 1, 30 do if sim.isReady() then simReady true break end sys.wait(1000) end if not simReady then log.error(main, SIM卡30秒内未就绪请检查SIM卡是否插好) return end log.info(main, SIM卡就绪ICCID: .. (sim.getIccid() or unknown)) -- 第二步等待网络注册成功超时30秒 local netReady false for i 1, 30 do if mobile.isReady() then netReady true break end log.info(main, 等待网络注册中已等待 .. i .. 秒) sys.wait(1000) end if not netReady then log.error(main, 网络注册超时请检查天线和SIM卡状态) return end log.info(main, 网络注册成功当前信号值: .. mobile.getSignal()) -- 第三步发送短信最多重试3次 local phone 10086 local content Air780E短信功能测试成功 for retry 1, 3 do local ok, err sms.send(phone, content, 10000) if ok then log.info(main, 短信发送成功第 .. retry .. 次尝试) break else log.warn(main, 短信发送失败错误码: .. tostring(err) .. 准备重试) sys.wait(2000) end if retry 3 then log.error(main, 短信发送最终失败) end end end) sys.run()代码里的目标号码我填的是10086也就是运营商客服号。为什么拿它测试呢因为它是免费号码短信发过去不会产生费用而且一定会返回一条自动回复短信能顺便验证接收通道是否正常。等你确认全流程没问题再换成真实的业务号码就好。3.2 核心代码逐段拆解与为什么这么做这段代码看起来不长但每一部分都有它的用意不能删。先说sys.taskInit和sys.run这是LuatOS的任务调度机制。sys.taskInit把一个函数包装成独立的任务函数内部可以使用sys.wait做延时挂起不会阻塞其他任务的执行。sys.run必须是整个脚本的最后一行它启动了整个调度器没有它你写的任务不会被执行这也是新手经常会犯的错。再说SIM卡检测的这部分循环逻辑。模组上电之后SIM卡不是瞬间就能识别的少则需要一两秒多则需要好几秒尤其是一些旧卡的识别速度更慢。直接跳过这一步去查网络状态很可能会得出网络未注册的错误结论。我见过很多同学一上来就发短信结果返回失败然后就开始怀疑模组坏了其实只是没等SIM卡稳定。循环30秒这个设计足够覆盖绝大多数场景如果30秒都读不到SIM卡基本可以确定是硬件层面出问题了。第二段等待网络注册的循环和上面的逻辑是同一个道理。Cat.1模组要完成网络附着、PDN建立等流程需要一个过程。前面那个判断管的是卡能不能读到这段判断管的是模组能不能注册上运营商网络。这两个状态是递进关系不能把顺序写反。信号值mobile.getSignal()返回的是0到31之间的数字31是最好的情况0表示完全没信号。实测下来信号值只要不低于10短信功能基本都能正常工作低于这个值就要考虑换位置或者检查天线了。最关键的sms.send函数它其实是一个同步阻塞接口调用后会等待短信发送结果返回第三参数10000表示最长等待10秒。为什么要加超时参数因为短信发送涉及模组和运营商网络之间的多次交互正常情况下几秒内能完成但在信号弱或者网络拥塞的时候可能会拖得很久。如果不设置超时这个函数可能会长时间阻塞把整个任务卡住。10秒是比较合理的经验值既不会频繁误判失败也不至于因为极端情况卡死任务。3.3 烧录运行与日志观察代码写完之后烧录流程在LuaTools上走一遍就成。打开LuaTools选择好Air780E对应的串口设备点击烧录固件按钮确认固件和脚本两个部分都被选中然后点开始。此时工具会提示你给模组上电复位Air780E核心板一般插拔一次USB就能进入可以烧录的状态或者按板子上的复位键也行。烧录过程中尽量不要拔线等进度条走完出现成功提示再操作。烧录完成后工具会自动重启模组并开始抓日志。在日志窗口你会看到类似下面这样的输出[time] main/Air780E 短信发送Demo启动 [time] main/等待网络注册中已等待1秒 [time] main/等待网络注册中已等待2秒 ... [time] main/网络注册成功当前信号值: 18 [time] main/短信发送成功第1次尝试看到短信发送成功这行日志说明整个链路已经通了。正常情况下用不了几秒钟测试号码的手机会收到那条短信目标号码如果是10086会收到运营商的自动回复这正好能验证双向链路是否都正常。4. 真机实测与常见问题排查4.1 一次短信发送的完整日志实录为了让你对整个过程有个直观感觉我把一次实际测试的日志梳理出来。这里省略了具体的时间戳但保留了关键信息main/Air780E 短信发送Demo启动 main/SIM卡就绪ICCID: 898601xxxxxxxxxxxx main/等待网络注册中已等待1秒 main/等待网络注册中已等待2秒 main/网络注册成功当前信号值: 22 main/短信发送成功第1次尝试整个过程从启动到发送成功大概4秒上下网络注册只花了2秒信号值22属于良好水平。这里信号值22不是越高越好到离谱的程度城市室内环境一般就是这个范围超过25说明你在窗边或者基站附近低于10就需要排查了。如果你的日志卡在等待网络注册循环里出不来重点检查天线和SIM卡别急着在代码层面折腾。另外注意日志里SIM卡打印出来的ICCID是一个20位的数字串这个信息很有用。它能帮你确认模组读到的确实是你要测试的那张卡尤其是当你有好几张卡分别属于不同运营商的时候通过ICCID判断当前插的是哪张可以避免以为是移动卡实际插的是联通卡这种乌龙。4.2 高频问题排查速查表实际开发中大家反馈最多的几个问题我整理成一张速查表问题现象可能原因排查与解决方向日志里SIM卡30秒未就绪卡没插到位、卡尺寸不匹配、触点氧化重新插卡用酒精棉擦拭卡背面触点检查卡槽卡扣是否压紧网络注册超时天线没接好、周围信号弱、SIM卡未实名检查天线接口移至窗边测试确认SIM卡在手机上能正常注册网络短信发送失败返回错误码号码格式错误、运营商拦截、SIM卡短信服务未开通核对号码是否为11位手机号或完整区号座机号换普通手机号测试日志一直打印等待注册但SIM卡已读取模组没有完成PDN建立部分运营商需要手动配置APN检查此卡在手机上的APN配置必要时在代码中设置接入点发送显示成功但收不到短信被运营商拦截、接收号码设置了短信过滤先给自己另一张SIM卡发排除接收端问题中文短信内容出现乱码脚本文件编码不是UTF-8确认编辑器保存为UTF-8无BOM格式重新保存再烧录模组上电反复重启USB供电不足、外设电流过大换5V/2A适配器供电临时断开外设排查干扰这张表里最容易被忽略的是APN问题。大部分物联网卡和普通SIM卡在默认情况下能自动获取APN但有一部分定向流量卡、企业内部物联网卡必须手动指定APN才能完成网络注册或者发送短信。解决办法也很直接在LuatOS里用mobile.configApn配置当前SIM卡对应的APN参数或者直接打运营商客服问那张卡的APN名称是什么。4.3 几条值得记住的实操经验最后分享几个我自己在多次测试中沉淀下来的经验都属于文档里不会写得很细、但实战中非常救命的内容。第一天线永远放在所有排查项的第一位。我曾经调试一块Air780E开发板网络注册一直不稳定日志时好时坏整整查了三天代码最后发现是IPEX天线接头里有一根针脚歪了导致接触不良。硬件层面的小毛刺很难靠日志看出来一旦遇到反复无常的网络问题先去摸天线再去怀疑代码。第二测试短信功能时选一张跨网或者异地的号码效果更明显。比如说你用的是移动的网络发送到联通或者电信的号码能直观检验运营商之间的链路是否正常。如果只是本网号码互发有时候网络侧会走内部通道掩盖了一些延迟或编码问题等实际部署到用户那边再暴露就晚了。第三mobile.isReady()在部分固件版本里可能不叫这个名字。不同时期的LuatOS固件对网络注册状态的判断函数命名有差异早期版本用net.isReady()新版本推荐用mobile.isReady()。如果你在编译或者运行时遇到报错说函数不存在去当前固件对应的SDK文档里搜一下isReady找到你那个版本对应的API名字替换就行。这不算踩坑属于生态迭代的正常节奏心态放平就好。我个人在实际操作中的一个感受是短信功能虽然简单但它能一次性把SIM卡识别、网络注册、运营商链路、编码格式这几个关键环节全部串起来。跑通它相当于给Air780E这块板子做了一次全面的自检后面你再去接MQTT云平台、HTTP API很多网络链路的原理都是相通的。顺手也可以把接收短信的解析逻辑加上做一个收到特定指令就执行动作的小功能比如远程重启设备、远程修改上报周期这在无人值守的现场非常有实用价值。Air780E能折腾的方向还有很多短信只是一个不错的起点。