
1. 项目缘起与整体设计思路1.1 为什么选择巡检小车这个方向实验室巡检这件事做过的人都知道有多枯燥。每天晚上十点值班的人要挨个检查每间实验室的温湿度、设备运行状态、门窗是否关好一圈走下来至少二十分钟遇到楼层多、房间分散的实验室群半小时都打不住。更麻烦的是人工巡检的记录往往靠手写数据零散、难以追溯出了问题想查历史记录基本靠翻本子。我最初做这个项目的动机很朴素能不能让一台小车替人跑腿把温湿度数据自动采集回来顺便把现场画面传回来人在值班室就能完成巡检这个想法落地之后就形成了现在这套基于单片机的实验室巡检遥控小车方案。它的核心能力有三个远程遥控移动、环境数据采集温湿度、数据回传与本地显示。适合谁参考我觉得有三类人一是正在做嵌入式课程设计或毕业设计的同学这个项目覆盖了单片机最小系统、传感器驱动、无线通信、电机控制、显示模块等典型知识点是一个麻雀虽小五脏俱全的综合项目二是想入门嵌入式但不知道做什么练手的初学者这套方案硬件成本低、资料多、坑也典型三是需要做小型移动监测平台的工程人员可以把它当作一个原型验证。1.2 主控选型为什么是STM32F103C8T6主控芯片的选择直接决定了整个项目的开发难度和成本上限。市面上常见的候选有三类51单片机、STM32F103C8T6、以及更高端的STM32F4系列。51单片机比如STC89C52便宜、资料多但它的短板在巡检小车上会被放大IO口少、RAM小、没有硬件PWM、串口只有一个接上温湿度传感器、无线模块、电机驱动、显示屏之后资源基本就捉襟见肘了。而且51的定时器精度和中断响应速度在做电机调速和无线数据收发并发时会比较吃力。STM32F4系列性能强但对这个项目来说是杀鸡用牛刀价格也上去了最小系统板动辄三四十块还不算外围。STM32F103C8T6刚好卡在甜点位置72MHz主频、64KB Flash、20KB RAM、3个USART、多个定时器和PWM通道资源足够跑完整个项目还有富余最小系统板价格普遍在十元上下性价比极高更关键的是它的资料生态极其丰富标准库、HAL库都有大量现成例程遇到问题几乎都能搜到答案。所以这个项目我最终锁定STM32F103C8T6作为主控。1.3 无线方案ESP8266的角色定位无线通信这块我选的是ESP8266模块。这里要澄清一个常见误区很多人以为ESP8266只能用来连WiFi上云其实它也可以工作在透传模式下当作一个串口无线桥使用单片机通过串口发AT指令就能收发数据。我选它的理由有三点。第一成本低一个ESP-01S模块几块钱第二它同时支持AP模式和STA模式既可以自己建热点让手机直连也可以接入实验室现有路由器灵活性高第三AT指令集成熟配合STM32的串口中断收发代码量不大。注意ESP8266的供电是很多新手翻车的地方。它的瞬时电流峰值能到300mA以上如果直接用STM32最小系统板上的3.3V稳压输出给它供电很容易出现模块反复重启、AT指令无响应的问题。务必给它单独一路3.3V稳压或者用质量好的降压模块。1.4 整体架构拆解整个系统可以分成四个层次来理解这样后面调试的时候思路会清晰很多感知层DHT11温湿度传感器负责采集环境数据。控制层STM32F103C8T6主控负责调度所有外设、处理数据、执行指令。通信层ESP8266无线模块负责与上位机手机或电脑双向通信。执行与显示层L298N电机驱动直流减速电机负责移动LCD1602负责本地数据显示。数据流向是这样的DHT11采集温湿度 → STM32读取并处理 → 一路送LCD1602本地显示一路通过ESP8266发到上位机同时上位机下发的移动指令 → ESP8266接收 → STM32解析 → 驱动L298N控制电机。这个采集-处理-显示-上传-执行的闭环就是巡检小车的核心逻辑。2. 硬件选型与关键细节解析2.1 核心元器件清单与选型理由先把整套硬件清单列出来方便你直接照着采购。下面这张表是我实际用过的配置价格是常见市场价供参考。模块型号数量参考单价选型理由主控板STM32F103C8T6最小系统板110-15元资源充足、生态好、性价比高无线模块ESP8266ESP-01S16-10元成本低、AT指令成熟、支持AP/STA温湿度传感器DHT1113-5元单总线、驱动简单、够用显示模块LCD1602带I2C转接板18-12元显示直观、I2C省IO口电机驱动L298N16-10元双路H桥、驱动能力强、资料多直流减速电机TT马达轮子25-8元/个扭矩够、便宜、配套轮子好买车体底盘亚克力双层底盘115-25元结构稳定、孔位标准电源18650锂电池×2 电池盒1套15-20元供电充足、可充电降压模块LM2596可调降压13-5元给ESP8266单独稳压整套下来成本大概在80到120元之间对学生党非常友好。2.2 STM32F103C8T6最小系统板的关键引脚分配引脚分配是硬件设计里最容易埋雷的环节一旦分配冲突后面改起来很痛苦。我建议在动手焊接之前先在纸上把引脚规划清楚。下面是我这套方案的引脚分配经过实测没有冲突功能引脚说明DHT11数据线PA0单总线需上拉电阻LCD1602 SCLPB6I2C1时钟LCD1602 SDAPB7I2C1数据ESP8266 TX→STM32 RXPA10USART1_RXESP8266 RX→STM32 TXPA9USART1_TXL298N IN1PB0左电机方向1L298N IN2PB1左电机方向2L298N IN3PB4右电机方向1L298N IN4PB5右电机方向2L298N ENAPA6左电机PWMTIM3_CH1L298N ENBPA7右电机PWMTIM3_CH2这里有几个细节值得展开说。第一DHT11的数据线一定要接上拉电阻通常4.7K到10K都可以我用的4.7K。因为DHT11是单总线开漏结构没有上拉的话数据线拉不高读出来的全是0或者直接超时。第二ESP8266和STM32的串口要交叉连接模块的TX接单片机的RX模块的RX接单片机的TX这个新手特别容易接反。第三PWM引脚要选带定时器通道的PA6和PA7对应TIM3的通道1和通道2这样两路电机调速可以共用一个定时器代码简洁。2.3 电源系统的设计要点电源是移动小车最容易被忽视、也最容易出问题的部分。我踩过的坑是一开始图省事用两节18650串联得到7.4V直接给L298N供电然后用L298N板载的5V输出给STM32供电再用STM32板上的3.3V给ESP8266供电。结果小车一动起来ESP8266就掉线。原因很简单电机启动瞬间电流很大会把整条电源线的电压拉低ESP8266对电压波动极其敏感一掉压就重启。后来我改成三路独立供电18650电池组直接给L298N的电机供电端一路LM2596降压到5V给STM32另一路LM2596降压到3.3V单独给ESP8266。这样电机再怎么折腾也不会影响通信模块的供电稳定性。提示如果你不想用两片降压模块至少也要保证ESP8266和电机不共用同一条电源支路。在ESP8266的电源脚旁边并一个100uF以上的电解电容也能明显改善掉线问题。2.4 DHT11与LCD1602的驱动特性DHT11是单总线数字温湿度传感器测量范围温度0到50摄氏度、湿度20%到90%RH精度分别是正负2摄氏度和正负5%RH。它的通信协议是单总线一次完整读取大概需要4到5毫秒时序要求比较严格微秒级的延时不能差太多。所以驱动DHT11的时候延时函数一定要用定时器或者精确的微秒延时不能用粗略的循环延时。LCD1602我强烈建议用带I2C转接板的版本。标准LCD1602是并行接口要占用6到7个IO口接线又多又乱。加了I2C转接板之后只需要SCL和SDA两根线占用IO少接线清爽代码上调用现成的I2C库也简单。转接板上的电位器用来调对比度如果屏幕亮着但看不到字八成是对比度没调好。3. 软件架构与核心代码实现3.1 工程搭建基于标准库的STM32工程模板我用的开发环境是Keil MDK库选择的是STM32标准库而不是HAL库。原因很实际标准库的代码结构清晰、寄存器操作直观对于学习单片机原理的人来说更容易理解底层而且网上针对F103C8T6的标准库例程最多遇到问题好查。HAL库虽然移植性好但层层封装之后初学者反而看不清外设到底是怎么工作的。搭建工程模板的步骤大致是这样先建好文件夹结构把标准库的启动文件、CMSIS核心文件、外设驱动文件、以及自己的用户代码分目录放好然后在Keil里新建工程选好芯片型号STM32F103C8接着把需要的库文件添加到工程分组里最后在工程选项里配置好头文件包含路径和宏定义比如USE_STDPERIPH_DRIVER。这套模板建好之后可以反复用后面做别的F103项目直接复制就行。注意STM32F103C8T6的Flash是64KBKeil里默认的器件配置有时候会按128KB处理下载时如果报错检查一下工程选项里的Flash算法和实际容量是否匹配。3.2 DHT11温湿度采集的时序实现DHT11的读取流程分三步主机发送起始信号、DHT11响应、数据传输。起始信号是主机把数据线拉低至少18毫秒然后拉高20到40微秒接着释放总线等待DHT11响应。DHT11会先拉低80微秒再拉高80微秒表示响应之后开始传输40位数据。这40位数据里前16位是湿度整数和小数中间16位是温度整数和小数最后8位是校验和。校验规则是前四个字节相加的低8位等于校验和不相等就说明数据出错要重新读取。代码实现上关键点在于微秒级延时的准确性和读取引脚电平的时机。我一般用定时器做一个微秒延时函数然后在读取每一位数据时先等数据线变高延时40微秒后采样高电平就是1低电平就是0。整个读取过程要关中断避免被其他中断打断导致时序错乱。// DHT11读取核心逻辑示意 uint8_t DHT11_ReadByte(void) { uint8_t i, byte 0; for (i 0; i 8; i) { while (!DHT11_PIN); // 等待50us低电平结束 delay_us(40); // 延时40us判断高电平持续时间 byte 1; if (DHT11_PIN) byte | 1; while (DHT11_PIN); // 等待高电平结束 } return byte; }实测下来DHT11的读取间隔不能太短官方建议至少间隔1秒以上我一般设成2秒读一次数据比较稳定。读太快不仅数据不准还容易读失败。3.3 ESP8266的AT指令配置与透传模式ESP8266的配置是整个项目里最需要耐心的部分。我把它分成两种工作模式来讲你可以根据实际需求选。AP模式ESP8266自己建一个热点手机直接连这个热点就能通信。优点是部署简单不需要实验室有路由器缺点是通信距离有限而且手机连上之后就没法上网了。配置指令大致是设置AP模式、设置热点名称和密码、开启多连接、建立TCP服务器。STA模式ESP8266接入实验室现有的路由器手机和它连同一个路由器通过IP地址通信。优点是能接入现有网络、距离远缺点是需要知道路由器信息配置稍复杂。配置过程中最容易卡住的地方是AT指令的响应判断。ESP8266每条指令返回的OK不是立刻来的需要给足等待时间一般设500毫秒到1秒比较稳妥。如果循环里检测不到OK就死等很容易进死循环。我的做法是加超时机制等不到就重发重发三次还不行就复位模块重新配置。// AT指令发送与响应等待示意 uint8_t ESP_SendAT(char *cmd, char *expect, uint16_t timeout) { USART_SendString(USART1, cmd); while (timeout--) { if (USART_ReceiveContains(expect)) return 1; delay_ms(1); } return 0; // 超时 }提示如果ESP8266怎么都不响应AT指令先检查波特率。新模块默认波特率通常是115200但有些批次是9600。另外如果之前配置过透传模式模块可能还在透传状态发AT指令没反应这时候需要先退出透传发注意前后要留时间间隔或者直接ATRESTORE恢复出厂设置。3.4 电机PWM调速与运动控制L298N驱动直流电机每个电机需要三根控制线两根方向线加一根使能线。方向线决定正转反转使能线接PWM决定转速。STM32这边用TIM3产生两路PWM频率我设的是1kHz左右这个频率下电机运行平稳、噪音也不大。运动控制逻辑封装成几个函数前进、后退、左转、右转、停止。前进就是两个电机都正转后退都反转左转是左轮反转右轮正转原地转右转反之。调速的话通过改变PWM的占空比来实现占空比越高转速越快。// 运动控制函数示意 void Car_Forward(uint8_t speed) { GPIO_SetBits(GPIOB, GPIO_Pin_0); // 左轮正转 GPIO_ResetBits(GPIOB, GPIO_Pin_1); GPIO_SetBits(GPIOB, GPIO_Pin_4); // 右轮正转 GPIO_ResetBits(GPIOB, GPIO_Pin_5); TIM_SetCompare1(TIM3, speed); // 左轮速度 TIM_SetCompare2(TIM3, speed); // 右轮速度 }实际调试时我发现两个电机即使型号相同同样的PWM占空比下转速也会有差异导致小车走不直。解决办法是给两个电机分别标定一个速度补偿系数走直线的时候右轮稍微给多一点或左轮少一点具体数值靠实测调。3.5 主循环的任务调度设计主循环的设计我采用的是时间片轮询的思路而不是把所有逻辑堆在一起。具体做法是用SysTick定时器产生1毫秒的基准节拍然后在主循环里根据计数值判断各个任务是否到了执行时间。温湿度采集每2000毫秒执行一次LCD刷新每500毫秒执行一次无线数据收发每50毫秒检查一次接收缓冲电机控制实时响应收到指令立即执行这样设计的好处是各任务互不阻塞不会因为DHT11读取的几毫秒延时导致无线数据丢包。如果用delay死等的方式通信和采集就会互相打架。4. 系统联调与常见问题排查4.1 分模块调试的顺序建议我强烈建议不要一次性把所有模块焊好再上电那样出了问题根本不知道是哪一块的锅。正确的顺序是先单独调通STM32最小系统能下载、能点灯再单独调DHT11能读出合理数据再单独调LCD1602能显示字符再单独调ESP8266能收发AT指令最后调电机能转、能调速全部单独通了之后再整合。整合的时候也要一步步来先整合主控显示再整合主控传感器显示再整合主控无线最后加上电机。每加一个模块就测一次问题定位会快很多。4.2 常见问题速查表下面这张表是我在实际调试中遇到过的典型问题整理出来供你对照排查。现象可能原因排查与解决DHT11读数全是0或255上拉电阻缺失、时序不准加4.7K上拉检查微秒延时DHT11偶尔读失败读取间隔太短、中断干扰间隔拉到2秒读取时关中断LCD1602亮但无字对比度没调好、I2C地址错调电位器扫描I2C地址ESP8266无AT响应波特率不对、处于透传态试9600/115200发退出透传ESP8266频繁重启供电不足、电压波动单独3.3V供电加滤波电容小车走不直两电机转速不一致分别标定PWM补偿系数电机不转使能线没接、PWM没输出检查ENA/ENB示波器看PWM下载失败Flash配置错、BOOT跳线错检查器件容量BOOT0拉低4.3 无线通信丢包与延迟的处理无线通信在实际环境中丢包是常态尤其是实验室里设备多、WiFi信号杂2.4G频段干扰严重。我的处理思路是应用层加简单协议每条数据加上帧头和帧尾接收端校验帧结构不完整的直接丢弃关键指令比如停止加确认重传机制发出去等不到确认就重发。另外数据发送频率不要太高。温湿度这种慢变量2秒发一次足够了发太快反而增加丢包概率。控制指令可以实时发但要做好去重避免同一条指令重复执行导致小车动作异常。4.4 实测经验与避坑心得分享几个文档里不会写、但实际很关键的经验。第一电机和传感器要物理隔离。我一开始把DHT11装在电机旁边结果电机一转温湿度读数就飘。后来把传感器用排线引到车头远离电机的位置数据立刻稳定了。电机的电磁干扰和发热对传感器影响很大。第二电池电量要监控。18650电量低的时候电压会下降降压模块输出可能不稳导致各种莫名其妙的故障。我后来加了一个简单的电压检测电量低的时候让LCD显示提示避免小车半路罢工。第三代码里加看门狗。移动设备运行环境复杂程序跑飞的概率比固定设备高。开独立看门狗主循环里定期喂狗一旦程序卡死能自动复位可靠性提升明显。第四底盘重心要低。亚克力双层底盘把电池和电机放底层主控和传感器放上层重心低小车转弯不容易翻。我第一版把电池放顶层转弯稍快就侧翻调整之后稳多了。5. 功能扩展与进阶方向5.1 从遥控到半自主巡检现在这套方案是纯遥控的人得一直盯着。往半自主方向走可以加循迹模块或者超声波避障模块。循迹的话在实验室地面贴一条黑色胶带小车用红外对管循着走到指定点位停下来采集数据。避障的话车头装超声波检测到障碍自动停下或绕行。这两个扩展都不难循迹模块几块钱超声波模块也就几块钱但能让小车从玩具变成工具。5.2 数据上云与历史记录如果实验室有网络可以把ESP8266配置成STA模式接入路由器把温湿度数据通过MQTT协议发到云平台这样就能在手机或电脑上查看历史曲线还能设置阈值报警。这一步需要一点云平台的知识但ESP8266的MQTT AT指令是现成的配合云平台的设备接入文档一两天能跑通。5.3 加装摄像头做视觉巡检再往深了做可以在车上加一个摄像头模块把现场画面传回来。不过要注意图像数据量大ESP8266的带宽扛不住实时视频只能传低帧率的图片。如果要实时视频得换更强的通信方案成本和复杂度都会上一个台阶。对于课程设计来说传个静态图片证明能看到现场就足够了。5.4 低功耗优化思路如果希望小车续航更长可以从几个方面优化主控在空闲时进睡眠模式定时唤醒采集ESP8266不用的时候关掉射频电机只在移动时通电停下就断使能。这些优化能让续航从两三个小时延长到一整天但代码复杂度会上升建议先把基础功能做扎实再考虑。我个人在实际操作中的体会是这类嵌入式项目最大的价值不在于最后跑起来的那一下而在于调试过程中把每一个模块的脾气摸清楚。DHT11的时序、ESP8266的供电、电机的干扰这些坑踩过一遍你对整个系统的理解就完全不一样了。最后再分享一个小技巧每次改完硬件接线先用万用表把电源和地量一遍再上电能避免绝大多数一上电就冒烟的悲剧。