1. 前言
随着物联网技术的快速发展,智能家居已经进入了人们的日常生活。在政策支持的背景下,智能家居企业越来越重视相关技术的研发和应用;但市场上的宠物喂养设备难以满足宠物主人的需求。本文介绍了宠物智能喂养装置STM32作为核心,协调多个模块,共同完成不同年龄段宠物的定期定量喂养、实时环境监测和高温报警,业主可以随时通过智能设备了解宠物的生活环境,为宠物添加食物。该系统功能完善,价格低廉,使用方便,解决了宠物饲养者外出时的后顾之忧,保证了宠物进食的规律性。
设计宠物喂食器,支持手动控制粮食喂食,设置恒温阀值、定期喂食、实时显示温湿度、剩余粮食重量等功能。
2. 需求
做一个基于STM宠物喂食器可用于养鸟或小黄鸭。
主要功能有:
能通过手机wifi app按钮控制食物喂养。定期喂食,每次喂食量(如果没有吃完,下次补充到设定的量,补充量不需要那么准确)
2.记录宠物的日食量(食用食物的重量)
3.屏幕显示当前盒子/鸟笼的温度和粮食的重量
4.温度控制:当温度低于多少度(自行设置)时,恒温器(只是简单的自动开关)会自动启动。
(1)手机APP:设计一款Android手机APP,一款windows作为上位机,客户端手动控制粮食喂养,设置恒温阀值,实时显示定期喂养、温湿度、剩余粮食重量等功能。
手机APP与STM32之间通过TCP网络协议传输数据,STM32这边使用ESP8266
创建无线网卡WIFI热点,手机APP连接热点后,建立小型局域网,完成数据通信。
(2)采用DHT11
检测鸟笼内当前的环境温度和湿度。
(3)采用0.96寸SPI接口的OLED显示屏
,显示当前鸟笼的温度、湿度和粮食重量。
(4)采用LED灯模拟恒温器,当鸟笼内环境温度低于设定阀值时,启动恒温器加热(点亮LED模拟)。
(5)宠物喂养28BYJ4 步进电机4相5线 ULN2003驱动板
步进电机转动指定的圆数或度数,模拟粮食喂养。
(6)喂食重量采用HX711称重传感器电子秤称重模块
完成检测。
3. 所需元器件
3.1 ESP8266 WIFI
ESP8266是一款无线WIFI模块可通过配置与单片机上的串口通信WIFI传输数据。
3.2 电子秤传感器
HX711 专为高精度称重传感器设计的24位A/D 转换器芯片。
3.3 DHT11温湿度传感器
DHT11是一种具有校准数字信号输出的温湿度传感器。 其精度湿度±5%RH, 温度±2℃,量程湿度5~95%RH, 温度-20~ 60℃。
3.4 步进电机
步进电机28BYJ-48名称含义: 28:步进电机的有效最大外径是28毫米 B: 步进电机步字汉语拼音首字母 Y: 永磁永字汉语拼音首字母 J: 表示减速型减字汉语拼音首字母 BYJ: 组合是永磁减速步进电机 48:表示四相八拍 5V:表示额定电压为5V,而且是直流电压 步进角:5.625度,就是1脉冲信号转动5.625度,64个信号转360度。 减速比:1/64,电机壳内的电机转动64电机壳外的圆圈和部分旋转1圈。 四相:ABCD四相(有电机定子8个齿,相对的2个齿是1相), 八拍:(A-AB-B-BC-C-CD-D-DA-A)。 一拍就是脉冲信号,完成循环8脉冲信号。 当通电状态的变化完成循环时,转子转动齿距。8齿距是一圈,8×8=64 64拍,64转动脉冲信号360度。
3.6 STM32开发板
STM32F103RCT6芯体规格为32位,速度为72位MHz,程序存储容量为256KB,程序存储器的类型是FLASH,RAM容量是48K。
3.7 杜邦线
4. 软件上位机设计
4.1 介绍开发环境
采用上位机软件Qt框架设计,Qt是跨平台的C 图形用户界面应用程序框架。Qt是一个1991年由Qt Company跨平台开发C 图形用户界面应用程序开发框架。它可以开发GUI程序,也可用于开发非GUI程序,如控制台工具和服务器。简单来说,QT它可以很容易地帮助面的软件,甚至不需要投入太多精力。
https://www.qt.io/
4.2 学习教程
QT入门实战专栏: https://blog.csdn.net/xiaolong1126626497/category_11400392.html
4.3 win10运行效果
4.4 Android运行效果
4.5 通信协议
读取ESP8266发来的数
$update,22,33,12
$update,温度,湿度,剩余克数
向ESP8266发送:
手动喂食: $0
定时投喂时间设置: $1,2
恒温温度设置: $2,22
5. STM32设备端开发
基于STM32设计的宠物投喂器
基于STM32设计的宠物投喂器_上位机源码:https://download.csdn.net/download/xiaolong1126626497/85736919 基于STM32设计的宠物投喂器_STM32源代码 https://download.csdn.net/download/xiaolong1126626497/85736953
5.1 设备实物
5.2 硬件接线说明
硬件连接方式:
1. ESP8266 WIFI接线
ATK-ESP8266串口WIFI模块与STM32的串口2相连接。
PA2(TX)--RXD 模块接收脚
PA3(RX)--TXD 模块发送脚
GND---GND 地
VCC---VCC 电源(3.3V~5.0V)
2. TFT 1.44 寸彩屏接线
GND 电源地
VCC 接5V或3.3v电源
SCL 接PC8(SCL)
SDA 接PC9(SDA)
RST 接PC10
DC 接PB7
CS 接PB8
BL 接PB11
3. DHT11 温湿度
VCC--VCC
GND---GND
DAT---PA5
4. 步进电机
ULN2003控制28BYJ-48步进电机接线:
ULN2003接线:
IN-D: PB15 d
IN-C: PB14 c
IN-B: PB13 b
IN-A: PB12 a
+ : 5V
- : GND
5. 称重传感器
VCC--->5V
SCK--->PB0 时序控制脚--对STM32--输出模式
DT---->PB1 输出输出脚-对STM32--输入模式
GND--->GND
6. 板载LED灯接线
LED1---PA8
LED2---PD2
7. 板载按键接线
K0---PA0
K1---PC5
K2---PA15
5.3 工程代码框架
5.4 main.c核心代码
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "usart.h"
#include <string.h>
#include "timer.h"
#include "esp8266.h"
#include "motor.h"
#include "oled.h"
#include "dht11.h"
#include "adc.h"
#include <string.h>
#include <stdlib.h>
#include "HX711.h"
//JTAG模式设置,用于设置JTAG的模式
//mode:jtag,swd模式设置;00,全使能;01,使能SWD;10,全关闭;
#define JTAG_SWD_DISABLE 0X02
#define SWD_ENABLE 0X01
#define JTAG_SWD_ENABLE 0X00
void JTAG_Set(u8 mode)
{
u32 temp;
temp=mode;
temp<<=25;
RCC->APB2ENR|=1<<0; //开启辅助时钟
AFIO->MAPR&=0XF8FFFFFF; //清除MAPR的[26:24]
AFIO->MAPR|=temp; //设置jtag模式
}
u8 temp;
u8 humidity;
u32 CurrentWeight=5; //默认重量值
u8 timer_hour=1; //定时投喂的时间
u8 SetTemperature=0; //设置恒温温度
//WIFI发送数据存储区域
char data_buff[300];
int main()
{
u8 esp8266_state=0;
u8 key;
u8 i;
u32 time_cnt=0;
u32 timer_hour_cnt=0; //记录定时的时间
JTAG_Set(JTAG_SWD_DISABLE); //释放PA15
LED_Init();
KEY_Init();
USART1_Init(115200);
Moto_Init(); //电机初始化
USART2_Init(115200);//串口-WIFI
TIMER2_Init(72,20000); //超时时间20ms
DHT11_Init(); //初始化DHT11
Lcd_Init(); //LCD初始化
Lcd_Clear(0); //清屏为黑色
LCD_LED_SET;//通过IO控制背光亮
Init_HX711pin(); //称重传感器
printf("正在初始化WIFI请稍等.\r\n");
for(i=0;i<5;i++)
{
if(ESP8266_Init()==0)
{
esp8266_state=1;
break;
}
else
{
esp8266_state=0;
printf("ESP8266硬件检测错误.\r\n");
}
}
if(esp8266_state)
{
printf("准备创建热点....\r\n");
//配置ESP8266创建的WIFI名称和WIFI密码,手机需要连接这个WIFI热点
printf("WIFI状态:%d\r\n",ESP8266_AP_TCP_Server_Mode("esp8266_666","12345678",8089));
}
Get_Maopi(); //称毛皮重量
delay_ms(1000);
delay_ms(1000);
Get_Maopi(); //重新获取毛皮重量
while(1)
{
//按键可以测试投喂食物
key=KEY_Scan(0);
if(key==2)
{
Motorcw_ring(1,300); //电机正转1圈--模拟投喂粮食
printf("启动步进电机投喂食物...\r\n");
}
else if(key==3)
{
Lcd_Clear(0); //清屏为黑色
LED2=!LED2;
}
//轮询时间到达
if(time_cnt>=100)
{
time_cnt=0;
LED1=!LED1;
//获取环境温湿度
if(DHT11_Read_Data(&temp,&humidity))
{
printf("温度读取失败.\r\n");
}
printf("环境温度:%d\r\n环境湿度:%d\r\n",temp,humidity);
//获取称重传感器反馈的重量
Get_Weight();
printf("净重量 = %d g\r\n",Weight_Shiwu); //打印
//LCD屏实时显示温湿度、称重信息
sprintf(data_buff,"H:%d",humidity);
Gui_DrawFont_GBK16(0,16*1,RED,GRAY0,(u8*)data_buff);
sprintf(data_buff,"T:%d",temp);
Gui_DrawFont_GBK16(0,16*2,RED,GRAY0,(u8*)data_buff);
sprintf(data_buff,"G:%d",Weight_Shiwu);
Gui_DrawFont_GBK16(0,16*3,RED,GRAY0,(u8*)data_buff);
//传给手机APP实时显示
//$update,22,33,12 CurrentWeight
//$update,温度,湿度,剩余克数
sprintf(data_buff,"$update,%d,%d,%d",temp,humidity,CurrentWeight);
//发送数据
ESP8266_ServerSendData(0,(u8*)data_buff,strlen(data_buff));
}
// 接收WIFI返回的数据
if(USART2_RX_FLAG)
{
USART2_RX_BUFFER[USART2_RX_CNT]='\0';
printf("WIFI收到数据:\r\n");
//向串口打印服务器返回的数据
for(i=0;i<USART2_RX_CNT;i++)
{
printf("%c",USART2_RX_BUFFER[i]);
}
//如果是下发了属性
if(USART2_RX_CNT>5)
{
//使用字符串查找函数
//如果需要手动投喂粮食
if(strstr((char*)USART2_RX_BUFFER,"$0"))
{
Motorcw_ring(1,300); //电机正转1圈--模拟投喂粮食
}
//如果是设置定时投喂的时间(小时)
//格式: 定时投喂时间设置: $1,2
else if(strstr((char*)USART2_RX_BUFFER,"$1"))
{
char *p=strstr((char*)USART2_RX_BUFFER,"$2");
//转为整数
timer_hour=atoi(p+3);
printf("定时投喂的时间:%d\r\n",timer_hour);
}
//如果是设置恒温器的温度
//格式: 恒温温度设置: $2,22
else if(strstr((char*)USART2_RX_BUFFER,"$2"))
{
char *p=strstr((char*)USART2_RX_BUFFER,"$2");
//转为整数
SetTemperature=atoi(p+3);
printf("设置恒温温度为:%d\r\n",SetTemperature);
}
USART2_RX_CNT=0;
USART2_RX_FLAG=0;
}
}
//判断是否需要加热
//如果环境温度小于了设置的恒温温度就加温
if(temp<SetTemperature)
{
//执行加温的代码----
}
//判断定时的时间是否到达
if(timer_hour_cnt >=(100*60*60)*timer_hour)
{
timer_hour_cnt=0; //重新下一次计数
Motorcw_ring(1,300); //电机正转1圈--模拟投喂粮食
}
DelayMs(10);
time_cnt++;
timer_hour_cnt++;
}
}