宠物喂食器的设计-基于涂鸦三明治三件套

宠物喂食器的设计-基于涂鸦三明治三件套

本文章允许涂鸦智能转载使用
去年疫情突发,全国很多地区封城,封小区,让原本备受宠爱的主子与铲屎官异地分离。遇到有准备的铲屎官,主子们还能勉强度日,那些没有准备的主子只能靠吃猫砂,吃垃圾度日,甚至有些小可怜被活活饿死。
疫情缓解后,为了避免这样的事件再次发生,也为了解放懒惰的铲屎官,于是自动猫砂盆,自动喂食器,自动喂水器的需求不断提升。有数据显示,疫情后自动猫砂盆增长879%,自动喂水器增长120%,自动喂食器增长也超一倍。毕竟主子是家里的老大,要吃好喝好还要拉好。
此次DIY自动投食器由涂鸦智能开展的【宠物喂食器】实战营策划,并提供了涂鸦三明治开发套件,其中包括:
涂鸦三明治 Wi-Fi MCU 通信板1
宠物喂食器的设计-基于涂鸦三明治三件套_第1张图片
涂鸦三明治H桥直流电机驱动功能板
1

宠物喂食器的设计-基于涂鸦三明治三件套_第2张图片
涂鸦三明治直流供电电源板*1。
宠物喂食器的设计-基于涂鸦三明治三件套_第3张图片
除此之外,用户还需要自行准备MCU控制板和电机等组件,该WiFi模组出厂默认为透传模式,只负责数据转发,不负责数据处理,所以我们只需要准备MCU用于数据处理和外设控制。

涂鸦智能平台

1.前往涂鸦智能开发平台

(https://auth.tuya.com/register_source=7b811ac2e872ccb62376ba4dfe0568eb)注册开发者账号
宠物喂食器的设计-基于涂鸦三明治三件套_第4张图片

2.在涂鸦loT平台创建产品

宠物喂食器的设计-基于涂鸦三明治三件套_第5张图片

3.在小家电品类里面找到【宠物喂食器】

宠物喂食器的设计-基于涂鸦三明治三件套_第6张图片
宠物喂食器的设计-基于涂鸦三明治三件套_第7张图片

4.使用MCU SDK方案,完善产品信息

宠物喂食器的设计-基于涂鸦三明治三件套_第8张图片
宠物喂食器的设计-基于涂鸦三明治三件套_第9张图片

5.产品创建后添加标准功能

宠物喂食器的设计-基于涂鸦三明治三件套_第10张图片

6.硬件开发选项

宠物喂食器的设计-基于涂鸦三明治三件套_第11张图片
以上步骤更加具体配置可参考涂鸦IOT平台产品创建流程(https://shimo.im/docs/HvHRgTtjUDYIvLlA/read)产品创建完成后下载开发资料,建议全部下载,其中MCU SDK的内容会根据你所选择的标准功能不同而不同,为了方便可在选择功能时尽可能多的考虑到需要配置的功能,当然,即使你一个不选,SDK也开放了各个功能的函数,只是被屏蔽,可自行放开。宠物喂食器的设计-基于涂鸦三明治三件套_第12张图片

功能调试

MCU对接方案通信原理图

宠物喂食器的设计-基于涂鸦三明治三件套_第13张图片

1.WIFI模组调试

打开上一步最终下载的文件如图,接着我们打开涂鸦调试助手宠物喂食器的设计-基于涂鸦三明治三件套_第14张图片
宠物喂食器的设计-基于涂鸦三明治三件套_第15张图片

将WiFi的通信板的串口1接到usb-ttl上,接到电脑,一定是串口1,串口0是查看模组本身的logo的,打开涂鸦调试助手。选择MCU模拟,此时调试助手就相当于是MCU,可以与WiFi模组通信,可用此来调试WiFi模组。选择好串口,波特率默认9600.功能点调试文件选择之前下载的json文件。初始化配置保持默认,点击开始调试。如收到以下数据说明模组与助手连接正常,可以开始调试。
宠物喂食器的设计-基于涂鸦三明治三件套_第16张图片
此时我们下载涂鸦智能APP,注册后选择添加设备,在小家电里面找到宠物喂食器,选择2.4G的WiFi网络。输入密码。点击下一步
宠物喂食器的设计-基于涂鸦三明治三件套_第17张图片
此时在模组调试助手点击smart配网,手机点击下一步
宠物喂食器的设计-基于涂鸦三明治三件套_第18张图片
宠物喂食器的设计-基于涂鸦三明治三件套_第19张图片
配网成功后会在手机APP和调试助手同时看到相应信息。连接成功后会定时发送心跳包保持连接。
宠物喂食器的设计-基于涂鸦三明治三件套_第20张图片
至此WiFi模组配网完成,改配网信息会保存在WiFi模组内部,下次上电会自动连接该网络。如果更换网络环境需要重置后再次配网。此时可在DP CMD里面测试相关DP点的数据上报,观察有无数据的上报下发。

2.MCU调试

WiFi模组调试完成之后我们需要调试我们的主控,也就是MCU,在我这里就是STM32F103ZET6。在进行MCU调试之前我们需要先进行SDK的移植,将之前下载的SDK移植到我们的STM32项目中。

1.工程搭建

本文实在串口驱动实验的基础上搭建的,因为后面需要用到串口;
usart.h

#ifndef __USART_H
#define __USART_H
#include "stdio.h"	
#include "sys.h" 

#define USART_REC_LEN  			200  	//定义最大接收字节数 200
#define EN_USART1_RX 			1		//使能(1)/禁止(0)串口1接收
	  	
extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART_RX_STA;         		//接收状态标记	
//如果想串口中断接收,请不要注释以下宏定义
void uart_init(u32 bound);
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);

#endif

usart.c

#include "sys.h"
#include "usart.h"	
#include "mcu_api.h"
#include "protocol.h"
#include "system.h"
#include "wifi.h"
// 	 
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h"					//ucos 使用	  
#endif

#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 

}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
	return ch;
}
#endif 
 
#if EN_USART1_RX   //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   	
u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
u16 USART_RX_STA=0;       //接收状态标记	  
  
void uart_init(u32 bound)
{
	//GPIO端口设置
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟

	//USART1_TX   GPIOA.9
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9

	//USART1_RX	  GPIOA.10初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  

	//Usart1 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器

	//USART 初始化设置

	USART_InitStructure.USART_BaudRate = bound;//串口波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式

  USART_Init(USART1, &USART_InitStructure); //初始化串口1
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
  USART_Cmd(USART1, ENABLE);                    //使能串口1 

}

void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
        /* 发送一个字节数据到USART */
        USART_SendData(pUSARTx,ch);
               
        /* 等待发送数据寄存器为空 */
        while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);        
}

void USART1_IRQHandler(void)
{
  uint8_t ucTemp;
	if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)
	{		
		ucTemp = USART_ReceiveData(USART1);
		uart_receive_input(ucTemp);   
	}	
	USART_ClearFlag(USART1,USART_FLAG_RXNE);	
}
 
#endif	

写一个发送单字节函数,此函数必须,用于向WiFi模组发送数据。

void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
        /* 发送一个字节数据到USART */
        USART_SendData(pUSARTx,ch);
               
        /* 等待发送数据寄存器为空 */
        while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);        
}

2.移植SDK

基础工程搭建完成后将SDK放入工程,记得在keil中添加文件路径。
宠物喂食器的设计-基于涂鸦三明治三件套_第21张图片
这个时候要是编译,会疯狂报错,主要是官方方便我们修改。
宠物喂食器的设计-基于涂鸦三明治三件套_第22张图片
在下图的函数中填入上面写的串口单字节发送函数
宠物喂食器的设计-基于涂鸦三明治三件套_第23张图片

3.确认protocol.h的相关宏定义

1.定义 PID。PRODUCT_KEY 为产品 PID 宏定义。PID 即产品 ID, 为每个产品的唯一标识,可在 IoT 平台的产品详情页面获取。
宠物喂食器的设计-基于涂鸦三明治三件套_第24张图片

#define PRODUCT_KEY "gktqnpciyofn****"    //开发平台创建产品后生成的16位字符产品唯一标识

2.定义 Wi-Fi 模块工作模式。CONFIG_MODE 为配网方式,支持默认模式(AP 和 SmartConfig 互相切换)、安全模式、防误触模式。建议选择防误触模式。
3.定义模块工作方式(必选)
如果配网按键和 LED 接在 MCU 端,即选择模块和 MCU 配合处理工作模式(常用),保持 WIFI_CONTROL_SELF_MODE 宏定义处于被注释状态。

//#define         WIFI_CONTROL_SELF_MODE                       //Wi-Fi 自处理按键及LED指示灯,如为MCU外接按键/LED指示灯请关闭该宏

如果配网指示灯和按键是接在 Wi-Fi 模块上的,即选择模块自处理工作模式,开启 WIFI_CONTROL_SELF_MODE 宏定义,然后根据实际的硬件连接,将指示灯和按键所连接的 GPIO 脚位填入下面两个宏定义。

#ifdef          WIFI_CONTROL_SELF_MODE             //模块自处理
    #define     WF_STATE_KEY            14         //Wi-Fi 模块状态指示按键,请根据实际 GPIO 管脚设置
    #define     WF_RESERT_KEY           0          //Wi-Fi 模块重置按键,请根据实际 GPIO 管脚设置
#endif

以上三点较为重要,其他可自行安排,都有相关介绍。

移植protocol.c文件及函数调用

  1. 将wifi.h 文件保存至存放 Wi-Fi 相关文件的文件夹中,例如 main.c文件夹。而我是创建了一个WiFi文件夹,WiFi.c只是引用了wifi.h这个头文件,其他为空。
  2. 在 MCU 串口及其他外设初始化后调用 mcu_api.c 文件中的 wifi_protocol_init() 函数。
  3. 将 MCU 串口单字节发送函数填入 protocol.c 文件中 uart_transmit_output 函数内,并删除 #error。此步骤在上文已介绍。不赘述。
  4. 在串口接收中断服务函数里面调用 mcu_api.c 文件内的 uart_receive_input 函数,并将接收到的字符作为参数传入。示例如下:
void USART1_IRQHandler(void)
{
  uint8_t ucTemp;
	if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)
	{		
		ucTemp = USART_ReceiveData(USART1);
		uart_receive_input(ucTemp);   
	}	
	USART_ClearFlag(USART1,USART_FLAG_RXNE);	
}
  1. 在主函数的while(1) 循环后调用 mcu_api.c 文件内的 wifi_uart_service() 函数。该函数用于wifi串口数据处理服务,同时维持心跳。此函数无需任何判断条件,直接调用。在使用该函数时最好不要关闭总中断或串口中断,防止数据丢失,如必要,尽可能短的时间关闭。
    在这里插入图片描述
    走到这一步,SDK移植已经完成了,接下来将单片机的串口街道电脑进行调试。此时调试助手选择模组模拟。同时我们在protocol.c文件中将all_data_update() 函数中的所有DP点上传函数打开,默认为0。宠物喂食器的设计-基于涂鸦三明治三件套_第25张图片
    此时MCU接到调试助手,打开串口,添加DP点文件,启动调试,便会看到所有DP点的上报宠物喂食器的设计-基于涂鸦三明治三件套_第26张图片
    进入DP CMD添加一个开启小夜灯的指令并下发,便可看到模组成功接收,说明MCU的SDK移植成功。
    宠物喂食器的设计-基于涂鸦三明治三件套_第27张图片
    一个完整的自动喂食器的MCU工程便已搭建完成,后续我们只需要解析wifi模组下发的消息,并进行相应的外设控制便可。当然,每次MCU完成动作后也要上传数据给模组。完成服务器和手机APP端的数据刷新。

3.相关功能完善

1.一键配网功能

配网有两种模式AP配网和smart配网,这里仅介绍smart类型。
配网指令有两个函数可以实现:mcu_reset_wifi() 和 mcu_set_wifi_mode()。通常在按键触发配网后,在按键处理函数中调用。mcu_reset_wifi()调用后复位 Wi-Fi 模组,复位后之前的配网信息全部清除。mcu_reset_wifi() 每调用一次,Wi-Fi 模块即在 AP 和 Smart 之间切换一次配网模式。
mcu_set_wifi_mode()参数为SMART_CONFIG和AP_CONFIG。调用后清除配网信息,进入 Smart 模式或者 AP 模式。值了在按键KEY0中断函数中调用 mcu_get_wifi_work_state() 函数主动获取 Wi-Fi 状态。根据 Wi-Fi 状态,写入相应闪灯的模式。通过switch()判断进入何种状态,状态可选参数如下:
exti.c

#include "exti.h"
#include "led.h"
#include "key.h"
#include "delay.h"
#include "usart.h"
//#include "beep.h"
#include "mcu_api.h"
#include "protocol.h"
#include "system.h"
#include "wifi.h"
#include "lcd.h"
#include "text.h"
#include "motor.h"

//外部中断0服务程序
void EXTIX_Init(void)
{
 
 	EXTI_InitTypeDef EXTI_InitStructure;
 	NVIC_InitTypeDef NVIC_InitStructure;

    KEY_Init();	 //	按键端口初始化

  	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	//使能复用功能时钟

    //GPIOE.2 中断线以及中断初始化配置   下降沿触发
  	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);

  	EXTI_InitStructure.EXTI_Line=EXTI_Line2;	//KEY2
  	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);	 	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

   //GPIOE.3	  中断线以及中断初始化配置 下降沿触发 //KEY1
  	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
  	EXTI_InitStructure.EXTI_Line=EXTI_Line3;
  	EXTI_Init(&EXTI_InitStructure);	  	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

   //GPIOE.4	  中断线以及中断初始化配置  下降沿触发	//KEY0
  	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);
  	EXTI_InitStructure.EXTI_Line=EXTI_Line4;
  	EXTI_Init(&EXTI_InitStructure);	  	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器


   //GPIOA.0	  中断线以及中断初始化配置 上升沿触发 PA0  WK_UP
 	 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); 

  	EXTI_InitStructure.EXTI_Line=EXTI_Line0;
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  	EXTI_Init(&EXTI_InitStructure);		//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器


  	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;			//使能按键WK_UP所在的外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2, 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;					//子优先级3
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure); 

    NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;			//使能按键KEY2所在的外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2, 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;					//子优先级2
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure);


  	NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;			//使能按键KEY1所在的外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;					//子优先级1 
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure);  	  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

	  NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;			//使能按键KEY0所在的外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;					//子优先级0 
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure);  	  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
 
}

//外部中断0服务程序 
void EXTI0_IRQHandler(void)
{
	delay_ms(10);//消抖
	if(WK_UP==1)	 	 //WK_UP按键
	{			
				LED0=!LED0;	 
			  mcu_reset_wifi();
        mcu_set_wifi_mode(SMART_CONFIG);
//        EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位 
	}
	EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位  
}
 
//外部中断2服务程序
void EXTI2_IRQHandler(void)
{
	delay_ms(10);//消抖
	if(KEY2==0)	  //按键KEY2
	{
		int i=1000;
		LED0=!LED0;
		for(i=1000;i>0;i--)
			motor_control_F(2);
		delay_ms(1000);
	}		 
	EXTI_ClearITPendingBit(EXTI_Line2);  //清除LINE2上的中断标志位  
}
//外部中断3服务程序
void EXTI3_IRQHandler(void)
{
	delay_ms(10);//消抖
	if(KEY1==0)	 //按键KEY1
	{			
		int i=1000;	 
		LED0=!LED0;
		for(i=1000;i>0;i--)
			motor_control_Z(2);
		delay_ms(1000);
		//LED1=!LED1;
	}		 
	EXTI_ClearITPendingBit(EXTI_Line3);  //清除LINE3上的中断标志位  
}

void EXTI4_IRQHandler(void)
{
	delay_ms(10);//消抖
	if(KEY0==0)	 //按键KEY0
	{
		  LED0=!LED0;
		  switch(mcu_get_wifi_work_state())
					{

						case SMART_CONFIG_STATE:
								Led_Blink_Quick();
								POINT_COLOR=BLUE;
								Show_Str(30,20,200,16,"处于 Smart 配置状态",16,0);	
						break;
						case AP_STATE:
								Led_Blink_Slow();
								POINT_COLOR=BLUE;
								Show_Str(30,40,200,16,"处于 AP 配置状态",16,0);
						break;
						case WIFI_NOT_CONNECTED:
								GPIO_ResetBits(GPIOB,GPIO_Pin_5);
								POINT_COLOR=BLUE;
								Show_Str(30,60,200,16,"Wi-Fi 配置完成,正在连接路由器",16,0);
						break;
						case WIFI_CONNECTED:
								GPIO_SetBits(GPIOB,GPIO_Pin_5);
								POINT_COLOR=BLUE;
								Show_Str(30,80,200,16,"路由器连接成功",16,0);
						break;
						case WIFI_CONN_CLOUD:
								GPIO_SetBits(GPIOB,GPIO_Pin_5);
								LCD_Clear(WHITE);//清屏	
								POINT_COLOR=BLUE;
								Show_Str(30,100,200,16,"WIFI已经连接上云服务器",16,0);	
						
						break;
						default:break;
					}
	}		 
	EXTI_ClearITPendingBit(EXTI_Line4);  //清除LINE4上的中断标志位  
}

在外部中断函数0里面添加了mcu_reset_wifi(),复位模组,清除全部配网信息,然后调用mcu_set_wifi_mode()函数,参数添加SMART_CONFIG进入smart模式。在这用TFTLCD屏幕显示是否进入smart配网模式,还可显示其他状态。

现在将MCU与模组通过串口1连接,注意TX与RX反接并共地。按下按键,LED快闪,打开手机APP进行配网,当wifi配置完成灯会熄灭,连接上路由器之后灯会重新点亮,并保持常亮。此过程本人已测试无问题,但是过程比较长不适合贴图,会在视频中展示。

2.添加小夜灯等类似功能

配网完成了,那么怎么执行功能呢?在protocol.c中dp_download_handle()函数可以处理下发的数据。在此函数中会对下发的指令进行归类,我们找到小夜灯的处理,这里可以进行小夜灯指令的处理,处理完成之后会上报数据,用于更新APP数据。我们跳转进dp_download_light_handle()函数,此函数中有具体的处理,针对不同的开或关会进入不同的if函数。我们在对LED的端口初始化后便可以将开关灯填入。达到不同下发指令实现开关灯。开关功能类似,不赘述。
宠物喂食器的设计-基于涂鸦三明治三件套_第28张图片

3. 添加手动喂食执行功能

这里没有使用涂鸦提供的H桥驱动板,大家要是想要用,直接上一个12V的减速电机,每分钟12转,驱动力大,速度慢,易于控制。将电机接到驱动板的U和V接线柱上,控制口PWM1和PWM2接到单片机PA2和PA3。给PA2和PA3不同的高低电平就可以实现正反转,因为电机本身速度比较慢,就不用软件进行控制速度了。而且因为场景的关系,不用控制正反两个反向,只控制正转和停止。
我在这里用的就不是涂鸦提供的了,步进电机:28BYJ-48,驱动电路:ULN2003芯片的驱动板,
宠物喂食器的设计-基于涂鸦三明治三件套_第29张图片
宠物喂食器的设计-基于涂鸦三明治三件套_第30张图片
motor.c

#include "motor.h"
#include "delay.h"
#include "led.h"


#define  A1   GPIO_SetBits(GPIOC, GPIO_Pin_3);
#define  A2   GPIO_ResetBits(GPIOC, GPIO_Pin_3);

#define  B1   GPIO_SetBits(GPIOC, GPIO_Pin_4);
#define  B2   GPIO_ResetBits(GPIOC, GPIO_Pin_4);

#define  C1   GPIO_SetBits(GPIOC, GPIO_Pin_5);
#define  C2	 GPIO_ResetBits(GPIOC, GPIO_Pin_5);

#define  D1   GPIO_SetBits(GPIOC, GPIO_Pin_6);
#define  D2   GPIO_ResetBits(GPIOC, GPIO_Pin_6);

void motor_configuration(void)
{
	 GPIO_InitTypeDef  GPIO_InitStructure;
		
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);	 //使能PB,PE端口时钟
		
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;				 //PC.012 端口配置
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
	 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
	 GPIO_Init(GPIOC, &GPIO_InitStructure);					 //根据设定参数初始化GPIOC.5
	 GPIO_ResetBits(GPIOC,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6);						 //PC.012 输出低
		
}
void motor_control_F(int n)
{
	A1;
	delay_ms(n);
	A2;
	B1;
	delay_ms(n);
	B2;
	C1;
	delay_ms(n);
	C2;
	D1;
	delay_ms(n);
	D2;
}

void motor_control_Z(int n)
{
	A1;
	delay_ms(n);
	A2;
	D1;
	delay_ms(n);
	D2;
	C1;
	delay_ms(n);
	C2;
	B1;
	delay_ms(n);
	B2;
}
void Motor_Ctrl_Off(void){
	GPIO_ResetBits(GPIOC,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6);
}

编写控制函数,参数为投喂量,通过转动时间来控制投喂量,延时时间需要与宠物的饭盒出粮口搭配,不同出粮口修改延时基数。
随后在dp_download_quick_feed_handle()函数中执行该函数,参数由mcu_get_dp_download_value()函数提供,该函数会提取手机下发的命令。
宠物喂食器的设计-基于涂鸦三明治三件套_第31张图片

最后我还加了语音控制功能,下面的文件里有这个工程的全部文件,包括语音模块的设计,就是类似于小度小度那样的智能管家,这里就不在一一介绍了,大家自行下载,看我的演示视频吧。
文件地址:https://download.csdn.net/download/kekebb/16207490

你可能感兴趣的:(智能家居,stm32)