☰
基于STM32的智能鸽子驯养系统:定时投喂与远程监测设计
2026/10/31 14:17:50 网站建设 项目流程

做这个智能鸽子驯养系统,起因特别朴实。我在鸽舍实际跑了一个多月,发现信鸽驯养里最磨人的不是飞行训练,而是喂食纪律:早上六点、傍晚五点,投喂时间和投喂量必须稳定,鸽子才会形成条件反射,愿意到点归巢落棚。人工喂食不是忘了就是量忽多忽少,出差几天整个节奏直接崩掉。所以这套基于STM32的系统,目标非常明确:定时定量投喂、检测鸽子是否落位、监测环境温湿度和光照、饲料余量不足时报警,再把运行状态通过手机远程看得到。

整套做下来是三件套交付:能跑的实物、完整的电路板、从原理图到测试记录的设计手册。适合两类人参考,一类是拿它当毕业设计的学生,一类是家里有鸽舍、想自己动手改造投喂流程的爱好者。无论哪类,核心都是把STM32的定时器、ADC、串口、I2C这些外设在一个真实场景里串起来,而不是点个流水灯就结束。

1. 系统整体设计与方案选型

1.1 驯养需求拆解:先把功能表列出来

动手画电路之前,我习惯先把使用场景走一遍,把"人每天做什么"翻译成"系统每天做什么"。鸽舍的实际流程是这样的:早晨固定时间喂食,鸽子听到声响落下来,吃完去家飞;傍晚再喂一次,然后归巢休息。期间人要观察鸽子状态、填料、检查水器、应激处理。

翻译成系统功能就是五件事。第一,定时投喂,早、晚两个时间点,投喂量可调。第二,落位检测,投喂前先确认鸽子是否在采食区,避免料放久了受潮或被麻雀吃掉。第三,环境监测,测温湿度、光照强度,光照太强需要拉遮阳帘,温度过高要开排风扇。第四,余量感知,料仓里还有多少饲料,低于阈值就上报提醒。第五,远程查看,通过手机能看到当前设备状态和历史记录。

这五个功能是主需求。我当时还留了两个扩展口,一个是风速传感器接定时器输入捕获测频率,一个是多鸽舍节点通过RS485组网。原因后面细说,但设计初期预留扩展比后期返工省太多事。

1.2 主控选型与资源分配逻辑

主控用了STM32F103C8T6,也就是最常见的"蓝板"。为什么选它而不是Arduino或者ESP32,有三个原因。第一,资源够用且不浪费,一个72MHz的Cortex-M3内核,64KB Flash、20KB RAM,跑裸机状态机绰绰有余。第二,外设种类全,这个项目要同时用到USART、I2C、SPI、ADC、定时器输入捕获、PWM输出,F103基本每个外设都有,适合做教学和毕设展示。第三,资料量巨大,无论是标准库还是HAL库,遇到问题网上全都有答案。

资源分配上我做了个确认表,避免写代码时候引脚冲突。串口1给WiFi模块ESP8266,串口2给RS485伺服电机,串口3留作调试打印。I2C1同时挂OLED和光照传感器BH1750,因为这两个器件地址不同,可以共存。ADC1的通道0给光敏电阻做备用,通道1给HX711称重(实际HX711更多用GPIO模拟时序)。定时器2做输入捕获测风速脉冲,定时器3做喂食状态机的时基,定时器4输出PWM给蜂鸣器。JTAG口只保留SWD,释放PA13、PA14以外的调试引脚。

1.3 供电拓扑和电路地线处理

供电这块踩过坑,顺序是:12V适配器输入,先用LM2596-5.0降到5V,再经AMS1117-3.3降到3.3V。为什么不用单级降压直接出3.3V,因为执行机构的逻辑不一样。28BYJ-48步进电机驱动板要5V,RS485的MAX485收发器要5V,ESP8266模块的电源也建议5V供电,板上逻辑全是3.3V,所以必须是一级5V、二级3.3V的双级结构。

地线处理是我这次最想强调的一点。HX711称重传感器属于微弱信号,对地弹和数字噪声非常敏感。我在PCB上把数字地和模拟地分开走,在HX711芯片附近用一个0欧电阻单点汇合。实测发现,如果不做单点汇合,HX711读出来的重量在步进电机动作的瞬间能跳几十克,做完单点汇合后波动控制在2克以内。这个细节很多参考设计不会说。

2. 硬件电路设计要点与外围接口

2.1 STM32最小系统与引脚规划

最小系统这部分,说实话很多人都会画,但每次出问题最多的地方也在这里。8MHz晶振配两个22pF负载电容,电容不要省,否则RTC跑偏、串口波特率有误差。NRST复位脚接10k上拉到3.3V,再对地接一个100nF电容。BOOT0和BOOT1各拉一个跳线,正常启动时BOOT0接地,需要ISP下载时拨到高。

引脚规划我做成了表,方便后面画PCB和写代码时反复对照。步进电机用PA0到PA3接ULN2003驱动板,这组引脚恰好和按键复用,所以我用了一个跳线座做切换。RS485接PA9和PA10,也就是USART1的TX和RX,注意485芯片的方向脚DE/RE接一个普通GPIO,我用PC13,控制发送和接收切换。超声波模块接PB8和PB9,TRIG输出、ECHO输入。DHT11单总线接PB10,10k上拉。OLED和BH1750共用I2C1,即PB6的SCL和PB7的SDA。

2.2 投料执行机构:步进电机与RS485伺服

投料机构是整套系统里最需要机械配合的部分。我用的方案是,料仓底部装一根螺旋下料器,由五线四相步进电机28BYJ-48带动。这个电机网上俗称"减速步进电机",内部自带1:64减速箱,输出扭矩大约0.3kg·cm,带动小螺旋杆完全够用。驱动板就是最常见的ULN2003八引脚小板,公共端接5V,IN1到IN4接STM32的四个GPIO。

四相八拍的驱动顺序是IN1、IN1+IN2、IN2、IN2+IN3、IN3、IN3+IN4、IN4、IN4+IN1,循环执行。每个拍子之间延时1到2ms,电机转速稳定且不会丢步。这里有个关键计算:28BYJ-48电机在四相八拍下一圈需要4096个脉冲,螺旋杆每转一圈大约下料1.5到2克。目标投喂量20克,我就把步进圈数定在14圈,对应约57344个脉冲,留出一点余量,防止不同批次饲料密度差异导致投喂不足。

舱门和遮阳帘我用的是RS485总线的伺服电机,具体型号是带Modbus RTU协议的24V直流伺服,通过控制寄存器实现正反转和角度位置控制。STM32这边接了一个MAX485芯片,DI接串口TX、RO接串口RX、DE和RE短接后接方向控制脚。发送数据前把方向脚拉高,发送完必须拉低回到接收状态,否则总线上会一直占着主导电平,其他节点全部瘫痪。

2.3 感知层电路:超声测距、HX711称重、温湿度与光照

落位检测用HC-SR04超声波模块。模块工作电压5V,但回传的ECHO引脚也是5V电平,直接接STM32会有灌电流风险。我加了一个简单分压电阻,ECHO输出串1k电阻后进PB9,同时在PB9对地接一个2.2k电阻,把5V拉到3.3V左右。TRIG引脚是输入型,STM32的3.3V高电平足够触发,不用加电平转换。

称重模块用HX711+5kg悬臂梁传感器,接在料仓底部。HX711的DOUT和SCK引脚直接接GPIO模拟时序,不需要硬件I2C。我重点说一下读取时序,DOUT为低时表示数据准备好,这时SCK输出24个脉冲,每个脉冲的下降沿读取一位数据,顺序是从高位到低位。读完24位后,SCK再多输出1到25个脉冲可以切换通道和增益,常用的是128倍增益,也就是输出25个脉冲并保持在第25个。实际代码里,这个芯片读出来的原始值要先做去皮和标定,用标准砝码测出斜率和零点,再换算成克数。

温湿度用DHT11,单总线协议,数据线要接10k上拉到3.3V。光照用BH1750,I2C接口,它和OLED共存于同一总线,地址不同不会冲突。需要注意BH1750上电后要发一条Power On命令,再发一次连续高分辨率模式命令,之后才能读到有效数据。

2.4 人机交互与通信电路:按键、OLED、ESP8266

交互部分做了三个实体按键:模式键、加键、减键。按键电路很简单,每个按键一端接GND,另一端接GPIO并外接10k上拉电阻。为什么不直接接3.3V做下拉,因为STM32内部可以开启上拉,但外部上拉更稳,避免引脚配置错了导致按键电平不确定。软件里做20ms消抖,按下一次只响应一次。

显示用的0.96寸I2C OLED,128x64分辨率,单色蓝。它只能显示字符和简单的图形,所以我做了三个页面:主页面显示温湿度和光照,第二页显示饲料余量和下料次数,第三页显示当前模式和各扩展口状态。页面切换用模式键,加减键在设置页面改参数。

远程通信用ESP8266-01S模块,接串口1。模块出厂带AT固件,我用AT指令操作为主。为了省电,模块平时处于断电状态,每天早上投喂前先上电联网,上报一次状态后就继续断电。这个设计能明显降低系统功耗,也减少WiFi对传感器的电磁干扰。如果不需要远程上报,这个模块可以直接不焊,整套系统照常运行。

3. 软件架构与核心模块实现

3.1 工程搭建:从Keil标准库到VSCode调试

软件工程我一开始用的Keil MDK+标准库,因为参考代码最多,调试最直观。新建工程的步骤是:先选芯片型号STM32F103C8,然后在Manage Run-Time Environment里勾选CMSIS的CORE和Device的Startup,接着添加标准库的源码文件,主要是src目录下的stm32f10x_gpio.c、stm32f10x_tim.c、stm32f10x_usart.c这些用得到的模块。

关键一步是在C/C++选项卡的Define里写上USE_STDPERIPH_DRIVER, STM32F10X_MD,不加这两个宏,编译器会把整个标准库文件全部编译进去,Flash直接爆掉。系统主频72MHz,8MHz外部晶振经PLL倍频9倍得到。

后来我换到了VSCode+PlatformIO,工程管理更清晰。一个platformio.ini就能搞定编译器、上传和串口监视器,配置如下。

[env:bluepill_f103c8] platform = ststm32 board = bluepill_f103c8 framework = stm32cube upload_protocol = stlink debug_tool = stlink

用VSCode调试时,我建议直接装Cortex-Debug插件,配合St-Link的SWD接口,可以在代码里打断点看变量。注意launch.json里device字段要填stlink的序列号或接口类型,svdFile填芯片的SVD文件,这样才能在调试窗口看到外设寄存器的实时值。实际调电机时序时,我就是靠断点确认状态机跳转和步进脉冲计数的。

3.2 喂食状态机与定时策略

整个控制逻辑我写成状态机,比裸用延时循环靠谱太多。状态机五态:空闲、检测、投喂、进食、休眠。空闲态持续巡检时间和传感器;时间到了进入检测态,超声波先看采食区有没有鸽子;确认落位后进入投喂态,步进电机按设定圈数转动;投喂完成进入进食态,等待30分钟让鸽子吃完;最后回到空闲态。整个流程用定时器3做10ms软件时基轮询,不阻塞主循环。

typedef enum { ST_IDLE, ST_DETECT, ST_FEED, ST_SETTLE, ST_SLEEP } feed_state_t; feed_state_t state = ST_IDLE; uint32_t feed_remain_pulse = 0; switch (state) { case ST_IDLE: if (feed_time_reached()) state = ST_DETECT; break; case ST_DETECT: if (bird_on_perch()) { feed_remain_pulse = FEED_CIRCLE * PULSES_PER_REV; state = ST_FEED; } break; case ST_FEED: if (feed_remain_pulse > 0) feed_remain_pulse--; else state = ST_SETTLE; break; case ST_SETTLE: if (settle_timeout()) state = ST_IDLE; break; }

定时投喂我不用RTC芯片,而是用STM32内部定时器累计秒数,断电后恢复出厂默认时间并重新计时。虽然精确度不如带电池的DS3231,但对喂食场景足够。DS3231可作为扩展选项,留着I2C地址不冲突,随时可以焊上。

3.3 步进电机控制与超声波落位检测

步进电机控制封装成了一个函数,每次调用走一拍,外部传入目标脉冲数。核心是要保证中断处理不打断步进输出,否则会产生毛刺导致电机抖一下。我在进入投喂态时暂时挂起低优先级中断,投喂结束再恢复。这个细节我在实际调试中发现很重要,因为ESP8266串口接收中断和超声波测距中断频率都很高,一旦在步进换相瞬间被打断,电机就会停在错误的角度。

超声波落位检测是另一个需要防误触发的点。我的做法是:每2秒触发一次TRIG,收到ECHO返回后算出距离,连续3次测距结果都在40厘米以内,才判定鸽子落位成功。为什么这么设计,因为鸽子在采食区上空飞过时,超声波反射面是移动的,测距值会剧烈跳动,只有稳定站在食槽前时读数才稳定。判定条件里我加了稳定窗口,也就是3次读数极差小于5厘米才算数。

测距公式很简单:distance_cm = echo_time_us * 340 / 2 / 1000,如果ECHO时间超过50ms,直接按超时处理,认为无遮挡。HC-SR04最大量程4米,实测在鸽舍环境下可靠量程大概2.5米左右,超过这个距离反射信号衰减太严重。

3.4 OLED界面与巴法云远程上报

OLED驱动我直接用现成的u8g2库改的,底层写了一个I2C字节发送函数。显示逻辑刷主页面时,我每500ms刷新一次数据区文字,减少闪烁,也降低CPU占用。页面内容按固定坐标排版,比如温度显示在第一行右侧,湿度在第二行,光照在第三行,饲料余量在第四行。

远程上报我用的是巴法云平台。贝法云是一个免费的MQTT物联网云服务,注册后每个设备有一个独立私钥,通过HTTP GET就能上报数据。STM32端ESP8266的AT指令流程是这样的:先AT+CWMODE=1设置Station模式,AT+CWJAP连接WiFi,AT+CIPSTART建立TCP连接到api.bemfa.com的80端口,这里把80端口和连接的字符串拼在一起。建立连接后发送HTTP请求:

char req[160]; snprintf(req, sizeof(req), "GET /api/device/%s/%s HTTP/1.1\r\n" "Host: api.bemfa.com\r\n" "Connection: close\r\n\r\n", device_uid, status_msg);

其中device_uid是巴法云后台生成的私钥,status_msg是上报内容,比如"temp:26.5,humi:58,feed:1234,remain:3200"。发送前用AT+CIPSEND加长度,服务器返回OK后发数据。实测从STM32发出指令到云端显示更新,耗时大约300毫秒,对喂食监控来说完全够。

模块心跳是坑。贝法云要求设备每30秒发一次心跳保活连接,我只在每天固定时间上报,所以每次上报都重新建立TCP连接,不用保持长连接,反而更省心,不用考虑断线重连逻辑。如果你要多节点实时在线,那就得做好定时心跳和断线重连。

4. 调试实录与常见问题排查

4.1 超声波模块风雨天误触发的处理

这个坑我印象最深。装到鸽舍第二天刮大风,暴雨,系统一上午触发了十几次投喂,料仓差点空了。排查发现是超声波模块在大风和雨滴环境下收到大量杂散反射,Echo引脚输出一串不规则的脉冲,软件直接把它当成障碍物距离。

处理办法有三层。第一层是硬件上加防护,模块正面贴一层透明薄膜防雨滴直接溅到探头,探头顶部加一个倾斜的挡雨檐。第二层是软件滤波,连续3次测距取中位值,单次突变超过20厘米的读数直接丢弃。第三层是给判定逻辑加最小持续时间,要求连续判定落位成功维持1秒以上才进入投喂,不是03次瞬时满足就动作。这样改完之后的两个月,再没有出现过误触发。

4.2 五线四相步进电机失步的根治办法

投料机构刚开始试机时频繁失步,症状是电机转十几圈自己停了,或者转到半程咔咔响反向抖动。用示波器看脉冲波形后定位到两个原因。

第一个是电源问题,ULN2003驱动板供电电压不足。5V电源来自LM2596,但步进电机启动瞬间电流冲击大,如果5V线上并了太多其他负载,电压会跌到4.4V以下,驱动板的输出就没劲了。解决办法是给驱动板单独走线,线径加粗,且在5V输出端加大470uF电解电容,实测电压跌落从0.6V降到0.15V。

第二个是换相时序和中断冲突。之前也说过,当串口中断在换相瞬间插入时,IN1到IN4的电平组合会停留两拍的时间,电机就出鬼了。我在步进输出函数里加了临界区保护,把所有全局中断暂时关掉,完成一拍后再打开。注意关中断时间不能超过50微秒,否则串口接收会丢字节。这个方案对裸机程序是有效的,如果你用FreeRTOS,那就得用带互斥锁的任务保护了。

4.3 RS485总线故障与ILI9341读ID异常的排查

RS485伺服电机联调时出现过"连不上"的情况——明明昨天还能动,今天上位机怎么发指令都没反应。排查流程分享出来:先用万用表测总线两端的差分电压,正常静态时AB之间应该至少有200mV偏置电压,如果接近0V,说明总线空闲电平不对,检查收发器供电和终端电阻。我的板子就是终端电阻忘焊了,导致信号反射,距离超过1米就收到乱码。补上120欧终端电阻后问题解决。

另外注意DE/RE方向脚切换要加延时,发送完最后一个字节后必须等待200微秒再把方向切回接收,否则尾字节会被截断,CRC校验失败,伺服不动作。

ILI9341屏幕读ID是0xA1A1这个问题,我在另一块屏幕调试时遇到过。现象是发送读ID指令0x04后,模块返回0xA1A1而不是0x9341。这不是硬件坏了,通常是初始化时序不对。ILI9341在SPI接口下刚上电时处于待初始化状态,直接读ID得到的不是有效ID,必须先发送一整套初始化序列,包括0x01软件复位、0x11退出睡眠、0x36设置扫描方向、0x3A设置像素格式、0x20关闭反色等,等到稳定后再读ID。另外SPI速度也要压下来,预分频调到64或以上,毕竟ILI9341的SPI最大时钟在10MHz附近,你给到18MHz就会读到乱码。

4.4 下载调试与固件升级的几个坑

调试口这部分的坑特别基础但特别容易踩。有一次我为了省引脚,在代码里调用了GPIO_Remap_SWJ_Disable(),想释放JTAG引脚做普通IO。结果烧完程序之后,SWD也连不上了,因为SWD是JTAG的一部分,全部禁掉就彻底锁死。正确做法是用GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE),只禁JTAG保留SWD。万一真锁死了,把BOOT0拉高、BOOT1拉低,重新上电后通过串口ISP擦除Flash,就能恢复下载。

VSCode调试时我遇到过launch.json配置文件不对导致连不上目标的问题。Cortex-Debug的关键配置是device字段要写stlink,interface写swd,servertype填stlink,svdFile路径要指到你芯片的SVD文件。如果上面都对还是无法连接,检查St-Link驱动是否安装,以及目标板上的NRST复位脚是否外接了其他设备。

5. 设计手册归档与联调验收

5.1 设计手册的材料清单与组织结构

做实物项目最容易忽略的就是设计手册,但评判一个项目是否可复现,手册比代码更重要。我的设计手册一共五个章节。第一是系统概述和功能指标,写明性能参数测量方法和结果,比如投喂精度、测距误差、上报成功率。第二是硬件设计,包含原理图PDF、PCB布板说明、元器件BOM表,BOM表里每个器件标注位号、型号、封装、数量、采购参考价格。第三是引脚分配表,把STM32所有占用引脚全部列出,注明功能、电气特性和外设复用。第四是软件设计,说明工程结构、状态机、各模块API函数接口和使用方法。第五是测试记录,包括每个功能模块的测试方法、测试数据、遗留问题和后续优化空间。

我在PCB上把所有测试点都标注了丝印,比如5V、3.3V、GND、PW1、PW2这些,方便联调用万用表直接测量。这个习惯让后期维修速度快非常多,不用对着原理图去找焊点。

5.2 上电联调顺序与最终验收清单

联调顺序我建议严格按"电源->最小系统->外设->整机"四步走,别上来就全部焊完再调。先空板焊好电源部分,上电量LM2596输出是否是5V,AMS1117输出是否是3.3V,电压不稳先别往下走。接着焊STM32和晶振复位电路,用ST-Link连接确认能识别到芯片。

然后是传感器逐个调试:先接OLED,能显示字符说明I2C总线正常;再接DHT11和BH1750,串口打印数据;再接超声波,对着墙面看测距值是否准确;再接HX711,用标准砝码标定重量。执行机构放最后,因为螺丝松了、皮带打滑这类机械问题会掩盖电气问题。

最终验收我是按这张表逐项打钩的:定时投喂时间误差不超过5分钟;投喂量误差不超过设定值的10%;落位检测成功率不低于95%;云平台上报成功率不低于90%;断电重启后系统能自动恢复待机状态;按键操作响应时间小于200ms;整机连续运行72小时无死机。全部通过后,整套系统才算验收完成。

最后再分享一个我做这类项目的习惯。实物做完之后,我会把整个项目资料打包成三层目录:原理图放在hardware,固件源码放在firmware,设计手册放在docs,每个目录里再加一个README说明文件结构和版本记录。这样不仅自己三个月后还能重新捡起来维护,别人拿到这份资料也能照着复现。做嵌入式小系统,最大的成就感其实是把一堆散乱的模块、线缆、代码捏合成一个能稳定运行的东西,这套驯养系统从第一天到现在,已经在鸽舍连续跑了两个月,唯一需要人工介入的就是给料仓加饲料。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询