1. 项目缘起与整体设计思路
1.1 为什么会想到做鸽子驯养系统
养鸽子这件事,外行看热闹,内行看门道。我接触信鸽驯养差不多有六七年时间,从最开始在阳台搭个简易棚,到后来帮朋友做鸽舍环境改造,踩过的坑真不少。传统养鸽最大的问题就是“凭感觉”——什么时候喂、喂多少、鸽舍温湿度怎么样、光照够不够、鸽子归巢有没有记录,全靠人盯着。一旦养的数量上到几十只,或者白天要上班,根本顾不过来。
这个基于STM32的智能鸽子驯养系统,核心目标就是把“凭感觉”变成“看数据”。它要解决的具体问题有这么几个:第一,定时定量投喂,避免鸽子过胖或者抢食不均;第二,鸽舍环境监测,温度、湿度、光照、氨气浓度这些指标实时掌握;第三,归巢检测,通过红外或者RFID方式记录鸽子进出;第四,远程告警,环境异常或者设备故障时能及时知道。整套系统是实物级别的,包含电路设计、PCB打样、程序开发和一份完整的设计手册,适合电子类专业学生做毕业设计,也适合有一定动手能力的养鸽爱好者自己复现。
从技术选型上说,STM32是绕不开的选择。原因很直接:外设资源丰富、资料多、成本低、生态成熟。你要做定时器PWM控制电机、要做ADC采集传感器、要做USART串口通信、要做RTC实时时钟,STM32F103系列一颗芯片全搞定,价格还不到十块钱。相比之下,用51单片机做同样的事情,外设不够用,定时器精度也吃紧;用树莓派或者ESP32,成本上去了,而且对于纯控制类任务来说有点杀鸡用牛刀。所以这个项目的主控就定在STM32F103C8T6,也就是大家常说的“最小系统板”那颗芯片。
1.2 系统整体架构拆解
整个系统我把它分成四个层次来设计,这样思路清晰,后面调试也好定位问题。
感知层:负责采集环境数据和鸽子活动信息。包括DHT22温湿度传感器、光敏电阻模块、MQ-135氨气传感器、红外对射传感器(装在鸽舍入口用于归巢检测)。这些传感器输出的信号有数字的也有模拟的,数字的走GPIO,模拟的走ADC。
控制层:STM32主控负责所有逻辑判断和决策。它要读传感器数据、驱动执行机构、管理时间任务、处理串口通信。这里我用的是标准库开发,因为对于初学者来说,标准库比HAL库更直观,寄存器操作一目了然,而且网上资料多,遇到问题好查。
执行层:包括舵机控制的投喂机构、继电器控制的补光灯和排风扇、无源蜂鸣器做的声光告警。投喂机构我用的是SG90舵机加一个旋转料盘,舵机转一个角度就放出一份饲料,结构简单可靠。
交互层:一块0.96寸OLED显示屏做本地数据显示,一个EC11旋转编码器做参数设置,另外通过HC-05蓝牙模块或者CH340 USB转串口和上位机通信,把数据传到电脑或者手机上看。
这个架构的好处是模块化程度高,每个层之间通过明确的接口通信,调试的时候可以一层一层单独验证。比如你先单独测传感器读数对不对,再测舵机转动角度准不准,最后再联调。不要一上来就全部焊好写完整程序,那样出了问题你根本不知道是哪里的毛病。
1.3 关键设计决策与取舍
在方案设计阶段,有几个地方我反复权衡过,这里把思考过程分享出来,供大家参考。
第一个决策:投喂机构用舵机还是步进电机?舵机便宜、控制简单、扭矩够用,缺点是角度范围有限(一般0到180度),而且长时间堵转容易烧。步进电机精度高、可以连续旋转,但需要驱动器,成本和复杂度都上去了。考虑到投喂动作其实就是一个“转一个固定角度放料”的简单动作,舵机完全够用,所以选了舵机。实际用下来,SG90在5V供电下扭矩大约1.8kg·cm,带动一个直径8cm的塑料料盘毫无压力。
第二个决策:归巢检测用红外还是RFID?红外对射便宜,一对才几块钱,但只能检测“有东西经过”,不能区分是哪只鸽子。RFID可以给每只鸽子戴脚环,实现个体识别,但成本高,而且读写距离和方向性需要仔细调。这个项目定位是“驯养系统”而不是“赛鸽计时系统”,所以红外对射够用了。如果你要做赛鸽归巢计时,那必须上RFID,这是另一个量级的项目。
第三个决策:通信方式用蓝牙还是WiFi?蓝牙模块HC-05便宜、配对简单、手机APP开发也容易,缺点是传输距离短(10米左右),穿墙能力差。WiFi模块比如ESP8266可以联网、可以远程访问,但需要配置路由器,对不熟悉网络的人有门槛。考虑到鸽舍一般就在家里阳台或者楼顶,蓝牙距离够用,所以选了蓝牙。如果你鸽舍在郊区院子里,那还是上WiFi或者4G模块更靠谱。
第四个决策:电源方案怎么定?整个系统需要5V(舵机、传感器)、3.3V(STM32、OLED)两种电压。我用的是12V直流适配器输入,然后通过LM2596降压到5V,再用AMS1117-3.3降到3.3V。这里要注意,舵机启动瞬间电流可能冲到1A以上,所以5V这一路的电容要够大,我用了两个470uF电解电容并联,实测舵机动作时电压波动控制在0.2V以内。另外,STM32的ADC参考电压用的是VDDA,如果3.3V不稳,ADC读数就会跳,所以AMS1117输出端也加了100uF和0.1uF的滤波电容。
2. 核心电路设计与关键细节
2.1 STM32最小系统电路
最小系统是整个板子的心脏,这部分如果画错了,后面全白搭。STM32F103C8T6最小系统包含这几个部分:电源、复位、晶振、启动模式选择、调试接口。
电源部分,VDD和VSS引脚每一对都要加0.1uF去耦电容,这个不能省。我见过有人为了省事只在整板放一个104电容,结果ADC采集出来的数据跳得跟心电图一样。正确的做法是每个电源引脚旁边就近放一个0.1uF,然后整板再放一个10uF的钽电容做储能。
复位电路用经典的RC复位,10k电阻上拉到3.3V,100nF电容下拉到地,再加一个复位按键。这里有个细节:复位按键两端最好并联一个0.1uF电容做硬件消抖,虽然STM32内部有复位滤波,但外部加一个更稳妥。
晶振电路用8MHz无源晶振加两个20pF负载电容。负载电容的值不是随便选的,要根据晶振规格书上的负载电容CL来算。公式是:CL = (C1 * C2) / (C1 + C2) + Cstray,其中Cstray是PCB走线寄生电容,一般取3到5pF。如果晶振规格书要求CL=12pF,那么C1和C2大约取18到20pF。晶振尽量靠近芯片放置,走线尽量短,下面不要走其他信号线。
启动模式选择,BOOT0通过10k电阻下拉到地,BOOT1(也就是PB2)也下拉到地,这样默认从主闪存启动。如果你要串口下载程序,把BOOT0跳到3.3V,复位后进入系统存储器启动模式。
调试接口我留了SWD四针接口:3.3V、GND、SWDIO、SWCLK。SWD比JTAG省引脚,而且速度够用。这里注意,如果你在程序里禁用了JTAG但保留了SWD,需要调用GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE),这样PA15、PB3、PB4可以当普通GPIO用,同时SWD还能正常下载。
2.2 传感器接口电路设计
DHT22温湿度传感器是单总线协议,数据线需要接一个4.7k到10k的上拉电阻到3.3V。这个上拉电阻不能省,否则信号上升沿太慢,STM32读出来的数据全是错的。我一开始用10k,读数据偶尔失败,换成4.7k之后稳定了。另外DHT22的供电电压是3.3V到5V,我直接接3.3V,这样数据线电平匹配,不需要电平转换。
光敏电阻模块我用的是GL5528加一个10k分压电阻,输出模拟电压接到STM32的ADC引脚。这里有个坑:光敏电阻的阻值范围很大,暗电阻可能到1M欧,亮电阻只有几k欧,所以分压电阻选10k的话,暗光下ADC读数接近0,亮光下接近4095,动态范围还行。但如果你想要更线性的响应,可以用对数放大电路,不过对于“判断白天还是晚上”这个需求来说,简单的分压就够了。
MQ-135氨气传感器输出也是模拟电压,但它的输出阻抗比较高,直接接ADC引脚会导致采样不准。正确做法是加一个电压跟随器,用LM358运放搭一个同相放大器,增益设为1,起到阻抗匹配的作用。LM358便宜好买,但注意它的输出摆幅不能到轨到轨,所以供电要给5V,输出经过分压后再进ADC,或者直接用轨到轨运放比如MCP6002。
红外对射传感器我用的是E18-D80NK,输出是数字信号,检测到遮挡输出低电平。这个传感器内部是集电极开路输出,所以需要接一个10k上拉电阻到3.3V。安装的时候要注意,发射端和接收端要对准,间距不要超过80cm,否则灵敏度不够。鸽舍入口一般也就20到30cm宽,完全够用。
2.3 执行机构驱动电路
舵机驱动看起来简单,其实有讲究。SG90舵机有三根线:棕色地、红色5V、橙色信号。信号线直接接STM32的PWM输出引脚就行,但要注意舵机的工作电流。空载的时候大概100mA,堵转的时候能到1A以上。如果你用STM32板子上的3.3V稳压器给舵机供电,大概率会烧掉稳压器。所以舵机的5V必须从独立的5V电源取,而且STM32和舵机要共地。
继电器模块我用的是光耦隔离的继电器板,输入控制信号接STM32的GPIO,输出控制220V的补光灯和排风扇。这里安全第一:强电和弱电必须物理隔离,PCB上强电走线和弱电走线间距至少3mm,而且强电部分要加绝缘漆或者灌封。如果你没有强电操作经验,建议补光灯和排风扇直接用12V直流的风扇和LED灯带,这样整个系统都是安全电压,调试起来也放心。
无源蜂鸣器驱动电路,很多人直接用GPIO推,结果声音小得跟蚊子叫一样。无源蜂鸣器需要方波驱动,而且驱动电流可能超过GPIO的20mA上限。正确做法是用一个NPN三极管做开关,比如S8050,基极通过1k电阻接GPIO,集电极接蜂鸣器负极,蜂鸣器正极接5V,发射极接地。同时蜂鸣器两端要反向并联一个续流二极管,比如1N4148,防止关断时反向电动势打坏三极管。PWM频率一般设在2kHz到4kHz之间,人耳最敏感,声音最响。
2.4 电源电路与抗干扰设计
电源部分我前面提了LM2596和AMS1117的组合,这里展开说细节。LM2596是降压型开关电源芯片,输入12V输出5V,效率大概80%左右。它的外围需要一个33uH的电感和一个肖特基二极管(比如SS34),输出电容建议用低ESR的电解电容或者钽电容。反馈引脚FB的电阻分压比决定了输出电压:Vout = 1.23 * (1 + R2/R1)。要输出5V,R1取1k,R2取3.06k,实际用3k和1k组合,输出大约4.92V,可以接受。
AMS1117-3.3是线性稳压器,输入5V输出3.3V,压差1.7V,在500mA负载下功耗大约0.85W,不加散热片的话芯片温度会到60度左右,有点烫但还能用。如果你带的负载比较重,比如OLED加蓝牙加传感器全开,电流可能到200mA,那功耗就是0.34W,温度还好。建议在AMS1117的输入输出端各加一个10uF钽电容和一个0.1uF陶瓷电容,抑制高频噪声。
抗干扰方面,STM32的ADC采集最容易受干扰。除了前面说的去耦电容,还可以在ADC输入引脚加一个RC低通滤波,比如1k电阻加0.1uF电容,截止频率大约1.6kHz,对于温湿度、光照这些慢变信号完全够用。另外,模拟地和数字地最好分开走,最后在电源入口处单点共地。如果PCB空间允许,模拟部分下面铺铜做屏蔽。
还有一个容易被忽略的地方:STM32的BOOT0引脚和NRST引脚如果走线太长,容易引入干扰导致误复位。这两个引脚尽量靠近芯片,走线短而粗。如果实在要走长线,加一个100pF电容到地做滤波。
3. 软件架构与核心代码实现
3.1 开发环境搭建与工程配置
开发环境我用的是Keil MDK5,配合STM32F1的器件支持包。安装的时候有个坑:Keil5默认不包含STM32的器件包,需要单独下载安装。你可以从Keil官网下载STM32F1xx_DFP,双击安装就行。另外,如果你电脑上同时装了Keil C51和Keil MDK,它们可以共存,但要注意安装顺序——先装C51再装MDK,否则C51的注册信息会被覆盖。如果已经装反了,卸载重装或者手动合并TOOLS.INI文件也可以解决。
工程配置里几个关键设置:第一,在Options for Target的Target标签页,勾选Use MicroLIB,这样printf函数才能重定向到串口。第二,在C/C++标签页的Define里加上USE_STDPERIPH_DRIVER,这样标准库的外设驱动才会被编译。第三,在Debug标签页选ST-Link Debugger,然后点Settings,在Flash Download里勾选Reset and Run,这样下载完程序自动运行,不用手动按复位键。
如果你习惯用VSCode开发,也可以配置STM32的开发环境。需要安装Cortex-Debug插件和ARM GCC工具链,然后写一个Makefile或者用STM32CubeMX生成工程。VSCode的好处是代码补全和跳转比Keil强,但调试体验还是Keil更顺手。我一般是Keil写代码和调试,VSCode用来看代码和搜索。
3.2 定时器与PWM驱动舵机
STM32F103C8T6有四个通用定时器:TIM2、TIM3、TIM4、TIM5,每个都有四个独立通道。我用TIM3的通道1(PA6)来输出PWM驱动舵机。舵机的控制信号是周期20ms、脉宽0.5ms到2.5ms的方波,对应角度0到180度。
计算过程:STM32系统时钟72MHz,TIM3挂载在APB1总线上,APB1预分频系数为2,所以TIM3时钟是36MHz。要得到20ms周期,预分频系数PSC和自动重装载值ARR满足:(PSC+1)*(ARR+1)/36MHz = 20ms。取PSC=71,则计数频率为36MHz/72=500kHz,周期2us。ARR取9999,则周期为(9999+1)*2us=20ms。这样PWM分辨率是2us,对应角度分辨率是180/2000=0.09度,完全够用。
脉宽设置:CCR值等于脉宽除以2us。0.5ms对应CCR=250,2.5ms对应CCR=1250。所以角度0到180度对应CCR从250到1250线性变化。代码里写一个函数SetServoAngle(uint8_t angle),内部计算CCR = 250 + angle * (1000/180),然后调用TIM_SetCompare1(TIM3, CCR)就行。
这里有个注意事项:舵机上电瞬间可能会抖动,因为PWM还没稳定。解决办法是在初始化的时候先把GPIO拉低,等定时器配置好了再使能PWM输出。另外,舵机不要频繁大角度来回转,SG90的塑料齿轮很容易扫齿。投喂动作一天也就几次,问题不大。
3.3 ADC多通道采集与滤波
STM32F103C8T6有两个ADC,12位精度,最多18个通道。我用ADC1的通道0(PA0)接光敏电阻,通道1(PA1)接MQ-135,通道2(PA2)接一个电位器用于手动调节阈值。
ADC配置步骤:第一,使能ADC1和GPIOA时钟。第二,配置PA0、PA1、PA2为模拟输入模式。第三,配置ADC为独立模式、连续转换、扫描模式,使能DMA。第四,配置DMA通道1,从ADC数据寄存器搬到内存数组。第五,使能ADC的DMA请求,启动ADC。
为什么要用DMA?因为如果你用轮询方式读ADC,每次转换都要等EOC标志,CPU占用率高,而且多通道切换的时候容易读到旧数据。用DMA自动搬运,CPU只需要在需要的时候读内存数组就行,效率高很多。
滤波方面,硬件上我已经加了RC低通,软件上再用滑动平均滤波。具体做法是开一个长度为10的数组,每次新数据进来就替换最旧的数据,然后求平均值。这样既能平滑数据,又不会引入太大延迟。对于温湿度这种慢变信号,还可以用一阶滞后滤波:Y(n) = α*X(n) + (1-α)*Y(n-1),α取0.1到0.3之间。我实测下来,滑动平均加一阶滞后组合使用,ADC读数波动从±20降到±3以内。
3.4 定时任务调度与看门狗
整个系统需要同时处理多个任务:读传感器、刷新OLED、检测按键、控制投喂、串口通信。如果全部塞在while(1)里顺序执行, timing会乱,而且某个任务卡住整个系统就死了。所以我用了一个简单的时间片轮询调度器。
具体做法:用SysTick定时器产生1ms中断,在中断里给每个任务计数器加1。主循环里判断计数器是否达到设定值,到了就执行对应任务,然后清零计数器。比如传感器任务每500ms执行一次,OLED刷新每200ms一次,按键扫描每20ms一次,投喂检查每1秒一次。这样每个任务都能按时执行,互不干扰。
看门狗用独立看门狗IWDG,时钟源是内部40kHz的LSI。预分频系数取64,重装载值取625,则溢出时间 = (64 * 625) / 40kHz = 1秒。主循环里每500ms喂一次狗,如果程序跑飞了,1秒后看门狗复位。这里注意,喂狗不要放在定时器中断里,否则中断还在跑但主循环卡死了,看门狗照样被喂,就失去保护意义了。喂狗必须放在主循环里,确保主循环正常运行。
3.5 串口通信与数据上报
串口我用USART1,波特率115200,接CH340模块到电脑,或者接HC-05蓝牙模块到手机。数据上报格式我设计成简单的文本协议,每行一条数据,字段用逗号分隔,方便解析。比如:
$DATA,25.6,68.2,45,120,1,0#分别表示温度、湿度、光照ADC值、氨气ADC值、归巢状态、投喂状态。上位机收到后按逗号分割就能解析。
printf重定向:在标准库工程里,需要重写fputc函数,把字符输出到USART1。代码很简单:
int fputc(int ch, FILE *f) { USART_SendData(USART1, (uint8_t)ch); while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); return ch; }注意要勾选Use MicroLIB,否则fputc不会被正确链接。另外,如果你同时用了半主机模式,需要注释掉#pragma import(__use_no_semihosting)相关的代码,否则程序会卡在BKPT指令。
蓝牙模块HC-05的配置:默认波特率是9600,需要发AT指令改成115200。接线的时候,HC-05的TXD接STM32的PA10(USART1_RX),RXD接PA9(USART1_TX),VCC接5V,GND共地。注意HC-05的RXD是3.3V电平,STM32的TX输出是3.3V,可以直接连,不用电平转换。
4. 实物组装与调试实录
4.1 PCB打样与焊接注意事项
PCB我用的是嘉立创打样,双面板,尺寸10cm x 8cm,绿色阻焊,白色丝印。画板的时候有几个地方要特别注意:第一,电源走线要粗,12V和5V的主干走线至少40mil,3.3V至少20mil。第二,晶振下面不要走任何信号线,最好铺地铜。第三,SWD接口放在板子边缘,方便插调试器。第四,舵机和继电器的接口用大间距的端子,比如KF301-2P,方便接粗线。
焊接顺序:先焊矮的元件,再焊高的。具体是:先焊STM32芯片(如果用贴片的话),再焊电阻电容,再焊晶振、复位按键,再焊排针、端子,最后焊OLED和蓝牙模块。STM32F103C8T6是LQFP48封装,引脚间距0.5mm,手焊有点难度。我的经验是:先用烙铁在焊盘上上一点锡,然后用镊子把芯片放正,再用烙铁把引脚一个一个压焊。如果连锡了,用吸锡带清理。助焊剂要多用,好的助焊剂能让焊接轻松很多。
焊接完成后,先不要上电,用万用表测一下3.3V和5V对地有没有短路。确认没有短路再上电,上电后先测电压对不对,3.3V应该在3.2到3.4之间,5V在4.8到5.2之间。然后用ST-Link连接,看能不能识别到芯片。如果识别不到,检查SWD接线和BOOT0电平。
4.2 分模块调试与联调
调试一定要分模块来,不要一上来就全部联调。我的调试顺序是这样的:
第一步,最小系统验证。写一个最简单的LED闪烁程序,下载进去看LED有没有闪。如果闪了,说明最小系统、下载电路、时钟配置都没问题。
第二步,串口验证。写一个串口发送程序,电脑上用串口助手看能不能收到数据。如果收不到,检查波特率、接线(TX和RX有没有接反)、串口助手有没有打开对应端口。
第三步,传感器验证。单独读DHT22,看温湿度数据对不对。如果读出来是0或者255,检查上拉电阻和时序。DHT22的时序对延时很敏感,如果STM32的延时函数不准,读数据会失败。我建议用SysTick做微秒级延时,不要用for循环空跑,因为编译器优化等级不同,for循环的延时时间会变。
第四步,执行机构验证。单独控制舵机转0度、90度、180度,看动作是否到位。如果舵机抖动或者不动,检查PWM频率和脉宽,以及5V供电是否足够。
第五步,联调。把所有模块接上,跑完整程序,观察OLED显示、串口输出、舵机动作是否正常。联调的时候最容易出现的问题是电源不够,比如舵机一动,OLED就闪一下,这是5V被拉低了。解决办法是给5V加更大的电容,或者给舵机单独供电。
4.3 常见问题与排查技巧
调试过程中我遇到不少问题,这里整理成速查表,方便大家对照排查。
| 问题现象 | 可能原因 | 排查方法 | 解决办法 |
|---|---|---|---|
| 程序下载失败 | BOOT0电平不对 | 测BOOT0对地电压 | BOOT0接3.3V进入下载模式 |
| OLED不显示 | I2C地址错误 | 用I2C扫描程序找地址 | 修改代码中的从机地址 |
| DHT22读数失败 | 上拉电阻太大 | 测数据线空闲电平 | 换成4.7k上拉 |
| 舵机抖动 | 电源电流不足 | 示波器看5V纹波 | 加470uF电容或独立供电 |
| ADC读数跳动 | 参考电压不稳 | 测VDDA电压 | 加去耦电容,软件滤波 |
| 串口乱码 | 波特率不匹配 | 检查两边波特率 | 统一设为115200 |
| 看门狗误复位 | 喂狗间隔太长 | 计算溢出时间 | 缩短喂狗周期或加大重装载值 |
| 蓝牙连接不上 | 波特率不对 | 发AT指令测试 | 用AT+UART改波特率 |
还有一个坑:STM32的PA15、PB3、PB4默认是JTAG引脚,如果你要用它们做普通GPIO,必须禁用JTAG。但禁用JTAG后,SWD还能用,所以下载程序不受影响。代码里加一句GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE)就行。我一开始不知道这个,PB3接蜂鸣器死活不响,查了半天才发现是JTAG占用了。
4.4 投喂机构机械结构优化
投喂机构我前后改了三个版本。第一版用舵机直接带一个挡板,挡板打开饲料就掉下来。问题是饲料容易卡住,而且每次掉落的量不稳定。第二版改成旋转料盘,舵机转一个角度,料盘上的孔对准出料口,饲料掉下去。这个方案好一些,但孔的大小和数量需要根据饲料颗粒大小调整。我用的鸽子饲料颗粒直径大约3到4mm,所以料盘上的孔直径取8mm,深度10mm,每次转60度放一份,大约15克。
第三版在料盘下面加了一个振动马达,每次放料前振动2秒,防止饲料结拱。振动马达用手机里的那种扁平马达,3V供电,通过一个NPN三极管驱动,基极接STM32的GPIO。实测下来,加振动之后放料成功率从80%提升到98%以上。
料盘和舵机的连接用的是一个3D打印的联轴器,如果你没有3D打印机,也可以用热熔胶把舵机臂和料盘粘死,但那样就不能调角度了。我建议还是画个简单的STL文件找打印店打一个,成本也就几块钱。
5. 设计手册编写与项目扩展
5.1 设计手册应该包含哪些内容
一份完整的设计手册不是把代码和原理图堆上去就完事了,它应该让一个完全不懂的人也能照着做出来。我写的手册包含这几个章节:
第一章是项目概述,讲清楚这个系统是干什么的、有哪些功能、适合什么场景。第二章是系统框图,用方块图展示各个模块之间的关系。第三章是硬件设计,包括原理图、PCB布局图、元器件清单(BOM表)。BOM表要写清楚每个元件的型号、封装、数量、购买链接或者替代型号。第四章是软件设计,包括程序流程图、关键代码解析、通信协议说明。第五章是组装调试,按步骤说明怎么焊接、怎么烧录、怎么测试。第六章是常见问题,就是我前面整理的那个速查表。
写手册的时候要注意,截图要清晰,标注要明确。比如原理图上每个网络标号都要看得清,PCB图要标出元件位置。代码解析不要贴大段代码,只贴关键部分,然后配上注释和说明。我见过一些毕业设计手册,代码贴了五十页,结果关键的中断服务函数反而没讲清楚,这就本末倒置了。
5.2 从驯养系统到赛鸽计时系统的升级路径
这个项目做完了,如果你还想继续折腾,可以往赛鸽计时系统方向升级。核心改动是把红外对射换成RFID读写器,给每只鸽子戴一个125kHz或者13.56MHz的电子脚环。当鸽子归巢经过读写器天线时,系统记录脚环ID和时间戳,然后通过蓝牙或者WiFi上传到手机APP。
RFID读写器我推荐用MFRC522模块,便宜、资料多、SPI接口。天线可以用PCB印刷天线或者铜线绕制。读写距离一般5到10cm,所以要把天线装在鸽舍入口的通道两侧,鸽子经过时刚好能读到。这里有个难点:多只鸽子同时经过时可能冲突,需要做防碰撞处理。MFRC522支持防冲突算法,但需要仔细调参数。
另外,赛鸽计时对时间精度要求高,STM32的RTC用外部32.768kHz晶振的话,精度可以做到每天误差几秒以内。如果要更高精度,可以加一个GPS模块做时间同步,但成本就上去了。对于业余比赛来说,RTC精度够用了。
5.3 低功耗设计与电池供电方案
如果鸽舍没有市电,或者你想做一个便携版本,那就需要考虑低功耗设计。STM32F103本身功耗不算低,运行模式大概30mA,睡眠模式可以降到几mA,待机模式只有几uA。但传感器和舵机才是耗电大户,DHT22每次测量大概1mA,舵机动作瞬间1A,这些都没法省。
所以低功耗设计的思路是:用大容量锂电池或者铅酸电池,配合太阳能板充电。电池容量按每天耗电量算,假设平均电流50mA,一天24小时就是1200mAh,考虑阴雨天备用,电池至少选10Ah以上。太阳能板选10W到20W,晴天一天能发40到80Wh,够用了。
软件上,可以让STM32在不干活的时候进入睡眠模式,用RTC闹钟或者外部中断唤醒。比如每10分钟醒来一次读传感器,读完继续睡。舵机只在投喂时间动作,其他时间断电。这样平均电流可以降到10mA以下,电池续航能到一个月以上。
5.4 上位机与手机APP的简单实现
上位机我用Python写了一个简单的串口数据接收和可视化程序,用pySerial读串口,用matplotlib画实时曲线。代码不长,大概一百行左右。核心逻辑就是开一个串口线程,不断读数据,解析后存到环形缓冲区,然后定时刷新图表。
手机APP可以用MIT App Inventor做,拖拖拽拽就能搭一个蓝牙接收界面。或者用微信小程序,通过蓝牙API连接HC-05,显示数据和控制投喂。如果你不想写APP,也可以用现成的蓝牙串口助手,比如“蓝牙串口助手”或者“Serial Bluetooth Terminal”,直接看数据就行。
数据存储方面,可以在电脑上把接收到的数据存成CSV文件,然后用Excel或者Python做进一步分析。比如统计一周的温度变化曲线,看看鸽舍环境是否稳定。这些数据对于优化驯养策略很有价值。
5.5 我踩过的几个典型坑
最后分享几个我在这个项目里踩过的坑,希望大家能避开。
第一个坑:STM32的延时函数delay卡死。我一开始用for循环做微秒延时,在默认的8MHz时钟下调好了,后来把时钟改成72MHz,延时就不准了,DHT22直接读不出数据。后来改用SysTick做延时,不管时钟怎么变,延时都准确。所以延时函数一定要用硬件定时器,不要用软件循环。
第二个坑:看门狗电路设计。我一开始把看门狗喂狗放在定时器中断里,结果主循环卡死了,中断还在跑,看门狗一直被喂,系统就不复位。后来把喂狗放到主循环,问题解决。另外,独立看门狗的时钟是内部LSI,精度不高,溢出时间会有偏差,所以喂狗周期要留足余量,比如溢出时间1秒,喂狗周期设500ms。
第三个坑:485电路和串口3.3V转1.8V电平转换。这个项目其实没用到485,但如果你要扩展成多鸽舍联网,485是常用方案。SN65HVD230是3.3V的485收发器,典型电路很简单,但要注意终端电阻。总线两端各接一个120欧姆电阻,中间节点不要接。另外,485的A和B线要双绞,最好加屏蔽层,否则长距离通信误码率很高。
第四个坑:无源蜂鸣器驱动电路。我一开始直接用GPIO推蜂鸣器,声音小得几乎听不见。后来加了S8050三极管和1N4148续流二极管,声音立刻大了很多。PWM频率也很关键,我试过1kHz、2kHz、4kHz,最后发现2.7kHz左右声音最响。这个频率不是固定的,不同蜂鸣器的谐振频率不一样,你可以写个程序从1kHz扫到5kHz,找到最响的那个频率。
第五个坑:STM32的ADC参考电压。我一开始用VDDA做参考,但VDDA是从AMS1117出来的3.3V,精度只有2%左右,ADC读数误差比较大。后来改用外部基准芯片比如REF3033,精度0.2%,ADC读数就准多了。当然,对于这个项目来说,2%的误差也能接受,但如果你要做精确测量,外部基准是必须的。
这个项目从画板子到写代码到组装调试,前后花了大概三周时间,中间断断续续改了很多版。现在系统跑得很稳,每天定时投喂三次,环境数据实时上传,鸽子养得比以前好多了。如果你也在做类似的项目,希望这些经验能帮你少走点弯路。