序号 | 修改时间 | 修改内容 |
---|---|---|
1 | 2022-4-13 | 修改了硬件连接部分,串口引脚使用错误:从“PA1和PA2”更改为“PA2和PA3”,详细请见“3.7 硬件连接” |
本论文设计了一款宠物自动喂食装置,该装置使用Stm32作为主MCU,通过ESP8266模块连接TLINK物联网平台,通过TLINK平台的手机APP查看宠物喂食的状态,并可以听过手机发送指令控制Stm32输出PWM波控制舵机旋转,实现宠物食物的投喂,同时也可以通过指令实现自动、定时、定量地喂养宠物。该系统的功能完善、价格低廉,使用方便,解决了宠物饲养者外出时的后顾之忧,还能保证宠物的进食有一定的规律性。
实现效果
【毕业设计】基于Stm32的宠物智能喂食装置
建模模拟效果
我会把我做该毕业设计的整体思路以及部分的主要代码在文章中详细介绍,包括Soildworks建模部分。
若是你很懒,不想自己一步一步自己做的话,可以直接去下载论文和源代码。
代码:【代码】基于Stm32的宠物自动喂食装置_毕业设计
论文:【论文】基于Stm32的宠物自动喂食装置_毕业设计
全家桶:【毕设全家桶】基于STM32的宠物自动喂食装置_毕业设计
(温馨提示:是要花钱的哦,我觉得你看完这篇文章完全可以自己做出来的,没必要花钱的,所以请一定要仔细看下去哦!)
完成一个好的设计是要在实现了它的功能的基础上,所以在进行设计之前需要确定一下本设计要实现的功能,然后再进行相应的设计。在本设计中使用TLINK物联网平台通过ESP8266与Stm32进行数据交互,Stm32作为主控制MCU去控制舵机旋转,可以使宠物的食物顺利掉出。整体的功能流程如图2.1所示。
TLINK部分:作为物联网平台,可以通过ESP8266WIFI模块与Stm32进行数据交互,可以通过手机APP发送喂食指令,实现远程投喂的功能。
Stm32的串口部分:主要功能是通过ESP8266与TLINK平台进行数据交互,接收TLINK发来指令信息。
Stm32的定时器部分:主要功能是通过库函数输出PWM波,从而控制舵机旋转。以使宠物的食物顺利掉出。
ESP8266是WiFi串口模块,通过串口与Stm32相连接,可以实现的功能就是:从串口接收Stm32发送的数据,WiFi输出该数据;从WiFi接收到数据,通过串口将该数据发送给Stm32。ESP8266有三模式:AP模式、STA模式、AP+STA模式。实物如图所示。
1.STA模式:该模式下ESP8266作为一个连接的设备,可以用过AT指令设置它所要连接的WiFi名字、密码,即可连接到无线网络上。
2.AP模式:该模式下ESP8266作为一个WIFI热点,可以通过AT指令设置其的WiFi名字、密码以及其他参数。像手机、平板电脑等其他的设备可以用过WiFi名字及密码连接上ESP8266。
3.AP+STA模式:该模式下ESP8266既可以作为一个WIFI热点,也可以作为一个连接的设备。
;本次设计中ESP8266选择STA模式,仅作为STM32与TLINK平台的数据交互的媒介,供电电压为3.3v。所以只使用到四个引脚:RX引脚、TX引脚、3V3引脚、GND引脚。
本次设计中使用STM32F103ZET6最小系统板作为核心MCU,实物如图3.3所示。使用其他的芯片已ok的。
本设计中Stm32部分主要使用串口跟定时器,来实现使用串口通过ESP8266 WIFI模块与TLINK平台进行数据交互、通过定时器输出PWM波控制舵机旋转,以实现宠物食物掉落的目的。
只强调一下,其引脚3.3v-5v耐压,过高的电压会烧掉其中的芯片。还有在本次设计中所用到的引脚:PB1、PB2、P31、PA2、PC6五个功能引脚,以及5V、GND供电引脚。
舵机选用达盛舵机科技有限公司生产的CLS150TD型号的舵机,实物图及尺寸如图3.5所示。该型号舵机运行温度在-15℃~70℃,工作电压范围为4.8v-6.8v,驱动方式为PWM波,脉冲范围为500~2500 μsec,控制角度为:360°。
工作原理:通过给舵机的信号线(橙黄色)输入周期为20ms的PWM波,通高电平时间:0.5-2.5ms可以使舵机旋转0~360°。如图所示。
压力传感器选用电阻应变式压力传感器,以电阻应变计为转换元件,由弹性敏感元件、电阻应变计、补偿电阻和外壳组成,弹性敏感元件受到所测量的力而产生变形,并使附着其上的电阻应变计一起变形。电阻应变计再将变形转换为电阻值的变化,从而可以测量压力的变化,再通过A/D转换模块,即可得到被测物体的重量。所需接线的引脚为:EXC+、EXC-、SIC+、SIC-。实物图、引脚如图所示。
A/D模块选用HX711芯片,主要实现将压力传感器检测到的电压信号转换成STM32可读的数字信号。所需连接的引脚:AVDD引脚、GND引脚、INA+引脚、INA-引脚、DT引脚、SCK引脚、VCC引脚。HX711模块实物图如图所示。
供电使用3S锂电池作为整体装置的供电,3S锂电池可以提供11.1v的电压。3S锂电池实物如图所示。
因为HX711模块、舵机、STM32都不能直接11.1v电压,所以需要对电压进行稳压到5v,才能给它们供电,使用稳压板进行稳压,稳压板选用基于LM2596芯片的 DC-DC稳压模块,稳压板的输入端连接3S锂电池,用电压表测量输出端电压,用螺丝刀旋转稳压板上的变阻器,直到输出端输出电压为5v即可。而ESP8266则需要3.3v供电,所以需要再加一个稳压板将5v电压降到3.3v即可。稳压板实物如图所示。
硬件连接部分使用杜邦线连接,连接如下:3S锂电池接稳压板1的输入端,稳压板1的输出端接STM32的5V和GND引脚、舵机的正(红色)负(棕色)极、HX711模块的VCC与GND引脚以及稳压板2的输入端。HX711的DT引脚接STM32的PB1引脚、SCK引脚接STM32的PB0引脚,STM32的PC6引脚(定时器3通道1)接舵机的信号线(橙黄色)、PA2引脚接ESP8266的RX引脚、PA3接ESP8266的TX引脚。稳压板2的输出端接ESP8266的3.3V和GND引脚。接线示意图、Solidworks建模图如图所示。
本部分主要介绍TLINK物联网平台配置以及STM32部分的软件编程,在TLINK官方网站进行平台的配置,实现数据的数据实时监测功能、定时发送指令、自动报警功能。STM32部分主要实现功能:使用串口连接ESP8266与TLINK平台进行数据交互、通过定时器输出PWM波、以及实现控制舵机旋转追踪的目的。
本部分主要是进行TLINK平台的配置,在建立好一个设备与STM32进行数据交互。并介绍TLINK平台所要实现的功能:数据实时监测功能、定时发送指令、自动报警功能。
首先简单叙述一下在TLINK平台新建一个新设备的流程,然后再具体的去介绍每一步的如何操作,添加设备的流程一般如下:先点击添加设备,然后在添加设备的页面设置分组、设置设备名称、选择链接协议、设置掉线延时、添加传感器配置完这些参数后,点击保存,一个新的设备就添加完成了,但是想要使用这个新的设备还需要进行传输协议的选择和定义,点击设置连接,在其中选择想要的传输协议与定义协议格式即可。流程图如图所示。
1.设备分组:可以在其中选择新设备的分组,方便以后更加快捷和方便的查看设备组。
2.设备名称:填写新设备的名称。
3.链接协议:可以在其中选择所要用到的传输协议,例如:MQTT协议、TCP协议、HTTP协议等等。在这里我选用TCP协议作为与ESP8266的传输协议进行数据的交互。
4.掉线延时时间:是指在多少时间范围内未接收到数据的传递,则显示设备下线,进行等待。
5.传感器:此部分可以设置和添加传感器,传感器有很多的类型可供选择,例如:数值型、开关型、图片型等等。在此设备中,我添加了三个传感器:食物剩余量(数值型)、投喂食物量(数值型)、开始投喂(开关型)。
在设置连接页面中,可以在此进行传输协议的选择和自定义协议格式。如图所示,我选择的是使用TCP协议进行数据传输,同时将传输协议定义为:
其中[H:]表示数据头标签,[H:ZLJ]则表传输的数据以ZLJ开始。
[S:]表示分隔符标签,[S::]、[S:;]则表示使用“:”、“;”分隔数据。
[D?]表示数据标签,表示需要赋值给传感器的数据,在这个协议中的三个[D?]依次代表赋值给食物剩余量、投喂食物量、开始喂食三个传感器。
[T:]表示结束符标签,[T:#]则表示传输的数据以“#”结束。
例如,通过STM32给TLINK平台发送ZLJ:120;100;0;#,则表示为当前食物的剩余量为120克,投喂食物量为100克,开始喂食为OFF。
可以通过手机或是电脑实时观战接收到的数据,并会可以自动的生成折线图,可以更加直观的观察食物的剩余量。同时可以电脑端给MCU发送数据以及操作指令使其完成相应的动作。手机APP远程查看如图所示。
可以通过TLINK平台设置定时向MCU发送指令或是数据,使其做出相应的动作。这样就可以通过定时使喂食装置每天按时投喂,避免忘记。我这里设置为每天中午的12点,TLINK平台会给STM32发送一个“FEED_ON”,当STM32接收到数据时,进入串口中断,输出PWM波,控制舵机旋转,使食物可以掉落到碗中,以实现定时喂食的功能。如图所示。
TLINK平台支持报警设置,可以自己设定剩余的食物低于某个值时,进行微信或是短信提醒。如图4.6所示。同时也可以设置自动进行相应的动作,例如,可以设置当剩余的食物量小于20克时,微信和短信报警提醒并进行投食动作。如图所示。
首先对STM32部分实现功能的整体逻辑进行分析,首先进行系统时钟的初始化,确保STM32的时钟周期正常运行。其次进行串口2的初始化,确保串口2可以正常的接收数据。然后进行HX711模块的初始化,确保HX711模块可以正常工作,进行可以得到压力传感器测量出的食物的重量。而后进行中断优先级的初始化,本程序中主要用到了串口2的接收中断,所以只需要配置串口2的中断优先级。接着进行定时器3初始化,确保定时器3的通道1可以输出PWM波控制舵机旋转。舵机回归初始位置,能够使装置上电后,舵机回到初始位置。最后称取毛皮重量。判断串口是否接收到数据。若串口接收到数据,则进入串口中断,执行相应的程序。反之,则进行循环:称重—>给TLINK平台发送数据—>延时1秒。整体流程图如图所示。其次对使用ESP8266连接TLINK平台、控制舵机旋转、HX711模块得到重量的功能进行独立的分析。
此部分主要是通过串口发送AT指令给ESP8266,以实现ESP8266与TLINK平台的连接。主要流程为:串口与ESP8266连接、判断是否连接成功、发送指令将8266设置为STA模式、发送8266所要连接的WIFI名及密码、建立TCP连接、进入透传模式、发送设备的序列号、传输数据。具体流程图如图所示。
1.串口与ESP8266连接:串口的RX与ESP8266的TX相连,串口的TX与8266的RX相连。
2.判断是否连接成功:通过串口给ESP8266发送AT,如果连接成功ESP8266会返回“ok”,否则等待直到连接成功。程序如下:
void checkESP8266(void)
{
memset(RXBuffer,0,RXBUFFER_LEN);//初始化接收BUF
sendString(USART2,"AT\r\n"); //串口发送AT指令,ESP8266收到该指令会回复“OK”
while(findStr(RXBuffer,"OK",500)==0)
{
sendString(USART2,"AT\r\n"); //未收到,重复发送
Delay_ms(500);
}
}
3.发送指令将8266设置为STA模式:通过串口发送AT指令:AT+CWMODE=1,即可将其设置为STA模式。部分程序如下:
memset(RXBuffer,0,RXBUFFER_LEN);
sendString(USART2,"AT+CWMODE?\r\n"); //发送AT指令,询问esp8266的模式
if(findStr(RXBuffer,"CWMODE:1",200)==0)
{
memset(RXBuffer,0,RXBUFFER_LEN);
sendString(USART2,"AT+CWMODE_CUR=1\r\n");//发送AT指令
if(findStr(RXBuffer,"OK",200)==0)
{
return 0;
}
}
4.发送8266所要连接的WIFI名及密码:通过串口发送AT指令:AT+CWJAP=“所要连接的WIFI名”,“WIFI的密码”。程序如下:
void connectAP(u8* ssid,u8* pwd)
{
memset(TXBuffer,0,RXBUFFER_LEN);
memset(RXBuffer,0,RXBUFFER_LEN);
sprintf(TXBuffer,"AT+CWJAP_CUR=\"%s\",\"%s\"\r\n",ssid,pwd);//其中ssid、pwd均为宏定义,分别为wifi名称及密码
sendString(USART2,TXBuffer);
while(findStr(RXBuffer,"OK",800)==0)
{
sendString(USART2,TXBuffer);
Delay_ms(800);
}
}
5.建立TCP连接:通过串口发送AT指令:AT+CIPSTART=“TCP”,“TLINK的IP地址”,端口号。部分程序如下:
memset(RXBuffer,0,RXBUFFER_LEN);
memset(TXBuffer,0,RXBUFFER_LEN);
sendString(USART2,"+++");
Delay_ms(500);
sprintf(TXBuffer,"AT+CIPSTART=\"%s\",\"%s\",%d\r\n",mode,ip,port);
sendString(USART2,TXBuffer);
while(findStr(RXBuffer,"CONNECT",800)==0)
{
sendString(USART2,TXBuffer);
Delay_ms(800);
}
6.进入透传模式:通过串口发送AT指令:AT+CIPMODE=1、AT+CIPSEND,即可进入透传模式。透传模式下,可以直接输送数据,无需使用AT+CIPSEND指令。部分程序如下:
memset(RXBuffer,0,RXBUFFER_LEN);
sendString(USART2,"AT+CIPMODE=1\r\n");
while(findStr(RXBuffer,"OK",300)==0)
{
sendString(USART2,"AT+CIPMODE=1\r\n");
Delay_ms(300);
}
memset(RXBuffer,0,RXBUFFER_LEN);
sendString(USART2,"AT+CIPSEND\r\n");
7.发送设备的序列号:通过串口发送所要连接的设备的序列号,进行连接。每个设备的序列号是唯一的。程序如下:
void sendBuffertoServer(u8* buffer)
{
memset(RXBuffer,0,RXBUFFER_LEN);
sendString(USART2,buffer); //其中buffer为宏定义,为设备的序列号
}
8.传输数据:通过串口发送想要发送的数据,数据的形式要按照自己定义的传输协议去写。程序如下:
void sendDeviceStatus(DeviceSta_Strcture * pdevsta)
{
char buffer[25] = {0};// 食物剩余量 投喂按钮 喂食状态
sprintf(buffer,"ZLJ:%d;%d;%d;#",pdevsta->Shengyu,pdevsta->Toushi,pdevsta->flag);
sendBuffertoServer(buffer);
}
本部分程序主要为串口初始化,以及串口中断函数的编写,主要实现Stm32通过串口2接收TLINK平台发送来的数据。当串口2接收到数据时,会进入串口2中断,运行串口中断内的程序。使用库函数编程,部分程序如下。
//串口2时钟使能:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB2Periph_USART2,ENABLE);
//串口2引脚配置:
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;//TX串口输出PA2
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;//RX 串口输入PA3
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//模拟输入
GPIO_Init(GPIOA,&GPIO_InitStructure); /*初始化GPIO*/
//串口2初始化设置:
USART_InitStructure.USART_BaudRate = 115200;//波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2, &USART_InitStructure);
USART_Cmd(USART2, ENABLE);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);
//中断优先级配置:
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;//串口2中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
以上部分为串口2的初始化部分,在串口2接收到TLINK平台发来的数据后,进入串口中断,在串口中断中执行相应的程序,部分程序如下:
static u8 i = 0;
if(USART_GetITStatus(USART2, USART_IT_RXNE))
{
RXBuffer[i++] = USART_ReceiveData(USART2);
if(i==RXBUFFER_LEN)
{
i = RXBUFFER_LEN-1;
}
}
if(USART_GetITStatus(USART2, USART_IT_IDLE))
{
USART_ReceiveData(USART2);
i = 0;
processDeviceStatus(&device);
}
本部分程序主要为通过HX711模块将压力传感器输出的模拟信号转换为Stm32可读的数字信号。本文中HX711模块输入通道使用A通道,增益为128。程序如下:
u32 HX711_Read(void)
{
unsigned long count;
unsigned char i;
HX711_DOUT=1;
Delay_us(1);
HX711_SCK=0;
count=0;
while(HX711_DOUT);
for(i=0;i<24;i++)
{
HX711_SCK=1;
count=count<<1;
Delay_us(1);
HX711_SCK=0;
if(HX711_DOUT)
count++;
Delay_us(1);
}
HX711_SCK=1;
count=count^0x800000;//第25个脉冲下降沿来时,转换数据
Delay_us(1);
HX711_SCK=0;
return(count);
}
经过以上程序得到的数字值后,需要将此值转换为重量值,此部分程序如下:
u32 Get_Weight(void)
{
HX711_Buffer = HX711_Read();
if(HX711_Buffer > Weight_Maopi)
{
Weight_Shiwu = HX711_Buffer;
Weight_Shiwu = Weight_Shiwu - Weight_Maopi; //获取实物的AD采样数值。
Weight_Shiwu = (s32)((float)Weight_Shiwu/GapValue); //计算实物的实际重量
HX711_Buffer = Weight_Shiwu ;
}
return HX711_Buffer ;
}
本部分程序主要为定时器3通道1的初始化,并使用Stm32的固件库中函数TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1)输出PWM波,使舵机旋转。该函数有两个参数,第一个参数为定时器号,第二个参数为占空比的参数。部分程序如下。
//使能定时器3的时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//配置定时器3的引脚:
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);
//初始化定时器3的基本配置:
TIM_TimeBaseInitStructure.TIM_Period=per; //自动装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
//初始化输出比较通道1:
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OC1Init(TIM3,&TIM_OCInitStructure); //输出比较通道1初始化
//使能定时器3:
TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3,ENABLE);//使能预装载寄存器
TIM_Cmd(TIM3,ENABLE); //使能定时器
以上部分为定时器3通道1的初始化部分,可以通过下面的setFEED()子函数控制舵机旋转合适的角度。
void setFEED(DeviceSta_Strcture * pdevsta)
{
u8 i;
if(Flag == 0 )
{
Flag = 1;//正转
for(i=0;i<3;i++)//喂食,旋转三次
{
TIM_SetCompare1(TIM3,FEED[i]);//FEED为数组,存放舵机的旋转角度
Delay_ms(1000);
}
}
else
{
Flag = 0;//反转
for(i=3;i<6;i++)
{
TIM_SetCompare1(TIM3,FEED[i]);
Delay_ms(1000);
}
}
pdevsta->flag = 0;
}
TLINK平台的调试主要通过网络调试助手通过TCP连接,查看是否可与TLINK进行数据的交互,首先使用网络调试助手连接TLINK平台,连接成功后,通过网络调试助手向TLINK发送连接设备的唯一序列号,连接后,便可进行数据交互。结果如图所示。
Stm32部分的调试则在Keil中使用Debug完成的,通过连接CMSIS-DAP无线仿真器进行在线的调试。可以查看Stm32是否连接上ESP8266、是否可以连接上WiFi、是否连接到TLINK平台、是否可以与TLINK平台进行数据交互以及是否可以输出PWM波。
通过Stm32向ESP8266发送AT,RXBuffer中接收到“OK”则表示二者连接成功。其中RXBuffer内为储存串口2接收到的数据信息。通过Dubeg将其添加到Watch1中进行数据查看,可以直观的观测到到串口接收到的数据信息,更加偏于进行Stm32部分的软件调试。如图所示。
通过Stm32向ESP8266发送所要连接的Wifi的名字及密码,RXBuffer中接收到“OK”则表示已经连接上WiFi。其中两个形参ssip、pwd分别表示为WiFi名、密码。如图所示。
通过Stm32向ESP8266发送通信协议、TLINK平台的IP地址、端口号,发送完成后,延时0.5秒,再次发送设备的序列号进行连接,连接成功后,通过APP可以查看到设备显示“已连接”。结果图如图所示。
TLINK连接成功后,则可以进行数据的交互,可以通过TLINK平台向Stm32发送指令:“FEED_ON”表示开始喂食,“FEED_OFF”表示喂食停止。如图所示。
通过定时器3通道1输出周期为20ms,占空比为12.5%的PWM,即高电平时间为2.5ms。如图所示。
本次毕业设计还存在着一次缺陷,比如在3D打印的部分,由于3D打印机的精度不够高,导致打印出的成品,有些粗糙,会给压力传感器的测量带来问题,以后争取改进!