
简介基于STM32的宠物智能饲养盒Proteus仿真设计是一份面向单片机初学者、嵌入式开发者及电子竞赛选手的完整参考方案适用于智能家居、单片机课程设计、毕业设计及宠物喂养装置预研等多种场景。压缩包内共223个文件其中H/C文件为工程源码pdsprj与pdsbak为Proteus仿真主工程及备份Hex/Axf为编译烧录文件avi为演示与补拍视频另有LCD1602、DHT11等模块驱动整包大小约为32.88MB目录结构分类清晰。该设计已吸引184人学习下载核心功能包括定时器定时、LCD1602信息显示、继电器控制投食、温湿度采集与智能控制并支持宠物喂养与温湿度监控联动控制。通过仿真图和源码对照可掌握STM32的GPIO、定时器及延时等外设配置思路理解Proteus与Keil的联调流程结合演示视频可减少环境搭建和排错时间适合快速进行功能验证与二次开发。1. 别急着搭硬件先用Proteus把饲养逻辑跑通把宠物寄养出去最不省心的其实是喂食节奏。真实喂食器涉及电机、传感器和电源管理改一轮硬件就得等几天物流纯看框图又验证不了执行结果。这套基于STM32设计的宠物智能饲养盒Proteus仿真方案把定时投食、DHT11温湿度读取、LCD1602显示和继电器动作完整地放在仿真环境里所有硬件用元件库搭建逻辑全部在Keil工程里跑。正在做嵌入式课设或毕业设计的人可以用它先验证“定时调度传感器采集执行器控制”这套组合逻辑已经上手过STM32的工程师也能从定时器分时调度和单总线时序里看到一些边界细节。下面按定时驱动、采集执行、仿真联调、参数标定四个层次展开。2. STM32定时器分时调度与LCD1602显示驱动2.1 通用定时器选型与1ms时基配置饲养盒的控制循环需要三类时间源1ms的系统心跳、DHT11起始信号需要的18ms以上低电平、以及喂食间隔的秒级倒计时。STM32F103里TIM2到TIM4都是通用定时器这里选用TIM2原因很实际TIM1是高级定时器配置项多在Proteus仿真里模型兼容性也不如通用定时器稳定TIM3、TIM4留给以后扩展PWM调速时用。把TIM2配置成1ms中断后喂食倒计时和LCD刷新都靠它累加主循环里不需要再开其他定时源。void TIM2_Base_Init(void) { TIM_TimeBaseInitTypeDef tim_cfg; NVIC_InitTypeDef nvic_cfg; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); tim_cfg.TIM_Prescaler 71; // 72MHz / 72 1MHz tim_cfg.TIM_CounterMode TIM_CounterMode_Up; tim_cfg.TIM_Period 999; // 1MHz / 1000 1ms tim_cfg.TIM_ClockDivision TIM_CKD_DIV1; TIM_TimeBaseInit(TIM2, tim_cfg); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); nvic_cfg.NVIC_IRQChannel TIM2_IRQn; nvic_cfg.NVIC_IRQChannelPreemptionPriority 1; nvic_cfg.NVIC_IRQChannelSubPriority 0; nvic_cfg.NVIC_IRQChannelCmd ENABLE; NVIC_Init(nvic_cfg); TIM_Cmd(TIM2, ENABLE); }代码逻辑不复杂先打开TIM2的APB1总线时钟再配置预分频、计数模式和自动重装载值。预分频71把72MHz降到1MHz自动重装载999让计数器数满1000产生更新中断中断频率正好1kHz也就是1ms心跳。优先级这里给了抢占1、子优先级0故意比SysTick略低因为后面DHT11单总线时序对延迟敏感不能让定时器中断长时间霸占CPU。提示Proteus里如果发现喂食倒计时比真实时间慢先检查MCU属性里的Crystal Frequency是不是8MHz。工程默认按8MHz外部晶振加9倍PLL跑72MHz晶振频率填错整个时钟树全部偏移。2.2 LCD1602的4位驱动与显示引脚分配LCD1602在本设计里负责两块信息第一行显示温度和湿度第二行显示喂食倒计时和继电器状态。采用4位总线模式数据线只占D4-D7四条相比8位模式少占4个IO给继电器和DHT11留出引脚余量。Proteus里连线时注意LCD的VEE引脚要通过10k可调电阻接地直接接地或悬空会导致对比度异常屏幕全黑或全白。表LCD1602与STM32引脚分配LCD引脚STM32引脚说明RSPC1寄存器选择0命令1数据RWPC2读写选择固定接地或接PC2EPC3使能信号下降沿锁存D4PC7数据线低四位之一D5PC6数据线D6PC5数据线D7PC4数据线VO可调电阻中端对比度调节4位模式下的写入分为两步先写高4位再写低4位。E引脚每产生一次下降沿LCD控制器锁存一次数据所以写数据时要先拉高E再延时再拉低。初始化序列里最关键的三个0x03是厂家手册定义的唤醒序列必须逐级延时少一个延时就会出现显示不全、首行乱码这类现象。void LCD_WriteNibble(uint8_t data) { GPIO_WriteBit(GPIOC, GPIO_Pin_4, (BitAction)((data 3) 0x01)); GPIO_WriteBit(GPIOC, GPIO_Pin_5, (BitAction)((data 2) 0x01)); GPIO_WriteBit(GPIOC, GPIO_Pin_6, (BitAction)((data 1) 0x01)); GPIO_WriteBit(GPIOC, GPIO_Pin_7, (BitAction)(data 0x01)); GPIO_SetBits(GPIOC, GPIO_Pin_3); Delay_us(1); GPIO_ResetBits(GPIOC, GPIO_Pin_3); } void LCD_WriteCommand(uint8_t cmd) { GPIO_ResetBits(GPIOC, GPIO_Pin_1); GPIO_ResetBits(GPIOC, GPIO_Pin_2); LCD_WriteNibble(cmd 4); LCD_WriteNibble(cmd 0x0F); Delay_us(50); } void LCD_Init(void) { GPIO_Config_LCD(); // PC1-RS, PC2-RW, PC3-E, PC4-PC7数据 Delay_ms(15); LCD_WriteNibble(0x03); Delay_ms(5); LCD_WriteNibble(0x03); Delay_ms(5); LCD_WriteNibble(0x03); Delay_us(150); LCD_WriteNibble(0x02); LCD_WriteCommand(0x28); LCD_WriteCommand(0x0C); LCD_WriteCommand(0x01); Delay_ms(2); LCD_WriteCommand(0x80); }数据引脚的映射和常规接法相反PC4对应D7、PC7对应D4所以移位方向是反着来的接线时务必以原理图标注为准。GPIO_Config_LCD是把表里每个引脚配置为推挽输出的封装函数对应第4章的GPIO_Init标准写法。0x28设置4线2行5x7点阵0x0C打开显示关闭光标0x01清屏需要至少1.64ms代码里给2ms留足余量。如果第二行显示位置偏右问题通常出在0x80之后的地址设置0x80是第一行起始地址第二行要写0xC0。2.3 中断里置位、主循环执行的分时调度不在中断里直接刷新LCD或读取DHT11这两个操作耗时长而且DHT11读取过程中的精确延时会被新来的中断打乱。常规做法是TIM2中断里只做计数和置标志位主循环根据标志执行具体任务。volatile uint32_t sys_tick 0; volatile uint8_t flag_1s 0; volatile uint8_t flag_display 0; void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) ! RESET) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); sys_tick; if (sys_tick % 1000 0) flag_1s 1; if (sys_tick % 200 0) flag_display 1; } }主循环只有三个分支flag_1s置位时跑喂食倒计时状态机flag_display置位时刷新LCD每5秒调一次DHT11读取函数。显示刷新周期放在200ms是因为LCD1602连续写入几十个字节需要时间200ms刷新一次肉眼看起来是流畅的同时给继电器动作留出足够的电平稳定时间。这套“中断置位主循环清理”的结构是整个工程所有任务调度的骨架继电器控制和温湿度刷新全部挂在上面。3. 继电器投食执行链与DHT11温湿度采集3.1 继电器驱动电路为什么GPIO不能直接带线圈STM32F103的GPIO最大输出电流约20mAProteus里常用的5V继电器线圈内阻只有70-100欧姆工作电流50mA以上直接驱动唯一的后果是引脚电压被拉低继电器抖动或不吸合。常规做法用一颗2N2222三极管做开关GPIO经过1k限流电阻接到基极集电极接继电器线圈发射极接地线圈两端反向并联1N4148二极管吸收关断时的反向电动势。表继电器投食电路的Proteus元件连接元件参数接法三极管2N2222基极经1k接PA0集电极接线圈发射极接地继电器5V线圈线圈一端接5V另一端接集电极续流二极管1N4148负极接5V正极接集电极状态LED红色220欧姆接继电器常开触点指示投食动作PA0输出高电平时三极管基极电流约2.2mA进入饱和导通状态线圈得电吸合。这段电路里最容易犯的错是漏掉续流二极管仿真里没有它继电器也能动但关断瞬间线圈产生的反向电压会经过三极管集电极打回芯片引脚真实硬件里大概率烧端口仿真里表现为随后几次投食动作失灵。养成在感性负载上加续流二极管的习惯无论仿真还是实物都适用。3.2 DHT11单总线时序与数据位判定DHT11只有一根数据线主机发起起始信号后从机连续返回40位数据其中湿度整数、湿度小数、温度整数、温度小数各8位最后8位是校验和。Proteus里的DHT11模型和真实芯片时序一致主机拉低数据线至少18ms再释放并拉高20-40us从机响应后先拉低80us再拉高80us之后每1bit数据都以50us低电平开头后面跟26-28us高电平表示070us高电平表示1。uint8_t DHT11_ReadByte(void) { uint8_t i, data 0; for (i 0; i 8; i) { while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) RESET); Delay_us(40); if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) SET) data (data 1) | 0x01; else data (data 1); while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) SET); } return data; }40us这个延时是判定0和1的分界线。DHT11的0高电平持续26-28us1高电平70us取中间值40us读到的引脚电平如果还是高就是1已经变低就是0。读取前要确保PA1在推挽输出模式下发完起始信号然后立刻切换成浮空输入切换慢了会错过从机的80us应答窗口。数据读取完成后必须做校验和判断否则Proteus模型偶发返回的0xFF会被当成真实温度显示在LCD上。读回的5个字节做一次加法校验低8位等于第5个字节才算有效否则丢弃本次结果并保留上一次有效值。这是单总线传感器最基础的容错手段仿真里模型偶尔受上位机调度影响会读错一帧加上校验后LCD上的数值就不会跳来跳去。3.3 智能控制逻辑阈值联动与投食状态机饲养盒的控制规则分三条温度超过设定阈值时第二个继电器吸合模拟风扇启动湿度低于下限时LCD第二行追加加水提醒喂食倒计时归零后投食继电器吸合1秒完成一次投食。阈值和周期全部用宏定义管理改参数只需要在头文件里动一处。#define FEED_INTERVAL_SEC 12 * 3600 #define RELAY_ON_SEC 1 #define TEMP_FAN_THRESHOLD 30 #define HUMI_LOW_THRESHOLD 40喂食逻辑适合用两态状态机实现避免倒计时归零瞬间重复触发继电器。状态A等待倒计时状态B继电器吸合中。只有在状态A且计数值归零时才进入状态B状态B内按秒累加吸合时长到达RELAY_ON_SEC后关闭继电器并重置倒计时回到状态A。void Feeding_Task(void) { static uint8_t feeding_active 0; static uint16_t relay_counter 0; if (flag_1s) { flag_1s 0; if (feeding_active) { relay_counter; if (relay_counter RELAY_ON_SEC) { GPIO_ResetBits(GPIOA, GPIO_Pin_0); feeding_active 0; relay_counter 0; } } else if (feed_interval_count 0) { GPIO_SetBits(GPIOA, GPIO_Pin_0); feeding_active 1; feed_interval_count FEED_INTERVAL_SEC; } else { feed_interval_count--; } } }状态B期间即使倒计时归零也不会重新进入投食因为入口被feeding_active锁死。这里把喂食周期默认值写成43200秒即12小时仿真验证时改成10秒就能在Proteus里快速观察一次完整的投食动作。继电器吸合时间也不要小于300ms否则Proteus里LED点亮时间太短肉眼几乎看不到投食发生的证据。4. Proteus联调从原理图到跑起来的完整链路4.1 元件放置与STM32最小系统打开Proteus新建工程后按原理图放置STM32F103C8、LCD1602、DHT11、5V继电器、2N2222、1N4148、LED和电阻。元件搜索框直接输入STM32F103C8如果器件库里没有对应芯片检查是否安装了STM32芯片包Proteus 8以上版本需要手动安装器件库才能在搜索列表里找到F103系列。DHT11直接搜“DHT11”继电器可以搜“RELAY”或用通用线圈模型替代。STM32F103C8最小系统只需要三个东西VDD接5V、VSS接地、NRST经10k上拉到3.3V。Proteus里如果NRST悬空仿真时芯片可能不停复位现象是LCD反复闪烁、程序从头执行。PC14和PC15在部分Proteus版本里默认占用低频晶振工程里没有用到这两个引脚时保持悬空不要强行接到别处。4.2 晶振对齐与HEX文件加载源码按8MHz外部晶振加9倍PLL运行到72MHzProteus里双击MCU把Crystal Frequency设为8MHz。这里最容易踩的坑是Proteus默认值不是8MHz晶振频率一错定时器1ms时基也跟着错喂食周期、LCD刷新全部乱套。加载HEX文件前确认Keil工程已在Output选项卡勾选Create HEX FileF7编译后会生成BH-STM32.hex在Proteus里指定该文件后运行。表源码包文件结构与用途文件用途BH-STM32.uvguix.AdministratorKeil工程会话文件记录窗口布局main.__iKeil编译过程文件可忽略Template.hex.asmHEX固件反汇编文本供调试时对照DHT11.hex.asmDHT11相关代码的反汇编注释DHT11.axfARM链接生成的可执行映像供调试器加载演示视频.avi仿真运行完整演示补拍视频.avi关键操作补充演示stm32f10x_tim.c定时器外设库工程核心依赖stm32f10x_flash.cFlash控制库用于参数存储扩展keilkill.bat清理编译中间文件保持目录干净加载HEX后如果Proteus提示找不到符号或程序不运行先检查芯片型号是否选成STM32F103R6两者Flash容量不同HEX加载区域会有差异换回F103C8即可。仿真运行视频里演示的操作顺序是先复位再观察LCD首屏温度湿度显示然后改短喂食周期观察继电器动作最后用虚拟终端监视DHT11波形。4.3 三个高频故障的定位路径LCD只亮不显示字。第一步把10k可调电阻的滑动端调到中间VO电压约0.5-1V对比度正常第二步检查E引脚初始化代码用的是PC3如果原理图把E接到PC10但代码没同步改屏幕上永远不会有内容第三步检查复位引脚NRST悬空会让芯片反复复位LCD初始化代码来不及完整执行。DHT11读到0xFF或湿度跳变。检查PA1的GPIO模式是否在发完起始信号后立即切回浮空输入紧接着检查DHT11数据线上有没有4.7k到10k上拉电阻。Proteus的DHT11模型不同于真实传感器内部不集成上拉结构不加电阻时数据线在应答阶段处于高阻态读回的数据位是随机值。继电器不吸合。优先看继电器线圈电压属性Proteus元件库里的继电器默认线圈有5V、9V、12V几种规格选成12V接5V电源自然无法吸合改成5V或更换模型其次看三极管基极电阻超过10k会限制基极电流三极管进不了饱和区最后确认PA0时钟使能和GPIO模式Mode必须设为GPIO_Mode_Out_PP。GPIO_InitTypeDef gpio; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); gpio.GPIO_Pin GPIO_Pin_0; gpio.GPIO_Mode GPIO_Mode_Out_PP; gpio.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, gpio);这组代码对应继电器引脚PA0的推挽输出配置GPIO_Mode_Out_PP是推挽输出能提供足够的驱动电流让三极管饱和。如果改成GPIO_Mode_Out_OD开漏输出三极管基极会缺少驱动电流仿真里表现为继电器动作无力。5. 仿真参数标定与喂养周期验证技巧5.1 用宏定义统一管理标定参数喂食周期、继电器吸合时长、温湿度阈值这三个参数散落在函数里改动容易漏改。把这组参数收敛到头文件后每次启动仿真前只打开一个文件修改编译后直接生效。#define FEED_INTERVAL_SEC 10 // 仿真验证用10秒实物改回43200 #define RELAY_ON_SEC 1 #define TEMP_FAN_THRESHOLD 30 #define HUMI_LOW_THRESHOLD 40喂食周期的修改还需要同步确认feed_interval_count变量在初始化时被赋值为FEED_INTERVAL_SEC如果只改宏定义、不改初值状态机会等待一整个周期才进入第一次投食误以为程序没生效。验证方法是先改到10秒跑一轮确认继电器按预期动作后再改回12小时。5.2 用虚拟仪器量化验证DHT11时序Proteus左侧工具栏的Virtual Instruments面板提供虚拟示波器和虚拟终端。把虚拟示波器A通道接到PA1运行仿真可以看到DHT11起始信号和40bit数据脉冲。测量单个高电平脉冲宽度持续26-28us判为0、70us判为1这个测量结果直接验证代码里的40us分界线是否准确。虚拟终端通过串口打印温湿度原始字节每帧打印5个十六进制数前4个之和低8位等于第5个即可判定通信正常。给一个可以直接套用的验证流程运行仿真等待DHT11首次采样完成后记录LCD第一行温度湿度值然后人工把Proteus里DHT11模型的温度属性从25改成31等待下一次采样LCD温度应更新且第二行继电器状态位变为ON此时第二个继电器的LED点亮模拟风扇开启再把湿度属性调到35以下第二行追加显示“ADD WATER”最后观察投食周期从10秒改回12小时后倒计时数字应持续递减。整个过程不需要改一行功能代码全部通过宏定义和Proteus元件属性完成适合用来检查设计逻辑是否完整。本文还有配套的精品资源点击获取