简介:这套资源是基于STM32和ESP8266的物联网智能台灯系统完整工程,通过点灯科技平台实现配网与远程控制,面向嵌入式学生与毕设、课设、竞赛参与者,适用于项目开发、工程实训、大创等多个场景。压缩包共一千一百零六个文件,约四十三点二七兆字节,以五百七十二个C源码、二百六十七个头文件为主,并含汇编、固件、工程配置及说明文档,目录结构清晰,便于烧录调试。目前已有192人学习使用,该资源经严格测试可直接运行,适合快速复刻或扩展新功能。下载后获得完整源码与工程文件,针对不熟悉PCB者,可用面包板加杜邦线连接外设模块替代,降低复现门槛;作者深耕嵌入式领域,使用中问题可通过博客私信解答,是课设、竞赛与自学练手的实用参考。
1. 用STM32+ESP8266和点灯科技做物联网智能台灯:毕设演示从「能亮」到「会联」
晚上在宿舍摸黑找台灯开关,是很多人做智能台灯选题的原始动机。而一套基于STM32和ESP8266、通过点灯科技Blinker平台设计的物联网智能台灯系统,恰好卡在课设与毕设的平衡点上:STM32负责本地控制(按键、PWM调光、灯具驱动),ESP8266负责联网接云,点灯科技提供App端控件与云端消息转发。对物联网毕业设计和竞赛实训来说,这既避开了自己搭MQTT服务器、自己写手机App的巨大工作量,又保留了串口协议、中断解析、PWM输出、状态机这些答辩时老师必问的知识点。下面按我实际做过的一条完整路径讲:怎么选型、怎么接线、怎么配网、怎么写STM32代码、踩过哪些坑、最后怎么验证。
2. 系统骨架与硬件选型:为什么是STM32+ESP8266而不是一块板子干到底
2.1 架构分层:主控、通信、云端的职责边界
先把这套系统的分工理清楚。最简单粗暴的方案是买一块ESP32开发板,WiFi、蓝牙、GPIO全都有,一个板子就能跑完整个台灯逻辑。但放到毕设和课设的场景里,这个方案的缺点很明显:ESP32的资料虽然多,但答辩时你很难讲出层次感,而且ESP8266/ESP32上跑WiFi协议栈本身就占了不少资源,你再用它去做按键扫描、PWM调光、ADC采集,代码稍微一多就容易互相挤兑,定位问题也麻烦。
常见做法是把系统拆成三个角色。STM32做主控,负责所有实时性要求高的本地逻辑:按键消抖、PWM调光、ADC读光敏电阻、本地状态机维护。ESP8266只做一件事——透传,它跑WiFi协议栈和MQTT客户端,通过串口和STM32通信。点灯科技(Blinker)则站在云端,把手机App和ESP8266之间的消息通道、设备管理、控件绑定全部封装好。这样的数据流是:手机App点按钮 → 点灯云 → ESP8266收到MQTT消息 → 通过串口发给STM32 → STM32解析后控制PWM输出 → 台灯亮度变化。
这个分层最大的好处是:哪一层出了问题,用串口日志一截就知道。WiFi连不上看ESP8266,指令没执行看STM32,App没反应看云端设备在线状态。读者如果做过物联网毕业设计就会明白,能快速定位问题在哪一层,比什么都重要。用STM32做主控还有一个现实考量:课设和毕设的评分标准里,STM32的中断、定时器、串口、PWM都是硬性知识点,把这些放在主控芯片上,答辩时你能展示的东西会多很多。
2.2 硬件选型与接线:避免三处常见设计错误
具体型号上,我一般推荐STM32F103C8T6最小系统板,也就是常说的「蓝板」,价格低、资料多,PA和PB两组IO足够用,标准库和HAL库的例程一抓一大把。WiFi模块的选择有两个方向:一是ESP-01S这种小模块,体积小但需要额外的USB转TTL才能下载固件,新手很容易卡在AT固件烧录上;二是NodeMCU开发板,自带USB转串口和3.3V稳压,插上USB线就能刷固件,虽然体积大一点,但对课设来说,能少折腾一步就少折腾一步。对用ESP8266做物联网的入门项目来说,NodeMCU是最稳的选择。
调光执行部分要分清场景。如果只做开关,一个5V继电器模块就够了;但如果要做无级调光,千万别用继电器——继电器触点通断LED灯会造成肉眼可见的闪烁,而且频繁通断寿命极短。常见做法是用一个MOS管模块(如AO3400)做PWM调光,或者用PT4115这类LED恒流驱动芯片,PWM信号直接控制亮度,效果稳定。电源方面是最容易翻车的地方:ESP8266在WiFi发射瞬间电流峰值能到300mA以上,如果用板载AMS1117从USB取电,电压会被拉垮导致模块反复重启。经验值是:STM32和ESP8266各用一路供电,或者共用一个5V/2A的适配器,但ESP8266的3.3V不要和STM32的3.3V从同一个1117出。
接线表按我常用的方案列一下:
| 信号 | STM32引脚 | ESP8266/外围模块 |
|---|---|---|
| ESP8266 TXD | PA10(USART1_RX) | D4(GPIO2) |
| ESP8266 RXD | PA9(USART1_TX) | D3(GPIO0) |
| 共地 | GND | GND |
| PWM调光输出 | PA0(TIM2_CH1) | MOS管栅极 / PT4115 DIM脚 |
| 按键输入 | PB0 | 按键一端接GND |
| LED状态灯 | PB1 | LED串电阻接3.3V |
接线有3个容易设计错误的地方。第一,ESP8266的TXD接STM32的RX,RXD接STM32的TX,交叉接,很多人这里搞反;第二,两个板子必须共地,否则串口电平没有参考点,收的全是乱码;第三,如果用ESP-01S,它的RXD/TXD电平是3.3V,STM32的USART也是3.3V,可以直接连,但如果你的STM32板子上带了5V电平的芯片,就要确认是不是直连,必要时加电平转换。另外一个隐藏坑:有些STM32最小系统板上的PA9/PA10同时被板载跳线接到了CH340串口芯片上,你在烧录程序时ESP8266也在往这两个引脚发数据,偶尔会导致下载失败,这时把ESP8266的RX引脚断开再烧录就行。
3. 点灯科技平台侧配置:Blinker App创建设备与配网流程
3.1 创建设备、获取Secret Key与类型选择
点灯科技的接入方式和常见物联网平台不太一样。你不需要自己搭服务器,也不需要手写MQTT连接代码,它的核心思路是:设备端运行Blinker库,App端下载点灯科技App,两端通过同一个Secret Key在云端绑定。理解了这个模型,后面所有操作都是顺理成章的。
第一步,手机下载点灯科技App(应用商店搜「点灯科技」或「Blinker」),注册并登录。第二步,在App首页点「添加设备」,选择「独立设备」,设备类型选择「Arduino」或「WiFi」——这里选哪个影响不大,Blinker库会自动上报设备类型。第三步,创建设备后,App会生成一个Secret Key,一般是一串8位十六进制字符。这个Key要记下来,后面写进ESP8266的固件代码里。
第四步,在Arduino IDE或PlatformIO里给ESP8266写固件,核心代码大致是这样:
#define BLINKER_WIFI #include <Blinker.h> char auth[] = "你的SecretKey"; char ssid[] = "你的WiFi名称"; char pswd[] = "你的WiFi密码"; BlinkerButton btn("btn-led"); void btnCallback(const String &state) { // 把App发来的开关状态通过串口转发给STM32 if (state == "on") { Serial.println("$LED,ON,100#"); } else { Serial.println("$LED,OFF,0#"); } } void setup() { Serial.begin(115200); Blinker.begin(auth, ssid, pswd); btn.attach(btnCallback); } void loop() { Blinker.run(); }这段代码的逻辑说明:BLINKER_WIFI这个宏告诉Blinker库当前设备是WiFi接入方式;auth数组填的Secret Key就是设备在云端的身份标识;BlinkerButton对应App上创建的一个按键控件,控件名btn-led要和App里设置的组件名一致。btnCallback是按键回调函数,App上每操作一次按钮,这个回调就会被触发,回调里通过Serial.println向STM32发送一条自定义文本指令。Blinker.begin()执行的是完整的上电流程——连接WiFi、连接MQTT服务器、绑定设备,这个过程会阻塞一段时间,所以放在setup()里。loop()里的Blinker.run()是必须的,它负责维持心跳和消息接收,不能省。
如果你不想做配网后每次换WiFi都重新烧录,还有另一种做法:不在代码里写死ssid和pswd,而是调用Blinker.begin(auth)进入配网模式,然后通过App的「配置WiFi」功能把WiFi信息下发到设备。对演示来说,写死WiFi信息更省事,但如果你要把作品带到答辩现场去连现场WiFi,就必须用配网方式。
3.2 WiFi配网的两种方式与状态指示
Blinker库支持两种配网方式,原理完全不同。第一种是SmartConfig,手机App通过UDP广播把WiFi的SSID和密码发出去,ESP8266处于监听模式时收到并保存,之后自动连接。这种方式用户操作最方便,在App里点「配置WiFi」,输入密码发送即可。第二种是AP模式配网,ESP8266自己开一个热点,手机先连上这个热点,再通过网页或App提交路由器的SSID和密码,ESP8266收到后切换回Station模式连接路由器。
判断配网是否成功,最直接的办法是看ESP8266的板载LED状态。以NodeMCU为例,常见状态是:未配网时LED慢闪,正在连接WiFi时LED快闪,连接成功且MQTT连上云端后LED常亮。不同固件的LED定义不一样,最可靠的方式还是打开串口监视器,波特率115200,看Blinker库打印的日志。日志里出现MQTT Connected基本就是全网通了,如果一直卡在WiFi Connecting,那问题多半在SSID或密码上。
我这里要提醒一个和点灯科技有关的经验:Blinker的设备在线状态依赖MQTT心跳,默认大概几十秒一次。也就是说,你把台灯断电再上电,App里显示「在线」可能要等一小会儿,这不代表设备坏了。做演示前,提前几分钟上电让设备完成重连,不要在答辩现场刚插电就点App,容易翻车。另外,点灯科技的免费版对消息频率和设备数量是有限制的,个人做毕设课设完全够用,但如果要做产品化部署,就得考虑付费配额或换用巴法云、OneNET这类平台——那是另一个话题了,这里不展开。
4. STM32实现:串口协议、PWM调光与本地兜底逻辑
4.1 串口数据帧设计:一条指令如何区分设备与动作
STM32和ESP8266之间通过串口通信,协议怎么定,直接决定项目后期的调试难度。我见过很多人图省事,ESP8266直接把Blinker收到的JSON原样转发给STM32,然后让STM32去解析JSON——不是不行,但C语言解析JSON的代码量不小,而且JSON字符串长、格式易变,串口传输错一个字符就整个帧作废。对台灯这种功能单一的场景,自定义一个定长文本协议更稳。
我常用的帧格式是:$开头,#结束,中间用逗号分隔字段。第一字段是设备类型,第二字段是动作,第三字段是参数。比如:
| 指令 | 含义 |
|---|---|
$LED,ON,100# | 开灯,亮度100% |
$LED,ON,60# | 开灯,亮度60% |
$LED,OFF,0# | 关灯,亮度0 |
$STA,ON,80# | 设备主动上报当前状态:开,亮度80% |
$NET,OFF# | ESP8266通知STM32:网络已断开 |
定这个协议时需要注意几点。第一,亮度参数范围统一用0到100,不要用0到255,因为App端和用户交互时用百分比更直观,STM32端解析后自己再映射到PWM的占位比。第二,每条指令都以#结尾,STM32收到#就知道一帧结束,不需要依赖固定长度,这种设计对不定长指令非常友好。第三,状态上报指令$STA是由STM32主动发给ESP8266的,ESP8266收到后再通过Blinker的Blinker.print()把状态推送到手机App——这个机制用来实现App和设备状态同步,避免App显示的是旧状态。
协议里还有一个容易忽略的点:校验。短帧在室内的干扰下出错的概率很低,但为了答辩时能说「我做了可靠性设计」,加一个简单的累加和校验是个低成本高收益的做法。帧格式变成$LED,ON,100,校验和#,校验和就是前面所有字符ASCII码之和的低字节。当然,如果你的串口线很短、环境也不太恶劣,先不加校验也能跑通,等出问题再补上也不迟。
4.2 STM32串口接收解析与PWM亮度控制
STM32这边的代码按HAL库来写,工程可以用STM32CubeMX生成,也可以用Keil MDK手工建标准库工程。对物联网毕业设计来说,我更推荐HAL库,因为CubeMX生成的初始化代码不容易漏配置。串口接收用中断方式,关键代码是中断回调函数:
uint8_t rx_temp; uint8_t rx_buf[64]; uint8_t rx_index = 0; volatile uint8_t frame_ready = 0; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART1) { if (rx_temp == '#') { rx_buf[rx_index] = '\0'; frame_ready = 1; rx_index = 0; } else { if (rx_index < 63) { rx_buf[rx_index++] = rx_temp; } } HAL_UART_Receive_IT(&huart1, &rx_temp, 1); } }这段代码的逻辑说明:HAL_UART_Receive_IT启动的是单字节接收中断,每收到一个字节进一次回调,收完立即重新开启下一次接收,形成连续接收链。rx_temp是当前收到的字节,如果它是#,就把一帧数据封存并置frame_ready标志;否则存入缓冲数组。这里最关键的设计是:中断回调里只做数据搬运和标志置位,绝对不做协议解析,更不做延时。
解析工作放在主循环里做:
uint8_t pwm_duty = 0; uint8_t led_on = 0; while (1) { if (frame_ready) { frame_ready = 0; if (strncmp(rx_buf, "$LED", 4) == 0) { if (strstr(rx_buf, "ON") != NULL) { led_on = 1; char *p = strrchr(rx_buf, ','); if (p != NULL) { pwm_duty = (uint8_t)atoi(p + 1); } } else { led_on = 0; pwm_duty = 0; } } if (led_on) { __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pwm_duty * 100); } else { __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 0); } } }这段代码的逻辑说明:strncmp(rx_buf, "$LED", 4)判断是否是LED控制指令,strstr(rx_buf, "ON")判断开灯还是关灯,strrchr定位到最后一个逗号,再用atoi取出亮度百分比。PWM占空比的设置通过__HAL_TIM_SET_COMPARE完成,把0到100的百分比映射到0到10000的计数周期——这里假定TIM2的PWM周期是10000,即20kHz左右的频率,具体取决于定时器时钟分频。如果是用标准库,对应函数是TIM_SetCompare2(TIM2, duty)。
关于PWM频率,这里有个参数选择要点:用于LED调光的PWM频率建议不低于1kHz。频率太低,人眼能看到明显的频闪;频率太高,如果用的LED驱动芯片是PT4115这类,它的开关速度可能跟不上,反而导致芯片发热。我一般把时基设为1kHz到20kHz之间,具体取多少看驱动芯片的数据手册。另外,__HAL_TIM_SET_COMPARE这个宏是HAL库里直接改写比较寄存器的快捷方式,比先停定时器再修改再重启要平滑得多,不会产生毛刺。
4.3 本地按键与离线兜底:断网时台灯不罢工
一个只靠App控制的台灯,演示时如果现场WiFi抽风,整台设备就变成废物了。所以我在设计里一定会保留本地按键控制,并且让本地控制具有和云端控制同等的优先级。按键接在PB0上,通过外部中断或轮询扫描检测。轮询扫描配合20ms消抖的写法更简单、也更抗干扰:
uint8_t key_last = 1; uint8_t key_current = 1; void key_scan(void) { key_current = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0); if (key_last == 1 && key_current == 0) { HAL_Delay(20); if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == 0) { led_on = !led_on; if (led_on) { pwm_duty = 80; __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pwm_duty * 100); } else { __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 0); } // 通过串口通知ESP8266上报状态 printf("$STA,%s,%d#\r\n", led_on ? "ON" : "OFF", pwm_duty); } } key_last = key_current; }这段代码的逻辑说明:内部上拉使得按键空闲时为高电平,按下接地变为低电平,所以用下降沿检测按键动作。HAL_Delay(20)做简单消抖,避免机械按键的抖动导致一次按下被识别成多次。按键按下后翻转led_on状态,并把当前状态通过串口主动上报——这一步是状态同步的关键,否则你在App上看到的开关状态和设备实际状态是反的。
离线兜底逻辑也很重要:STM32不一定非要等ESP8266发$NET,OFF#才知道断网,更稳妥的做法是定义心跳超时。比如ESP8266每2秒通过串口发一个$HB#心跳帧,STM32用定时器记录距上次心跳的时间,超过5秒就认为ESP8266离线,此时允许按键继续控制台灯,但暂停向串口发送上报指令——因为发了也没人转发。这种「云端控制和本地控制双通道、离线自动切换」的设计,答辩时提出来会很加分,因为它体现了你对系统可靠性的思考,而不仅仅是把功能跑通。
5. 常见问题与排查:从配网失败到通信掉线的对证
5.1 现象:App搜索不到设备,配网一直超时
整套系统里最容易让新手卡住的环节就是配网。现象是:ESP8266烧录了Blinker固件,串口日志停在WiFi Connecting,手机App点「配置WiFi」搜不到设备,或者搜到了但发密码没反应。
原因一般有三个方向。第一,路由器的WiFi开了5G频段,Blinker的SmartConfig只支持2.4G频段,手机连着5G WiFi时发配网广播,ESP8266收不到;第二,WiFi密码里包含特殊字符,或者SSID是隐藏的,SmartConfig模式下识别不了;第三,代码里的auth密钥不对,设备绑定不了云端。
解决方式按顺序试:先打开串口监视器确认真实状态,如果日志显示WiFi Connecting持续超过10秒,第一步确认手机也连在2.4G频段上;第二步换个手机热点试试,把热点名设成纯字母数字,密码也设成纯数字,排除特殊字符干扰;第三步重新复制App里的Secret Key,注意不要多拷贝空格。如果是AP模式配网,还要确认手机连的是ESP8266开的热点,而不是路由器的热点——这两个热点名字可能很像,容易连错。
5.2 现象:串口乱码,或者控制指令偶尔生效偶尔无效
台灯能连上云,App按钮也能触发ESP8266发串口消息,但STM32这边解析出来的内容不对,控制时灵时不灵,串口监视器里看到大段的$LED,ON,100#变成了$LED€ON€100€#之类的错乱字符。
原因有两个:第一,波特率不匹配。ESP8266的Blinker固件默认115200,STM32的串口如果配成9600或4800,数据必然乱码。这种现象在课设里极其常见——因为很多人之前用ESP8266做AT指令测试时把固件波特率改成了9600,刷回Blinker库后忘了改回来。第二,共地没做好。STM32和ESP8266各自用独立的USB供电,但两个板子的GND没有连在一起,串口信号在电平参考点不一致的情况下会出现随机丢字节。
解决方式:统一两边波特率为115200,STM32的USART1初始化里把BaudRate设为115200;确保两块板子用一根杜邦线把GND连在一起;还有一个容易被忽略的细节是串口线的长度和质量——杜邦线超过20cm且走线靠近电源线时,干扰会明显增大,尽量缩短并让信号线和电源线分开走。
5.3 现象:ESP8266反复重启,或者连上WiFi后几秒就掉线
这个现象在Demo现场特别尴尬:App上设备状态一会有、一会没,ESP8266的板载LED狂闪,甚至能听到模块重启的清脆声响。
最常见的原因是供电不足。ESP8266在发射WiFi数据包瞬间电流峰值可能超过300mA,USB口供电时,如果用的是电脑前置USB口或者老旧USB Hub,电压被拉低到3V以下,板载稳压器直接欠压复位。第二个原因是WiFi路由器开启了AP隔离,导致设备与手机虽然在同一个WiFi下,但数据链路不通,MQTT建立不起来。第三个原因是散热——有些NodeMCU长期运行后芯片过热也会触发看门狗重启。
排查时先看串口日志:如果反复出现Boot字样,优先怀疑供电,换一个带独立供电的USB口或者直接用5V/2A的手机充电器供电;如果日志显示WiFi连接成功但MQTT连不上,进路由器后台关掉AP隔离和多播过滤;如果模块摸上去烫手,加一个小散热片或者把位置移到通风处。供电问题还有一个血泪经验:不要用那种一分多的USB充电线同时给STM32和ESP8266供电,两者开机时序不一致,很容易一个起来了另一个还在反复重启。
5.4 现象:指令解析正常,PWM也输出了,但灯不亮或亮度不可调
串口日志显示STM32已经收到并解析了指令,用万用表或示波器也能看到PA0引脚有PWM波形,但LED灯就是不亮,或者亮度只有最高和最低两档,中间调不了。
原因大概率在驱动电路。如果用继电器做调光,继电器只能通断,不能调亮度,PWM信号经过继电器后变成忽开忽关,LED灯会频闪或者干脆不亮;如果用三极管驱动,基极驱动电阻没限流,三极管进入不了饱和区,灯也会工作在异常状态。
解决方式:调光方案改用MOS管或PT4115恒流驱动,PWM信号直接接MOS管的栅极或PT4115的DIM脚;检查PWM频率是否匹配驱动芯片的开关能力,PT4115的DIM脚支持100Hz到20kHz,超过20kHz可能无法正常工作。另外还有一个人容易忽略的「玄学」问题:有些LED灯具内部自带恒流驱动电路,外部再用PWM去调光会和内部的驱动打架,表现为调光范围极窄。遇到这种情况,直接替换成可调光的LED灯带或LED灯板再试。
5.5 现象:设备断电再上电后,App显示的状态与实际不一致
演示中出现频率很高的状况:演示前把台灯关灯断电,答辩时重新上电,App里显示的是上一次的「开灯」状态,但实际灯是灭的,或者反过来。原因很好理解——设备端没有做上电状态恢复,断电前的状态没有保存,而云端保留着最后一次上报的状态。
解决方式是在STM32里做一个掉电状态保存:每次PWM占空比变化时,把led_on和pwm_duty写入到STM32的备份寄存器或Flash模拟EEPROM区域。上电初始化时先读取保存值,再恢复PWM输出,上电完成后主动通过串口上报一次$STA指令给ESP8266,让App同步成真实状态。这样既解决了状态不一致,答辩时还能多讲一个「低功耗设计」的亮点。
6. 验证方法与进阶技巧:把演示从「能亮」做到「答辩稳」
6.1 用串口日志做端到端验证
验收这套系统,不要只看灯亮没亮,要看整条链路每一层的日志。我通常的做法是准备两个串口监视器窗口:一个端口连ESP8266,看Blinker库的MQTT消息日志;另一个端口连STM32的USART1,通过USB转TTL引出,看STM32的解析结果。在App上按一下按钮,观察两边的日志是否按预期打印。如果ESP8266收到了消息但STM32没动作,问题在串口链路或协议解析;如果ESP8266根本没收到消息,问题在云端或WiFi。这种「每一层都能用日志对证」的习惯,能让你在答辩现场给出的解释既有说服力又不像背书。
验证时还要专门测一遍离线场景:把路由器关掉,等ESP8266掉线,按本地按键确认台灯还能正常开关;然后再把路由器打开,观察设备是否自动重连,重连后App状态是否自动同步。这个测试要提前做,因为自动重连耗时有时比预期长,明确知道重连时间,演示时心里才有底。
6.2 进阶:定时任务与传感器联动
功能层面如果还有余力,有两个方向性价比最高。一个是定时开关:在STM32里用RTC实现本地定时,比如晚上10点自动调暗到30%,早上7点自动点亮——注意点灯科技App里的定时是云端定时,设备掉线时不执行,本地RTC不受网络影响,两者都能讲,但你要说清楚区别。另一个是传感器联动:在STM32上加一个ADC通道读光敏电阻,环境变暗时自动调到预设亮度,或者接一个HC-SR501人体红外模块,有人靠近自动亮灯、人走延时熄灭。这些模块都便宜,接线也就一两根,却能把系统从「手机遥控」提升到「智能感知」,对竞赛和实训的评分帮助很大。
做这套系统给我留下的一个深刻教训是:所有的通信问题,最后都是靠日志而不是靠猜解决的。我早期做串口中断时,在中断回调里顺手放了一句HAL_Delay,结果整个系统像中了邪一样卡顿,排查了两天才发现是阻塞了中断调度。从那以后我养成一个习惯:中断只置标志、主循环干活,凡是涉及两端通信,先拿串口日志对一遍再往下做。这个项目最大的价值不是那块会亮的台灯,而是你完整走过了一遍「主控+联网+云端」的物联网系统搭建流程。希望这篇笔记能帮你少踩几个坑,把演示做得更稳。
本文还有配套的精品资源,点击获取