LoRa物联网追踪器开发实战:从硬件选型到低功耗固件设计
1. 项目概述:LoRa追踪器/寻呼设备
最近在捣鼓一个挺有意思的小玩意儿,一个基于LoRa技术的追踪器,或者说,它更像一个超远距离的“数字寻呼机”。这玩意儿核心就一个:用极低的功耗,实现几公里甚至十几公里范围内的单向或双向信息传递。听起来是不是有点像对讲机?但它可比对讲机省电多了,一个纽扣电池能撑好几个月,而且穿透力强,在城市楼宇间或者野外复杂地形里,表现比传统的Wi-Fi、蓝牙要靠谱得多。
我之所以折腾这个,是因为在一些特定的场景下,比如仓库资产盘点、宠物防丢、户外徒步队员间的简易联络,或者农场里监测个设备状态,你需要的不是高速率、大数据量的传输,而是“信号能传到”和“设备别老充电”。LoRa(Long Range)技术正好切中了这个痛点。它牺牲了传输速度,换来了超远的通信距离和极低的功耗。这个项目,就是基于市面上常见的LoRa模块(比如SX1278、RAK3172这些),搭配一个微控制器(MCU),打造一个可以自定义功能的追踪或信息收发终端。
简单来说,这个设备能干两件事:一是“发”,把自己的ID、传感器数据(比如GPS位置、温度)或者预设的报警信息发出去;二是“收”,监听特定频道,接收来自基站或其他设备的信息,并通过震动、声音或小屏幕显示出来,实现寻呼功能。它非常适合那些对成本敏感、需要长期部署且更换电池不便的物联网应用。无论你是嵌入式开发爱好者想练手,还是行业应用开发者寻找解决方案,这个项目都能给你提供一个清晰的实现路径和踩坑经验。
2. 核心硬件选型与电路设计思路
做硬件项目,第一步永远是选型。选对了,事半功倍;选错了,调试到怀疑人生。对于LoRa Tracker/Pager,核心就三块:LoRa射频模块、主控MCU、电源管理。围绕它们,再扩展传感器、人机交互等外围电路。
2.1 LoRa模块选型:芯片与模块的权衡
市面上LoRa方案主要分两种:一是纯射频芯片,如Semtech的SX1276/78/79系列;二是集成LoRa芯片和MCU的模组,如ASR的ASR6501、瑞萨的RAK3172(基于STM32WL)。对于新手或快速原型开发,我强烈建议从集成模组开始。
注意:直接使用SX1278这类纯射频芯片,你需要自己设计射频匹配电路、天线电路,并用MCU通过SPI接口去驱动它。射频电路布局布线要求极高,一个没处理好,通信距离就可能从几公里掉到几百米。而集成模组厂家已经帮你做好了这部分最难的工作,你只需要通过UART或I2C等简单接口发送AT指令或调用库函数即可,大大降低了门槛。
我这次用的是RAK3172模组。它内部集成了STM32WLE5CC这颗支持LoRa的Cortex-M4芯片,意味着主控和射频二合一,外围电路极其简洁。你只需要给它接上电源、天线,再通过串口就能进行通信。它的优势是自带ARM内核,性能足够,且ST的生态完善,HAL库用起来顺手。劣势是成本相对纯“MCU+SX1278”方案略高。
如果追求极致性价比,且有一定射频基础,可以选择“STM32F103(或其他低功耗MCU) + SX1278”的方案。这时,你需要仔细阅读SX1278的数据手册,关注以下几个关键引脚和电路:
- SPI接口:SCK, MISO, MOSI, NSS。务必确保SPI时钟速率在芯片支持范围内(通常初始化时用低速)。
- 控制引脚:RESET(复位), DIO0-DIO5(用于中断,如收发完成、超时等)。DIO0通常映射到MCU的外部中断引脚,用于高效处理收发事件。
- 射频匹配电路:这是核心。参考芯片手册或官方评估板设计,通常包括π型匹配网络和巴伦电路。天线接口建议使用标准的IPEX座子,方便连接各种胶棒天线或弹簧天线。
- 电源滤波:LoRa芯片在发射瞬间电流较大(约120mA),必须在电源引脚就近放置一个10μF以上的钽电容和一个100nF的陶瓷电容,以提供瞬时电流并滤除高频噪声。
2.2 主控MCU与电源管理设计
如果你选择了类似RAK3172的集成模组,那么它本身就是主控。如果选择了“MCU+SX1278”的分立方案,MCU的选型要重点考虑功耗和外设。
低功耗MCU推荐:STM32L0/L4系列、EFM32、nRF52系列(后者还集成蓝牙)。这些MCU都有多种低功耗模式(Sleep, Stop, Standby)。我们的设备大部分时间应处于深度睡眠(Stop或Standby模式),仅由定时器或外部中断(如按键唤醒、接收中断)唤醒,处理完任务后迅速再次休眠,这是长续航的关键。
电源管理电路是整个设备的“能量心脏”。如果使用电池供电,尤其是纽扣电池(如CR2032),其输出电流能力有限(通常峰值不超过20mA)。而LoRa发射时峰值电流可能超过100mA,这会导致电池电压瞬间被拉低,造成MCU复位。因此,必须加入一个大容量储能电容(如47μF至220μF的钽电容或低ESR的电解电容)在电源入口处。同时,一个高效的LDO(低压差线性稳压器)或DC-DC降压芯片是必须的,将电池电压稳定到3.3V。对于追求极致效率的,可以选择带有“省电模式(PSM)”的电源芯片。
外围电路设计要点:
- 传感器:如果需要定位,GPS模块(如ATGM336H)是耗电大户,仅在需要时上电。更省钱的方案是基站定位,通过多个LoRa基站收到信号的强度(RSSI)来粗略估算位置。
- 人机交互:一个单色OLED小屏(如SSD1306,I2C接口)可以显示信息,但会增加功耗。更简单的寻呼机可能只需要一个LED和一个震动马达。务必为马达驱动设计三极管或MOS管开关电路,MCU的GPIO引脚无法直接驱动马达。
- 调试接口:SWD/JTAG接口和UART转USB芯片(如CH340)务必留出,这是你后期调试的生命线。
3. 软件架构与低功耗策略实现
硬件搭好了,软件才是让设备“活”起来并实现长续航的灵魂。软件架构的核心思想是事件驱动和状态机,围绕低功耗展开。
3.1 主程序状态机设计
设备不可能一直全速运行。一个典型的工作循环如下:
- 深度睡眠:设备99%的时间处于此状态,仅RTC(实时时钟)和唤醒电路工作,电流可能低至1μA以下。
- 定时唤醒:由RTC闹钟或低功耗定时器(LPTIM)周期性唤醒,例如每10秒唤醒一次。
- 执行任务:唤醒后,初始化必要的外设(如LoRa模块、传感器),检查是否有信息需要发送(如定时上报位置),或监听一下空中是否有发给自己的消息。
- 快速休眠:任务执行完毕(可能只需几十毫秒),立即关闭所有高速外设(如射频、传感器),重新进入深度睡眠。
在代码中,这通常用一个超级循环(Super Loop)配合低功耗管理函数来实现。以STM32的HAL库为例,核心流程伪代码如下:
int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); // 其他必要初始化,注意先不初始化高功耗外设(如LoRa SPI) // 配置RTC或LPTIM定时唤醒 MX_RTC_Init_SetWakeup(10); // 每10秒唤醒一次 while (1) { // 1. 检查唤醒源 if (__HAL_PWR_GET_FLAG(PWR_FLAG_WU) != RESET) { // 是被定时器唤醒的 __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); process_periodic_task(); // 处理周期性任务,如发送信标 } if (check_button_press()) { // 是被按键唤醒的 process_button_event(); // 处理按键事件,如发送SOS } // 2. 处理其他事件(如串口收到AT指令) process_uart_command(); // 3. 判断是否所有任务处理完毕,可以休眠 if (is_system_idle()) { // 进入停止模式(Stop Mode),保留RAM,可由RTC或外部中断唤醒 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); // 唤醒后,系统时钟会重置为HSI,需要重新配置系统时钟 SystemClock_Config_AfterSTOP(); } } }3.2 LoRa通信协议与数据包设计
LoRa物理层只管把数据发出去,但数据包怎么组织、设备如何识别彼此,这就是应用层协议的事。一个简单可靠的私有协议至关重要。
数据包结构示例: 一个典型的数据帧可以这样设计:
[前导码 1字节] | [目标地址 2字节] | [源地址 2字节] | [包类型 1字节] | [数据长度 1字节] | [数据载荷 N字节] | [CRC16校验 2字节]- 前导码:固定值,如0xAA,用于帧起始同步。
- 地址:用于区分不同设备。广播地址可以设为0xFFFF。
- 包类型:定义这是数据上报(0x01)、ACK确认(0x02)、控制命令(0x03)还是寻呼消息(0x04)。
- CRC校验:确保数据在传输过程中没有出错,接收方校验失败则丢弃。
通信模式:
- 单向追踪(Tracker模式):设备周期性(如每分钟)发送包含自身ID和传感器数据(经纬度、电量)的数据包。网关负责接收并上传到服务器。无需确认,简单但可能丢包。
- 双向寻呼(Pager模式):发送方(基站或手机)发送一条消息给特定地址的设备。设备收到后,可以回发一个ACK确认。这需要设计简单的重传机制,例如发送后等待2秒,没收到ACK就重发,最多3次。
关键参数配置: LoRa的性能由几个关键参数决定,需要在通信距离、数据速率和抗干扰之间权衡:
- 扩频因子(SF, Spreading Factor):从SF7到SF12。SF越大,传输距离越远,抗干扰能力越强,但传输速度越慢,空中停留时间越长(更耗电)。城市环境,SF9~SF10是平衡点;远距离,可用SF11~SF12。
- 带宽(BW, Bandwidth):常用125kHz, 250kHz, 500kHz。带宽越宽,速率越高,但接收灵敏度略有下降。125kHz是兼顾距离和速率的常见选择。
- 编码率(CR, Coding Rate):4/5到4/8。编码率越高(分母越大),纠错能力越强,但有效数据比例降低。通常用4/5或4/7。
在代码中,你需要根据使用的LoRa芯片库来配置这些参数。例如,使用RadioLib库(一个优秀的开源多协议射频库):
// 以SX1278为例,设置频率为433MHz,SF=9,BW=125kHz,CR=4/7,同步字=0x12 int state = lora.begin(433.0, 125.0, 9, 7, 0x12, 17, 8, 0); if (state == ERR_NONE) { Serial.println("LoRa初始化成功!"); } else { Serial.print("初始化失败,错误码:"); Serial.println(state); }4. 固件开发实战与代码解析
理论说再多,不如一行代码。我们以RAK3172(STM32WLE5)为例,使用STM32CubeIDE和HAL库,搭建一个最简单的双向信标程序。
4.1 工程配置与LoRa驱动集成
首先,用STM32CubeMX初始化芯片。关键步骤:
- 使能RTC,配置为唤醒定时器(Wake-up timer)。
- 配置一个UART用于调试打印(连接CH340到电脑)。
- 配置另一个LPUART(低功耗UART)或普通UART用于连接其他传感器(如GPS)。
- 配置一个GPIO连接到LED,用于指示状态。
- 最重要的是,因为RAK3172的LoRa射频部分与STM32WLE5内核紧密集成,你需要添加Semtech的LoRaWAN协议栈(或者只使用其底层的LoRa调制驱动)。对于私有协议,我们可以使用更轻量级的驱动,比如直接使用ST提供的SubGHz_Phy中间件库。
在CubeMX中,通过“Software Packs”选择安装“STMicroelectronics.X-CUBE-SUBG2”这个软件包。安装后,在“Project Manager”的“Advanced Settings”里,将SX126x或SX127x的驱动由“Application”改为“STMicroelectronics”,这样CubeMX就会帮你生成SubGHz驱动的初始化代码。
生成代码后,你会在Application/User/目录下找到subghz_phy_app.c和subghz_ph相关的文件。我们的主要工作就是调用这个中间件提供的API来收发数据。
4.2 关键功能函数实现
我们实现两个核心函数:发送信标和接收监听。
发送函数示例:
// 定义一个简单的数据包结构体 typedef struct { uint16_t dest_addr; uint16_t src_addr; uint8_t pkg_type; uint8_t data_len; uint8_t data[32]; uint16_t crc; } lora_packet_t; void send_lora_beacon(void) { lora_packet_t packet; packet.dest_addr = 0xFFFF; // 广播 packet.src_addr = MY_DEVICE_ADDR; packet.pkg_type = 0x01; // 信标 packet.data_len = snprintf((char*)packet.data, 32, "V:%.2f", read_battery_voltage()); packet.crc = calculate_crc16((uint8_t*)&packet, sizeof(packet) - 2); // 计算除CRC字段外的CRC // 配置射频参数 SUBGHZ_PhySetParams_t param = { .Modulation = MODULATION_LORA, .Freq = 433500000, // 中心频率433.5MHz .LoRaBandwidth = LORA_BW_125, // 带宽125kHz .LoRaCoderate = LORA_CR_4_7, .LoRaSpreadingFactor = LORA_SF9, .LoRaPreambleLength = 8, }; SUBGHZ_PhySetParams(¶m); // 将数据包拷贝到发送缓冲区并启动发送 uint8_t tx_buffer[64]; uint16_t tx_size = pack_data_to_buffer(&packet, tx_buffer); SUBGHZ_PhySend(tx_buffer, tx_size, RF_TX_TIMEOUT_DEFAULT); // 等待发送完成(可以设置为中断方式,这里用轮询简化) while(SUBGHZ_PhyGetStatus() == RF_BUSY) { HAL_Delay(1); } LED_BLINK(1); // 发送完成,LED闪烁一次 }接收函数(在中断回调中处理): SubGHz驱动通常以中断方式通知接收完成。我们需要在subghz_phy_app.c中找到接收回调函数(如SUBGHZ_PhyRxCallback)并进行修改。
// 在应用层文件中声明一个接收缓冲区 uint8_t rx_buffer[64]; uint16_t rx_size; void my_rx_callback(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) { // 这个函数在射频驱动收到数据后自动调用 if(size > 0) { memcpy(rx_buffer, payload, size); rx_size = size; // 解析数据包 lora_packet_t *pkt = (lora_packet_t*)rx_buffer; if(verify_packet_crc(pkt)) { // CRC校验 if(pkt->dest_addr == MY_DEVICE_ADDR || pkt->dest_addr == 0xFFFF) { // 是发给我的或广播包 handle_received_packet(pkt, rssi, snr); // 处理包内容 LED_BLINK(2); // 收到包,LED闪烁两次 } } } // 重新使能接收,持续监听 SUBGHZ_PhyRecv(RF_RX_TIMEOUT_CONTINUOUS); } // 在main初始化中,替换默认的回调函数 SUBGHZ_PhySetRxCallback(my_rx_callback);4.3 低功耗休眠与唤醒的实现细节
让设备真正省电,休眠的配置是关键。STM32的Stop模式可以保留RAM,功耗极低,但所有高速时钟都关闭了。
void enter_stop_mode(void) { // 1. 关闭所有高功耗外设的时钟和电源 HAL_UART_DeInit(&huart1); // 关闭调试串口 // 关闭LoRa射频部分(如果驱动支持) SUBGHZ_PhySleep(); // 关闭其他传感器电源(通过GPIO控制其VCC) // 2. 配置唤醒源(这里使用RTC Wake-up Timer) HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 4096, RTC_WAKEUPCLOCK_RTCCLK_DIV16); // 约10秒唤醒一次 // 3. 清除唤醒标志,使能唤醒中断 __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1); // 使能RTC唤醒引脚 // 4. 进入Stop模式 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); // 5. 唤醒后从这里继续执行(系统时钟变为HSI 16MHz) SystemClock_Config_AfterSTOP(); // 必须重新配置系统时钟为原来的高速时钟(如MSI 48MHz) // 6. 重新初始化被关闭的外设 HAL_UART_Init(&huart1); SUBGHZ_PhyWakeup(); // 唤醒LoRa射频 // ... 其他外设初始化 }实操心得:在进入Stop模式前,务必确保所有可能产生中断的外设都已妥善处理。例如,UART的接收中断如果未禁用,可能会因为串口噪声产生虚假中断,导致设备无法深度休眠或异常唤醒。一个稳妥的做法是,在休眠前,将所有GPIO设置为模拟输入(浮空)以降低功耗,并禁用所有不必要的外设时钟。
5. 天线、调试与实测性能优化
硬件和软件都准备好了,但最终通信距离和稳定性,很大程度上取决于“最后一公里”——天线和实际环境。
5.1 天线选型与安装要点
天线是LoRa设备的“嘴巴”和“耳朵”,其重要性怎么强调都不为过。
- 类型选择:常用的是胶棒天线和弹簧天线。胶棒天线(1/4波长,如433MHz约17cm)方向性较强,增益高(通常2-3dBi),通信距离远,但体积大。弹簧天线(通常设计为PCB上的螺旋或线状)是全向的,增益低(约0dBi),体积小,适合嵌入式设备。
- 阻抗匹配:天线阻抗必须与LoRa模块的射频输出阻抗匹配(通常是50Ω)。不匹配会导致信号能量反射,大幅降低发射效率。使用天线分析仪或矢量网络分析仪(VNA)可以测量驻波比(SWR),理想值应小于1.5。
- 安装禁忌:
- 绝对不要在金属外壳内使用内置天线,金属会屏蔽信号。如果必须用金属外壳,必须使用外置天线,并做好天线接头的密封防水。
- 天线周围至少留出1/4波长的净空区,不要铺铜或走线,尤其是地线。
- 天线应尽量远离电机、开关电源、数字信号线等噪声源。
5.2 系统调试与问题排查实录
调试这类无线设备,需要一套方法。以下是我踩过坑后总结的步骤:
电源与基础功能调试:
- 首先,不接LoRa模块,测试MCU能否正常启动、休眠、唤醒,GPIO控制LED是否正常。用万用表测量各点电压,特别是电池在LoRa发射瞬间的电压跌落情况。如果跌落超过0.3V,说明储能电容不够大或电池内阻太高。
- 使用
printf通过串口打印调试信息,是定位问题的利器。确保在进入低功耗模式前刷新串口缓冲区(HAL_UART_Transmit或等待发送完成标志)。
LoRa射频功能调试:
- 先确保能发:编写一个最简单的连续发射程序(例如每秒发一个固定数据包),使用频谱分析仪或另一个LoRa设备(如LoRa USB Dongle)在近距离(1米内)接收,确认有信号发出,且频率正确。
- 再测试能收:两个设备,一个固定发射,另一个固定接收,在代码中打印接收到的RSSI(信号强度指示)和SNR(信噪比)。近距离下,RSSI应在-40dBm到-60dBm之间。如果收不到,检查SPI/I2C/UART通信是否正常,LoRa芯片的寄存器配置是否正确(与发射方参数一致)。
- 参数一致性:收发双方的扩频因子(SF)、带宽(BW)、编码率(CR)和同步字(SyncWord)必须完全一致,这是最常见的通信失败原因。
通信距离测试:
- 从近距离开始,逐步拉远距离。记录每个点位的RSSI和丢包率。在城市环境,障碍物是主要敌人。将设备举高(如放在窗边、楼顶)能显著改善。
- 测试不同数据包长度的影响。LoRa数据包在空中停留时间(Time on Air)随包长增加而增加,被干扰的概率也增大。在满足需求的前提下,尽量缩短包长。
5.3 常见问题与解决方案速查表
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 设备完全无法启动 | 1. 电源问题(电压不足、反接) 2. 复位电路问题 3. 晶振不起振 | 1. 测量电池电压及LDO输出(应为3.3V)。 2. 检查复位引脚电平,正常应为高电平。 3. 用示波器测量晶振引脚波形(若无,可暂时使用MCU内部时钟HSI测试)。 |
| LoRa初始化失败 | 1. SPI/I2C通信失败 2. 芯片型号选择错误 3. 电源不稳定 | 1. 用逻辑分析仪抓取SPI波形,检查CS、CLK、MOSI信号。 2. 确认代码中初始化的芯片型号(SX1278 vs SX1262)与实际硬件一致。 3. 在LoRa芯片的VCC引脚处并联一个100μF电容。 |
| 通信距离极短(<100米) | 1. 天线问题(未接、短路、型号不匹配) 2. 射频参数配置错误 3. 环境干扰(同频段干扰) | 1. 确保天线已正确连接,用万用表测量天线接口无短路。 2. 反复核对收发双方的SF、BW、CR、频率。 3. 尝试更换另一个频率点或信道。 |
| 设备耗电过快 | 1. 未进入低功耗模式 2. 外围电路漏电 3. 唤醒过于频繁 | 1. 用电流表串联测量睡眠电流,应<10μA。检查代码是否成功进入Stop/Standby模式。 2. 逐个断开传感器模块,定位漏电元件。 3. 评估业务需求,延长定时唤醒间隔(如从1秒改为10秒)。 |
| 接收端数据乱码或CRC错误 | 1. 空中干扰 2. 双方时钟不同步导致解调错误 3. 缓冲区溢出 | 1. 观察SNR值,如果SNR很低(如<-10),可能是强干扰,尝试改变频率。 2. 确保收发双方使用相同的晶振精度(TCXO比普通晶振更稳定)。 3. 检查接收中断服务函数,确保处理数据的速度快于数据到达的速度。 |
| 程序运行一段时间后死机 | 1. 看门狗未喂狗 2. 堆栈溢出 3. 中断嵌套冲突 | 1. 使能独立看门狗(IWDG)并定期喂狗。 2. 在启动文件或链接脚本中增大堆栈(Stack/Heap)大小。 3. 避免在中断服务程序(ISR)中进行复杂操作或调用阻塞函数。 |
6. 项目扩展与应用场景思考
一个基础的LoRa Tracker/Pager做出来后,你可以根据不同的应用场景,对它进行功能扩展和优化。
功能扩展方向:
- 多传感器融合:除了GPS,可以集成温湿度传感器(如SHT30)、气压计(用于测海拔)、三轴加速度计(用于检测移动或跌落)。通过算法融合这些数据,可以更智能地判断设备状态(如静止、运输中、跌落报警)。
- 组网与中继:实现简单的Mesh网络。让设备不仅能与网关通信,设备之间也能互相转发数据,从而扩展网络覆盖范围。这需要更复杂的路由协议(如OLSR、AODV的简化版)。
- 固件无线升级(FOTA):通过LoRa信道传输新的固件数据包,实现远程批量升级。这对部署在野外的设备至关重要。需要设计可靠的分包、校验和重启机制。
- 加密与安全:在数据包中加入加密算法(如AES-128),防止数据被窃听或篡改。虽然LoRa物理层有一定安全性,但应用层加密仍是必要的。
典型应用场景实操建议:
- 资产追踪:设备固定在货架或集装箱上。为了省电,可以将GPS设为每1小时或移动时才启动一次。平时主要依靠周期性发送LoRa信标,由部署在仓库/场站内的多个LoRa网关进行三角定位,精度在10-50米,足够室内仓储管理使用。
- 户外人员安全寻呼:徒步队每人携带一个。队长手持一个带屏幕的“主站”,可以群发或点对点发送文字消息(如“集合”、“注意天气”)。队员设备以震动和LED提示。关键是要防水(达到IP67等级)和耐低温(电池在低温下容量骤减,需选用宽温电池或设计保温措施)。
- 农业环境监测:设备集成土壤湿度、光照强度传感器,定时将数据发回远处的网关。由于农田环境空旷,通信距离可以很远,但设备需要太阳能供电。设计时需考虑低功耗采集电路和太阳能电池板的充电管理。
这个项目从硬件选型、电路设计,到嵌入式编程、低功耗调试,再到最后的实测优化,几乎涵盖了物联网终端开发的全部核心环节。它不像做一个简单的LED闪烁那样立刻有反馈,过程中你会遇到各种奇怪的射频问题和电源问题,但解决问题的过程正是能力提升最快的时候。我最深的体会是,在物联网项目里,对功耗的极致追求和对无线环境的不确定性保持敬畏,是做出稳定可靠产品的两大基石。当你看到自己做的这个小设备,在几公里外依然能稳定地回传数据,那种成就感,绝对是点亮一个LED灯无法比拟的。下一步,我打算给它加上一块电子墨水屏,显示更丰富的信息,同时进一步优化算法,让那颗纽扣电池真的能撑上一年。
