
简介这是一套面向物联网竞赛开发者的LoRa环境监测系统完整嵌入式工程基于STM32 ARM Cortex-M系列单片机实现低功耗远距离环境数据采集与人机交互。系统可实时读取温湿度DHT22、光照强度光敏传感器支持光照阈值触发LED1、按键控制LED2闪烁/关闭并通过OLED屏直观显示参数覆盖LoRa通信、传感器驱动、外设中断、HAL库应用等核心嵌入式开发技能。资源包共650个文件以237个.h头文件和181个.c源码为主辅以.o目标文件、.d依赖文件、.axf/.hex可执行镜像及Keil工程uvprojx/uvoptx完整呈现从底层驱动如stm32l0xx_hal_i2c.c、LoRaMac.c到应用逻辑的全栈代码结构。压缩包大小为18.05MB目录组织规范便于模块化学习与调试。目前已有1278人学习下载适合嵌入式初学者进阶实践或竞赛团队快速复现赛题原型。1. LoRa环境监测系统【物联网竞赛开发】为什么它成了高校IoT赛道的“稳进决赛圈”方案去年带某高校学生备赛全国大学生物联网设计竞赛时我见过太多团队在选型阶段就卡死WiFi模块功耗压不下来NB-IoT又得等运营商入网白名单Zigbee组网调试三天没通一个节点……直到他们把LoRa模块焊上温湿度PM2.5传感器用一块3.7V锂电池撑了47天——不是实验室理想值是真实部署在教学楼顶通风口的连续记录。LoRa环境监测系统【物联网竞赛开发】本质是一套以低功耗广域通信为骨架、多源环境参数采集为血肉、嵌入式边缘逻辑为神经的轻量级物联网闭环。它不追求吞吐量但死磕链路预算不堆算力但严控休眠电流不依赖云平台绑定却能通过标准AT指令对接主流IoT平台。适合参赛者快速验证“感知-传输-呈现”全链路也适合课程设计中拆解无线通信、传感器驱动、低功耗管理三大硬核模块。如果你正被“电池续航短”“信号穿墙差”“调试没日志”反复暴击这个标题背后的技术路径就是你该抄的第一份作业。2. 从芯片选型到节点组网LoRa环境监测硬件栈的三层取舍逻辑LoRa环境监测系统的硬件落地从来不是“买个模块焊上去”那么简单。它由传感层、通信层、供电层构成三角稳定结构每一层的选型都直指竞赛评审的隐性扣分点功耗数据是否真实、通信距离是否可复现、故障是否可追溯。我带过的12支队伍里8支在初赛就被打回重做问题全出在这三层的“想当然”。2.1 传感层别迷信“集成度高”先看ADC位数和校准接口环境参数的真实性源头在传感器本身。竞赛常见误区是直接选用带I²C接口的“三合一”模块如SHT30PMS5003组合板看似省事实则埋雷PMS5003的串口协议无校验SHT30的I²C地址固定无法多节点共存更致命的是——它们共用同一组电源滤波电容粉尘传感器启动瞬间的电流尖峰会直接干扰温湿度ADC采样。提示竞赛评审现场常要求现场更换传感器并验证数据一致性必须预留校准通道。推荐组合与接线逻辑温湿度Sensirion SHT45非SHT30I²C地址可编程0x44/0x45自带加热自检功能-40~125℃全量程精度±0.2℃颗粒物Plantower PMS7003非PMS5003UART接口带硬件流控RTS/CTS引脚必须接支持主动查询模式避免串口冲突气体BME680非CCS811集成气压/湿度/温度/气体四合一关键是有独立的I²C地址0x76且支持软复位// PMS7003主动查询模式初始化关键禁用自动上报改为主动轮询 void pms7003_init() { // 硬件流控启用RTS引脚接MCU GPIO拉低表示接收缓冲区满 HAL_GPIO_WritePin(PMS_RTS_GPIO_Port, PMS_RTS_Pin, GPIO_PIN_SET); // 发送指令0x42 0x4D 0xE1 0x00 0x00 0x00 0x01 → 进入主动模式 uint8_t cmd[] {0x42, 0x4D, 0xE1, 0x00, 0x00, 0x00, 0x01}; HAL_UART_Transmit(huart2, cmd, 7, 100); }逻辑说明PMS7003默认自动上报每秒1次但LoRa节点唤醒周期常为10分钟若不切主动模式99%的数据包会在MCU休眠时丢失。代码中RTS引脚控制是防丢帧的物理层保险。参数说明HAL_UART_Transmit超时设为100ms而非1000ms因PMS7003响应极快5ms过长超时会导致后续指令阻塞。2.2 通信层SX1278 vs SX1262看透竞赛场景的链路预算缺口LoRa芯片选型是功耗与距离的终极博弈。SX1278Semtech经典款和SX1262新一代在竞赛中常被混用但二者差异直击评分要害参数SX1278如LLCC68SX1262如ASR6502竞赛影响接收灵敏度-137dBmSF12,125kHz-148dBmSF12,125kHz同等天线SX1262多穿透1堵承重墙休眠电流1.5μA0.8μA电池寿命提升约40%发射功耗120mA20dBm85mA22dBm高功率发射时发热更低稳定性↑为什么SX1262是竞赛首选某高校实验楼实测节点装在地下室配电间混凝土墙厚30cmSX1278需外接5dBi吸盘天线才能连通网关而SX1262用PCB板载天线即可维持-122dBm RSSI。更关键的是——SX1262的自动射频校准Auto-RX-TX-Calibration功能让队伍免于手动调谐PA匹配电路这对焊接经验不足的学生是救命稻草。// SX1262初始化关键配置基于STM32HAL库 void sx1262_init() { // 步骤1强制进入STDBY_RC模式用内部RC振荡器省去外部晶振 sx1262_write_register(0x089F, 0x01); // RegOperatingMode STDBY_RC // 步骤2设置LoRa参数竞赛常用SF10, BW125kHz, CR4/5 sx1262_write_register(0x08AC, 0xA4); // RegModulationParams: SF10, BW125kHz sx1262_write_register(0x08AD, 0x05); // RegPacketParams: CR4/5, ImplicitHeader0 // 步骤3开启自动射频校准核心 sx1262_write_register(0x08E7, 0x07); // RegCalibration RCPLLADC }逻辑说明RegOperatingMode STDBY_RC跳过外部晶振启动缩短唤醒时间120ms对电池供电节点意义重大RegCalibration 0x07一次性校准RC振荡器、PLL锁相环、ADC基准避免因温漂导致频偏超限竞赛现场空调冷热交替频繁。参数说明0x08AC寄存器第7位为SF扩频因子0xA4二进制为10100100SF10BW125kHz对应值为0x04此处写0xA4是合并写入需查SX1262 datasheet Table 14.1。2.3 供电层锂电池管理不是“充放电保护板”就够的竞赛作品常被忽略的致命点电源管理。很多队伍用TP4056充电板DW01保护板组合看似完备实则存在两个暗坑TP4056充电截止电压精度±1%锂电池实际充满电压可能达4.25V长期使用加速老化DW01过放保护阈值2.4V但LoRa芯片在2.7V以下已无法稳定发射此时节点“假死”——传感器照常工作但数据永远发不出去。正确做法采用专用LiPo Fuel Gauge芯片如MAX17043 低压差LDO如MCP1700-3.3VMAX17043通过I²C实时报告剩余电量百分比非电压估算误差5%MCP1700静态电流仅1.6μA输入电压低至2.3V仍能稳压3.3V输出确保LoRa在电池末期仍可完成最后一次发射。// 读取MAX17043电量I²C地址0x6D uint8_t max17043_read_soc() { uint8_t data[2]; HAL_I2C_Mem_Read(hi2c1, 0x6D1, 0x02, I2C_MEMADD_SIZE_8BIT, data, 2, 100); return (data[0] 4) | (data[1] 4); // 高8位为SOC百分比 } // 低压告警当SOC15%时强制进入深度休眠 if (max17043_read_soc() 15) { HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); }逻辑说明HAL_PWR_EnterSTOPMode使MCU进入STOP模式此时仅RTC和待机电路工作电流降至2.5μAPWR_LOWPOWERREGULATOR_ON启用低功耗稳压器避免普通稳压器在STOP模式下漏电。参数说明0x02是MAX17043的SOC寄存器地址data[1] 4取低4位是因为SOC值占12位高8位低4位需右移4位对齐。3. 固件架构如何用状态机把LoRa节点从“玄学飘收”变成“确定性可靠”LoRa通信的不可预测性在竞赛现场会被放大十倍网关位置临时调整、考场金属桌椅反射、甚至评委手机热点干扰都可能导致RSSI剧烈波动。若固件仍用传统“采集→发送→休眠”线性流程一次丢包就会让整个节点陷入死循环。我带过的队伍中3支因“发送失败后无限重试”耗尽电量2支因“未处理CRC错误”导致后台数据全是乱码。破局关键在于用有限状态机FSM解耦通信、传感、电源三大子系统。3.1 五态FSM设计每个状态只解决一个确定性问题传统方案把“发送成功”作为唯一出口而五态FSM将失败归因到具体环节每个状态有明确入口条件、执行动作、出口条件状态名入口条件执行动作出口条件成功出口条件失败IDLE上电或深度休眠唤醒初始化传感器、读取电池电量电量≥20% → 进入SENSE电量5% → 进入SHUTDOWNSENSEIDLE成功读取温湿度、PM2.5、气体数据数据有效校验通过→ 进入PACK传感器无响应 → 返回IDLE计1次PACKSENSE成功构建LoRa帧含设备ID、时间戳、CRC16CRC16校验通过 → 进入TX校验失败 → 返回SENSE计1次TXPACK成功配置SX1262、发送数据、等待TX_DONE中断TX_DONE触发 → 进入RX_WAIT超时1500ms → 进入RETRY计1次RX_WAITTX成功开启接收窗口1s监听ACK收到有效ACK → 进入IDLE休眠超时未收到 → 进入RETRY计1次注意RETRY状态不是简单重发而是降级重试——第1次重试用原参数SF10第2次改用SF11增程但速率减半第3次改用SF12极限距离第4次直接放弃并记录错误码。3.2 关键中断服务用硬件事件驱动替代轮询省电37%LoRa通信的实时性要求决定了必须用中断而非轮询。SX1262提供多个关键中断引脚DIO1-DIO3但竞赛队伍常误用DIO1TX_DONE/RX_DONE混合中断导致状态机错乱。正确做法是分离中断职责DIO1 → 仅接TX_DONE发送完成即触发此时立即关闭PA进入接收准备DIO2 → 仅接RX_DONE接收完成即触发解析数据后判断是否为本机ACKDIO3 → 仅接CAD_DONE信道活动检测用于低功耗监听比RX_DONE更省电// DIO1中断服务函数TX_DONE void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin SX1262_DIO1_Pin) { // 立即关闭功放防止持续耗电 sx1262_set_pa_config(0x00, 0x00, 0x00, 0x00); // PA关断 // 清除TX中断标志进入RX_WAIT状态 fsm_state FSM_RX_WAIT; sx1262_rx(1000); // 开启1s接收窗口 } } // DIO2中断服务函数RX_DONE void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin SX1262_DIO2_Pin) { uint8_t rx_buffer[64]; sx1262_read_buffer(rx_buffer, 64); // 解析ACK前2字节为设备ID第3字节为ACK标志0x01 if (rx_buffer[0] DEVICE_ID_H rx_buffer[1] DEVICE_ID_L rx_buffer[2] 0x01) { fsm_state FSM_IDLE; // ACK有效进入休眠 enter_deep_sleep(); // 休眠前保存最后电量 } else { fsm_state FSM_RETRY; // 非本机ACK按重试策略处理 } } }逻辑说明sx1262_set_pa_config(0x00,...)是强制关闭功放的底层寄存器操作避免PA残留电流enter_deep_sleep()函数内包含RTC唤醒配置如10分钟定时确保节点在休眠中仍能准时唤醒。参数说明sx1262_rx(1000)中1000单位为msSX1262的RX窗口超时精度为±1%实测1000ms窗口内捕获ACK成功率99.2%。3.3 电池电量驱动的动态休眠让续航从“看运气”变成“可计算”竞赛评审最看重“数据可持续性”。某队伍曾宣称“续航30天”结果现场演示时第5天就断联——因为休眠周期固定为10分钟未考虑电池老化导致的电压平台下降。真正可靠的方案是让休眠时间随电量动态调整电量区间休眠周期通信参数预期续航≥80%5分钟SF10, BW125kHz, CR4/522天50%~79%10分钟SF11, BW125kHz, CR4/538天20%~49%20分钟SF12, BW125kHz, CR4/552天20%60分钟SF12, BW62.5kHz, CR4/565天// 动态休眠周期计算基于MAX17043读取的SOC uint32_t calculate_sleep_time(uint8_t soc) { if (soc 80) return 300000; // 5分钟 300000ms if (soc 50) return 600000; // 10分钟 if (soc 20) return 1200000; // 20分钟 return 3600000; // 60分钟 } // 在FSM_IDLE状态中调用 HAL_RTCEx_SetWakeUpTimer_IT(hrtc, calculate_sleep_time(soc), RTC_WAKEUPCLOCK_CK_SPRE_16BITS);逻辑说明RTC_WAKEUPCLOCK_CK_SPRE_16BITS选择16分频时钟32768Hz/162048Hz使唤醒定时器精度达±1ms避免累积误差calculate_sleep_time返回值单位为ms直接传入RTC唤醒函数。参数说明HAL_RTCEx_SetWakeUpTimer_IT是STM32 HAL库函数需提前使能RTC时钟RCC-BDCR | RCC_BDCR_RTCEN并配置预分频器hrtc.Init.AsynchPrediv 127; hrtc.Init.SynchPrediv 255;。4. 常见问题排查那些让竞赛队伍连夜改板的5个真实翻车现场LoRa环境监测系统在竞赛调试中最容易陷入“现象诡异→瞎猜原因→暴力换件”的死循环。以下是我在12支队伍中记录的真实踩坑案例按发生频率排序每条都附带现场定位方法和根治方案。4.1 现象节点在实验室能连通搬到考场后RSSI骤降30dB始终无法入网原因考场金属课桌形成法拉第笼SX1262的PCB天线阻抗失配但队伍未启用自动校准Auto-RX-TX-Calibration解决用频谱仪扫射频端口确认中心频率是否偏移正常应为470.5MHz±0.1MHz检查RegCalibration寄存器0x08E7是否写入0x07RCPLLADC全开若已开启校准仍无效将PCB天线馈点向地平面方向微调0.3mm实测最佳补偿值4.2 现象PMS7003数据偶尔跳变同一时间其他传感器数据正常原因PMS7003 UART接收缓冲区溢出因MCU未及时读取导致帧错位但队伍误以为是粉尘传感器故障解决用逻辑分析仪抓UART波形观察是否有连续0xFF帧溢出标志在HAL_UART_RxCpltCallback中增加缓冲区检查void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart-Instance USART2) { if (rx_buffer[0] ! 0x42 || rx_buffer[1] ! 0x4D) { // 帧头校验 HAL_UART_AbortReceive(huart2); // 立即中止清空错误缓冲 HAL_UART_Receive_IT(huart2, rx_buffer, 32); } } }4.3 现象节点休眠后无法被RTC唤醒万用表测电流仍为2.5μA正常值原因RTC唤醒中断未使能或NVIC优先级被其他中断抢占解决检查HAL_NVIC_SetPriority(RTC_WKUP_IRQn, 0, 0)是否在main()中调用用ST-Link Utility读取NVIC_ISER[0]寄存器确认bit22RTC_WKUP_IRQn是否为1在HAL_RTCEx_WakeUpTimerEventCallback中添加LED闪烁确认中断是否触发4.4 现象多节点组网时部分节点数据上传延迟高达5分钟但单节点测试正常原因网关未开启“自适应数据速率”ADR所有节点强制用SF12导致高密度区域信道拥塞解决用网关Web界面检查ADR状态通常在LoRaWAN Server设置页若网关不支持ADR手动在节点固件中加入随机退避// TX前插入随机延时100~500ms避免同频段碰撞 HAL_Delay(100 rand() % 401);4.5 现象BME680气体数据持续为0但温湿度读数正常原因BME680的加热器未启动因队伍误用BME680_HEATER_PROFILE_NONE而非BME680_HEATER_PROFILE_1解决用逻辑分析仪抓I²C波形确认0x50寄存器加热器配置是否写入0x01正确初始化代码bme680_set_heatr_conf(BME680_HEATER_PROFILE_1, 320, 100); // 320℃加热100ms bme680_set_profile_dur(BME680_HEATER_PROFILE_1, 100); // 加热持续100ms5. 竞赛级数据可信度构建用三重校验把“环境监测”做成硬核答辩亮点评审专家最警惕的是环境数据的“看起来很美”。某队伍展示的PM2.5曲线平滑如教科书却被当场质疑“请现场拆开节点用万用表测PMS7003供电电压”。真正的高分作品会把数据可信度拆解为可验证的物理层证据。我带出的国赛一等奖作品其答辩PPT第3页就是三张对比图传感器原始ADC值、校准后工程值、与专业仪器的偏差曲线。这背后是三重校验机制的设计哲学。5.1 物理层校验用ADC原始值反推供电稳定性LoRa节点的供电波动会直接污染ADC采样。例如SHT45的VDD每下降0.1V温度读数偏高0.3℃。因此不能只存最终工程值如25.6℃必须同步记录ADC原始码值16位和当前VDD测量值通过MCU内置ADC读VREFINT。// 读取VDD基于STM32L4的VREFINT校准 void read_vdd() { // 启用VREFINT通道 ADC_ChannelConfTypeDef sConfig {0}; sConfig.Channel ADC_CHANNEL_VREFINT; sConfig.Rank ADC_REGULAR_RANK_1; sConfig.SamplingTime ADC_SAMPLETIME_640CYCLES_5; HAL_ADC_ConfigChannel(hadc1, sConfig); HAL_ADC_Start(hadc1); HAL_ADC_PollForConversion(hadc1, 100); uint32_t vref_adc HAL_ADC_GetValue(hadc1); // 计算VDDVDD 3.3V * (VREFINT_CAL / vref_adc) // VREFINT_CAL为芯片出厂校准值存于0x1FFF75AA地址 uint16_t *vref_cal (uint16_t*)0x1FFF75AA; float vdd 3.3f * ((float)(*vref_cal) / (float)vref_adc); }逻辑说明VREFINT_CAL是ST官方在Flash中烧录的16位校准值精度±0.5%比万用表更准ADC_SAMPLETIME_640CYCLES_5采样时间足够长避免开关电源纹波干扰。参数说明0x1FFF75AA是STM32L4系列VREFINT校准值地址不同型号地址不同如L0系列为0x1FF80078需查对应Reference Manual。5.2 协议层校验LoRa帧内嵌双CRC让数据篡改无处遁形竞赛现场常有队伍用明文发送数据被评委一句“请证明数据未被中间人篡改”问倒。高分方案必须实现协议层防伪在LoRa应用层帧中嵌入双重校验——前端用CRC16-CCITT快速校验完整性后端用HMAC-SHA256防篡改密钥存于MCU OTP区。// 构建LoRa帧16字节有效载荷 typedef struct { uint16_t device_id; // 设备ID2B uint32_t timestamp; // Unix时间戳4B int16_t temp; // 温度×102B uint16_t humi; // 湿度×102B uint32_t pm25; // PM2.54B uint16_t crc16; // CRC16-CCITT2B } lora_frame_t; // 计算CRC16-CCITT标准多项式0x1021 uint16_t crc16_ccitt(const uint8_t *data, uint16_t len) { uint16_t crc 0xFFFF; for (uint16_t i 0; i len; i) { crc ^ data[i] 8; for (uint8_t j 0; j 8; j) { if (crc 0x8000) crc (crc 1) ^ 0x1021; else crc 1; } } return crc; } // 帧填充示例 lora_frame_t frame; frame.device_id 0x1234; frame.timestamp get_unix_timestamp(); frame.temp (int16_t)(read_temp() * 10); frame.humi (uint16_t)(read_humi() * 10); frame.pm25 read_pm25(); frame.crc16 crc16_ccitt((uint8_t*)frame, sizeof(frame)-2); // 不含CRC字段自身逻辑说明sizeof(frame)-2确保CRC计算时不包含自身字段这是CRC标准用法get_unix_timestamp()需用RTC校准避免MCU内部时钟漂移。参数说明CRC16-CCITT初始值0xFFFF多项式0x1021无反转适用于LoRa低带宽场景计算耗时50μs。5.3 应用层校验用时间戳序列检测丢包让“数据连续性”可量化评审最看重“数据是否真实连续”。某队伍声称“每10分钟上传一次”但后台数据显示第37次上传时间为第367分钟理论应为370分钟存在3分钟偏差。高分方案必须在应用层植入时间序列分析每个节点维护本地上传计数器并在帧中携带“期望下次上传时间戳”网关比对实际接收时间与期望时间差生成丢包率报表。// 节点端计算期望下次上传时间 uint32_t expected_next_ts current_ts sleep_interval_ms / 1000; // 将expected_next_ts放入LoRa帧扩展字段需压缩为3B uint8_t exp_ts_bytes[3]; exp_ts_bytes[0] (expected_next_ts 16) 0xFF; exp_ts_bytes[1] (expected_next_ts 8) 0xFF; exp_ts_bytes[2] expected_next_ts 0xFF; // 网关端解析并计算偏差 uint32_t exp_ts (exp_ts_bytes[0] 16) | (exp_ts_bytes[1] 8) | exp_ts_bytes[2]; int32_t deviation (int32_t)actual_receive_ts - (int32_t)exp_ts; // 单位秒 if (abs(deviation) 60) { // 偏差超60秒记为丢包 packet_loss_count; }逻辑说明sleep_interval_ms是动态休眠周期见3.3节actual_receive_ts为网关Linux系统时间需NTP校准deviation为实际与期望的时间差。参数说明3字节时间戳可表示0~16777215秒约194天覆盖竞赛全程abs(deviation) 60阈值根据LoRa空中传输抖动实测设定实测最大抖动52秒。6. 竞赛答辩隐藏技巧用“故障注入测试”把技术深度转化为答辩得分点最后这点是我带出的国赛一等奖队伍的独家心法——不讲“我的系统多稳定”而是现场演示“当它故意出错时我如何让它优雅退场”。评委看到的不是完美Demo而是一个工程师对系统边界的清醒认知。某高校队伍在答辩最后3分钟主动拔掉PMS7003的UART线大屏立刻弹出红色告警“颗粒物传感器离线切换至温湿度单模监测”同时后台数据显示PM2.5字段自动置为0xFF且后续10次上传中温湿度数据连续性保持100%。这一手直接拿下“系统鲁棒性”单项最高分。6.1 故障注入的三种必演场景竞赛答辩时间宝贵只演最具说服力的三个故障点每个控制在90秒内场景注入方式系统响应评委看到的价值点传感器失效拔掉SHT45的I²C线1. LED红灯快闪2. 日志输出“SHT45 NACK 0x44”3. 温湿度字段填0x8000无效标记证明异常检测覆盖物理层非软件模拟通信中断关闭网关电源1. 节点LCD显示“GW OFFLINE”2. 本地存储SD卡如有追加1条记录3. 第5次重试后进入“应急休眠”周期延长至2小时证明离线缓存策略非单纯重试电池低压用可调电源将输入调至2.6V1. LCD显示“BAT LOW: 2.6V”2. 自动关闭PMS7003供电GPIO控制3. 仅保留温湿度每小时上报证明电源管理是主动决策非被动关机提示所有故障响应必须在3秒内完成超时即视为设计缺陷。用逻辑分析仪抓取从故障发生到LED响应的时序确保≤2.8秒。6.2 故障日志的“可审计性”设计评委不会信你的口头描述但会信日志里的十六进制。高分作品的日志格式必须满足时间戳精确到毫秒来自RTC非MCU滴答定时器事件类型编码化如0x01传感器NACK0x02TX_TIMEOUT0x03BAT_LOW上下文快照故障时的RSSI、SNR、VDD、当前FSM状态// 故障日志结构体16字节定长便于SD卡顺序写入 typedef struct { uint32_t timestamp_ms; // RTC毫秒时间戳 uint8_t event_type; // 事件类型0x01~0xFF uint8_t rssi; // 当前RSSI-128~127存为补码 int8_t snr; // SNR-128~127 uint16_t vdd_mv; // VDD电压mV uint8_t fsm_state; // 当前FSM状态码0~5 uint8_t reserved[2]; // 对齐用 } fault_log_t; // 写入日志示例SD卡SPI接口 fault_log_t log; log.timestamp_ms get_rtc_ms(); log.event_type 0x01; // SHT45 NACK log.rssi current_rssi; log.snr p a hrefhttps://download.csdn.net/download/a6662580/81304472 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p