STM32+ONEnet+小程序实现智能家居

一、需求分析

1、获取温湿度显示在OLED和微信小程序

2、获取光照度显示在OLED和微信小程序

3、远程开关灯(使用MQTT+Cjson)

4、远程开关蜂鸣器(使用MQTT+Cjson)

5、蜂鸣器自动报警(光照度 < 5000 && 湿度 < 80 &&温度 < 38)

6、按键外部中断控制LED+蜂鸣器

硬件:

1.GY-30光照度传感器

2.DHT11温湿度传感器

3.蜂鸣器

4.LED灯

5.8266-01s

6.OLED显示屏

7.MCU

二、引脚定义

LED PA0
GY-30 PB14 PB15
OLED PB8 PB9
DHT11 PA7
BEEP PB12
USART1 PA9(TX) PA10 (RX) 调试串口
USART2 PA2(TX) PA3 (RX) 8266-01s发送AT指令
按键: PB0:LED PB10:蜂鸣器 (按键中断中别加入延时)
内部定时器 TIM4 温湿度需要(也可不用,可用Dealy驱动)
  ESP8266-01S+MQTT:
    1、烧录安信可8266-01S模块
    ESP8266-01S烧录模式:
    EN:高电平
    RST:按键控制转低电平,低电平有效
    IO0:低电平
    IO2:低电平
    2、运行模式时,只需要接VCC+GND+RXD+TXD即可

三、源代码

因代码过多,因此需要源码请私信我或者有问题私信我交流

以下代码包含了MCU驱动所有的主要程序

光照度传感器GY-30

#include "GY30.h"
#include "TIM.h"


void GPIOConfig( void )
{
	GPIO_InitTypeDef GPIO_InitStruct;
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_50MHz;
	GPIO_InitStruct.GPIO_Pin	= sda | scl;
	GPIO_Init( GPIOB, &GPIO_InitStruct );
}
/*启动:SDA/SCL为低
停止:SDA/SCL为高*/
void BH1750_Start()
{
	GPIO_SetBits( GPIOB, sda );     /*SDA拉高*/
	GPIO_SetBits( GPIOB, scl );     /*SCL拉高*/
	TIM4_Delayms(5);                  /*等待时间*/
	GPIO_ResetBits( GPIOB, sda );   /* SDA拉低 */
	TIM4_Delayms(5);                    /* 等待时间*/
	GPIO_ResetBits( GPIOB, scl );   /* SCL拉低 */
}
void BH1750_Stop()
{
	GPIO_ResetBits( GPIOB, sda );   /*SDA拉低*/
	GPIO_SetBits( GPIOB, scl );     /* SCL拉高 */
	TIM4_Delayms(5);                    /*  */
	GPIO_SetBits( GPIOB, sda );     /* SDA拉高*/
	TIM4_Delayms(5);                   /* */
}
void BH1750_SendACK( unsigned int ack )
{
	GPIO_InitTypeDef GPIO_InitStruct;

	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_50MHz;
	GPIO_InitStruct.GPIO_Pin	= sda;
	GPIO_Init( GPIOA, &GPIO_InitStruct );
	
	if ( ack == 1 )                 /* */
		GPIO_SetBits( GPIOB, sda );
	else if ( ack == 0 )
		GPIO_ResetBits( GPIOB, sda );
	else
		return;

	GPIO_SetBits( GPIOB, scl );     /*  */
	TIM4_Delayms(5);                   /*  */
	GPIO_ResetBits( GPIOB, scl );   /* */
	TIM4_Delayms(5);                    /*  */
}
unsigned int BH1750_RecvACK()
{
	GPIO_InitTypeDef GPIO_InitStruct;

	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_IPU;        
	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_50MHz;
	GPIO_InitStruct.GPIO_Pin	= sda;
	GPIO_Init( GPIOA, &GPIO_InitStruct );

	GPIO_SetBits( GPIOB, scl );                           
	TIM4_Delayms(5);                                           
	if ( GPIO_ReadInputDataBit( GPIOB, sda ) == 1 )         
		mcy = 1;
	else
		mcy = 0;

	GPIO_ResetBits( GPIOB, scl );                          
	TIM4_Delayms(5);    
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init( GPIOA, &GPIO_InitStruct );	
	return(mcy);
}

void BH1750_SendByte( unsigned char dat )
{
	unsigned char i;
	for ( i = 0; i < 8; i++ )
	{
		if ( 0X80 & dat )
			GPIO_SetBits( GPIOB, sda );
		else
			GPIO_ResetBits( GPIOB, sda );

		dat <<= 1;
		GPIO_SetBits( GPIOB, scl );     
		TIM4_Delayms(5);                    
		GPIO_ResetBits( GPIOB, scl );   
		TIM4_Delayms(5);                  
	}
	BH1750_RecvACK();
}


unsigned char BH1750_RecvByte()
{
	unsigned char	i;
	unsigned char	dat = 0;
	unsigned char	bit;

	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_IPU;       
	GPIO_InitStruct.GPIO_Pin	= sda;
	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_50MHz;
	GPIO_Init( GPIOB, &GPIO_InitStruct );

	GPIO_SetBits( GPIOB, sda );                             
	for ( i = 0; i < 8; i++ )                             
	{
		dat <<= 1;
		GPIO_SetBits( GPIOB, scl );                     
		TIM4_Delayms(5);                                 

		if ( SET == GPIO_ReadInputDataBit( GPIOB, sda ) )
			bit = 0X01;
		else
			bit = 0x00;
		dat |= bit;                                    
		GPIO_ResetBits( GPIOB, scl );                   
		TIM4_Delayms(5);                                   
	}
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init( GPIOB, &GPIO_InitStruct );
	return(dat);
}

void Single_Write_BH1750( unsigned char REG_Address )
{
	BH1750_Start();                         
	BH1750_SendByte( SlaveAddress );       
	BH1750_SendByte( REG_Address );         
	//BH1750_SendByte(REG_data);       
	BH1750_Stop();                          
}

void Init_BH1750()
{
	GPIOConfig();
	Single_Write_BH1750( 0x01 );
}


void mread( void )
{
	unsigned char i;
	BH1750_Start();                        
	BH1750_SendByte( SlaveAddress + 1 );    

	for ( i = 0; i < 3; i++ )               
	{
		BUF[i] = BH1750_RecvByte();     
		if ( i == 3 )
		{
			BH1750_SendACK( 1 );   
		}else  {
			BH1750_SendACK( 0 );    
		}
	}

	BH1750_Stop();                          
	TIM4_Delayms(5);
}

 GY-30.h

#ifndef __BH1750_H__
#define __BH1750_H__


#include "stm32f10x.h"                  // Device header




#define sda	GPIO_Pin_14      /* SDA */
#define scl	GPIO_Pin_15      /* SCL */

#define   SlaveAddress 0x46    /*当ADD接地时,地址为0X46*/
	                        

extern unsigned char	BUF[8];        
extern int	dis_data;      
extern int	mcy;          

void Init_BH1750( void );
void conversion( unsigned int temp_data );
void Single_Write_BH1750( unsigned char REG_Address );  
unsigned char Single_Read_BH1750( unsigned char REG_Address ); 
void mread( void );                           
void GPIOConfig( void );


#endif

TIM.c

#include "stm32f10x.h"                  // Device header                 // Device header


void TIM4_Init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);  ///使能TIM4时钟
	TIM_TimeBaseInitStructure.TIM_Period    = 50000-1; 	//自动重装载值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 60-1;     //定时器分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);//初始化TIM4
}

//微秒级延时
void TIM4_Delayus(uint16_t xus)
{
	TIM_Cmd(TIM4,ENABLE); //启动定时器
	while(TIM4->CNT < xus);
	TIM4->CNT = 0;
	TIM_Cmd(TIM4,DISABLE); //关闭定时器
}
//毫秒级延时
void TIM4_Delayms(uint16_t xms)
{
	int i;
	for(i=0;i<xms;i++)
	{
		TIM4_Delayus(1000);
	}
}

DHT11.c


/**
 * ************************************************************************
 * 
 * @file My_DHT11.c
 * @author zxr
 * @brief 
 * 
 * ************************************************************************
 * @copyright Copyright (c) 2024 zxr 
 * ************************************************************************
 */
#include "DHT11.h"
#include "TIM.h"

/**
 * ************************************************************************
 * @brief 将DHT11配置为推挽输出模式
 * ************************************************************************
 */
 
void DHT11_Init(void)
{
	//RC开启GPIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//初始化GPIO
	GPIO_InitTypeDef Beep;
	Beep.GPIO_Mode = GPIO_Mode_Out_PP;
	Beep.GPIO_Pin = GPIO_Pin_7;
	Beep.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&Beep);
	
	GPIO_SetBits(GPIOA,GPIO_Pin_7 );

}
static void DHT11_PP_OUT(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin = DHT11_PIN;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;	
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}

/**
 * ************************************************************************
 * @brief 将DHT11配置为上拉输入模式
 * ************************************************************************
 */
static void DHT11_UP_IN(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin = DHT11_PIN;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}

/**
 * ************************************************************************
 * @brief 读取字节
 * @return temp
 * ************************************************************************
 */
uint8_t DHT11_ReadByte(void)
{
	uint8_t i, temp = 0;

	for (i = 0; i < 8; i++)
	{
		while (DHT11_ReadPin == 0);		// 等待低电平结束
		
		TIM4_Delayus(40);			//	延时 40 微秒
		
		if (DHT11_ReadPin == 1)
		{
			while (DHT11_ReadPin == 1);	// 等待高电平结束
			
			temp |= (uint8_t)(0X01 << (7 - i));			// 先发送高位
		}
		else
		{
			temp &= (uint8_t)~(0X01 << (7 - i));
		}
	}
	return temp;
}

/**
 * ************************************************************************
 * @brief 读取一次数据
 * @param[in] DHT11_Data  定义的结构体变量
 * @return 0或1(数据校验是否成功)
 * @note 它首先向DHT11发送启动信号,然后等待DHT11的应答。如果DHT11正确应答,
 * 		 则继续读取湿度整数、湿度小数、温度整数、温度小数和校验和数据,
 * 		 并计算校验和以进行数据校验
 * ************************************************************************
 */
uint8_t DHT11_ReadData(DHT11_Data_TypeDef *DHT11_Data)
{
	DHT11_PP_OUT();			// 主机输出,主机拉低
	DHT11_PULL_0;	
	TIM4_Delayms(18);				// 延时 18 ms
	
	DHT11_PULL_1;					// 主机拉高,延时 30 us
	TIM4_Delayus(30);	

	DHT11_UP_IN();				// 主机输入,获取 DHT11 数据
	
	if (DHT11_ReadPin == 0)				// 收到从机应答
	{
		while (DHT11_ReadPin == 0);		// 等待从机应答的低电平结束
		
		while (DHT11_ReadPin == 1);		// 等待从机应答的高电平结束
		
		/*开始接收数据*/   
		DHT11_Data->humi_int  = DHT11_ReadByte();
		DHT11_Data->humi_dec = DHT11_ReadByte();
		DHT11_Data->temp_int  = DHT11_ReadByte();
		DHT11_Data->temp_dec = DHT11_ReadByte();
		DHT11_Data->check_sum = DHT11_ReadByte();
		
		DHT11_PP_OUT();		// 读取结束,主机拉高
		DHT11_PULL_1;	
		
		// 数据校验
		if (DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_dec + DHT11_Data->temp_int + DHT11_Data->temp_dec)	
		{
			return 1;
		}		
		else
		{
			return 0;
		}
	}
	else		// 未收到从机应答
	{
		return 0;
	}
}

DHT11.h

/**
 * ************************************************************************
 * 
 * @file My_DHT11.h
 * @author zxr
 * @brief 
 * 
 * ************************************************************************
 * @copyright Copyright (c) 2024 zxr 
 * ************************************************************************
 */
#ifndef __MY_DHT11_H
#define __MY_DHT11_H
#include "stm32f10x.h"                  // Device header


#define DHT11_PORT			GPIOA
#define DHT11_PIN			GPIO_Pin_7

#define DHT11_PULL_1		GPIO_SetBits(DHT11_PORT, DHT11_PIN)
#define DHT11_PULL_0		GPIO_ResetBits(DHT11_PORT, DHT11_PIN)

#define DHT11_ReadPin		GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)

/**
 * ************************************************************************
 * @brief 存储传感器数据的结构体
 * 
 * 
 * ************************************************************************
 */
typedef struct
{
	uint8_t humi_int;			// 湿度的整数部分
	uint8_t humi_dec;	 		// 湿度的小数部分
	uint8_t temp_int;	 		// 温度的整数部分
	uint8_t temp_dec;	 		// 温度的小数部分
	uint8_t check_sum;	 		// 校验和

} DHT11_Data_TypeDef;


uint8_t DHT11_ReadData(DHT11_Data_TypeDef* DHT11_Data);
void DHT11_Init(void);
#endif

USART.c

/**
	************************************************************
	************************************************************
	************************************************************
	*	文件名: 	usart.c
	*
	*	作者: 		张继瑞
	*
	*	日期: 		2016-11-23
	*
	*	版本: 		V1.0
	*
	*	说明: 		单片机串口外设初始化,格式化打印
	*
	*	修改记录:	
	************************************************************
	************************************************************
	************************************************************
**/

//硬件驱动
#include "usart.h"
#include "delay.h"

//C库
#include <stdarg.h>
#include <string.h>
#include <stdio.h>


/*
************************************************************
*	函数名称:	Usart1_Init
*
*	函数功能:	串口1初始化
*
*	入口参数:	baud:设定的波特率
*
*	返回参数:	无
*
*	说明:		TX-PA9		RX-PA10
************************************************************
*/
void Usart1_Init(unsigned int baud)
{

	GPIO_InitTypeDef gpioInitStruct;
	USART_InitTypeDef usartInitStruct;
	NVIC_InitTypeDef nvicInitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	//PA9	TXD
	gpioInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
	gpioInitStruct.GPIO_Pin = GPIO_Pin_9;
	gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &gpioInitStruct);
	
	//PA10	RXD
	gpioInitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	gpioInitStruct.GPIO_Pin = GPIO_Pin_10;
	gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &gpioInitStruct);
	
	usartInitStruct.USART_BaudRate = baud;
	usartInitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;		//无硬件流控
	usartInitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;						//接收和发送
	usartInitStruct.USART_Parity = USART_Parity_No;									//无校验
	usartInitStruct.USART_StopBits = USART_StopBits_1;								//1位停止位
	usartInitStruct.USART_WordLength = USART_WordLength_8b;							//8位数据位
	USART_Init(USART1, &usartInitStruct);
	
	USART_Cmd(USART1, ENABLE);														//使能串口
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);									//使能接收中断
	
	nvicInitStruct.NVIC_IRQChannel = USART1_IRQn;
	nvicInitStruct.NVIC_IRQChannelCmd = ENABLE;
	nvicInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	nvicInitStruct.NVIC_IRQChannelSubPriority = 2;
	NVIC_Init(&nvicInitStruct);

}

/*
************************************************************
*	函数名称:	Usart2_Init
*
*	函数功能:	串口2初始化
*
*	入口参数:	baud:设定的波特率
*
*	返回参数:	无
*
*	说明:		TX-PA2		RX-PA3
************************************************************
*/
void Usart2_Init(unsigned int baud)
{

	GPIO_InitTypeDef gpioInitStruct;
	USART_InitTypeDef usartInitStruct;
	NVIC_InitTypeDef nvicInitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	
	//PA2	TXD
	gpioInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
	gpioInitStruct.GPIO_Pin = GPIO_Pin_2;
	gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &gpioInitStruct);
	
	//PA3	RXD
	gpioInitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	gpioInitStruct.GPIO_Pin = GPIO_Pin_3;
	gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &gpioInitStruct);
	
	usartInitStruct.USART_BaudRate = baud;
	usartInitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;		//无硬件流控
	usartInitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;						//接收和发送
	usartInitStruct.USART_Parity = USART_Parity_No;									//无校验
	usartInitStruct.USART_StopBits = USART_StopBits_1;								//1位停止位
	usartInitStruct.USART_WordLength = USART_WordLength_8b;							//8位数据位
	USART_Init(USART2, &usartInitStruct);
	
	USART_Cmd(USART2, ENABLE);														//使能串口
	
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);									//使能接收中断
	
	nvicInitStruct.NVIC_IRQChannel = USART2_IRQn;
	nvicInitStruct.NVIC_IRQChannelCmd = ENABLE;
	nvicInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	nvicInitStruct.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&nvicInitStruct);

}

/*
************************************************************
*	函数名称:	Usart_SendString
*
*	函数功能:	串口数据发送
*
*	入口参数:	USARTx:串口组
*				str:要发送的数据
*				len:数据长度
*
*	返回参数:	无
*
*	说明:		
************************************************************
*/
void Usart_SendString(USART_TypeDef *USARTx, unsigned char *str, unsigned short len)
{

	unsigned short count = 0;
	
	for(; count < len; count++)
	{
		USART_SendData(USARTx, *str++);									//发送数据
		while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);		//等待发送完成
	}

}

/*
************************************************************
*	函数名称:	UsartPrintf
*
*	函数功能:	格式化打印
*
*	入口参数:	USARTx:串口组
*				fmt:不定长参
*
*	返回参数:	无
*
*	说明:		
************************************************************
*/
void UsartPrintf(USART_TypeDef *USARTx, char *fmt,...)
{

	unsigned char UsartPrintfBuf[296];
	va_list ap;
	unsigned char *pStr = UsartPrintfBuf;
	
	va_start(ap, fmt);
	vsnprintf((char *)UsartPrintfBuf, sizeof(UsartPrintfBuf), fmt, ap);							//格式化
	va_end(ap);
	
	while(*pStr != 0)
	{
		USART_SendData(USARTx, *pStr++);
		while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
	}

}

/*
************************************************************
*	函数名称:	USART1_IRQHandler
*
*	函数功能:	串口1收发中断
*
*	入口参数:	无
*
*	返回参数:	无
*
*	说明:		
************************************************************
*/
void USART1_IRQHandler(void)
{

	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
	{
		USART_ClearFlag(USART1, USART_FLAG_RXNE);
	}

}

USART.h

#ifndef _USART_H_
#define _USART_H_


#include "stm32f10x.h"


#define USART_DEBUG		USART1		//调试打印所使用的串口组


void Usart1_Init(unsigned int baud);

void Usart2_Init(unsigned int baud);

void Usart_SendString(USART_TypeDef *USARTx, unsigned char *str, unsigned short len);

void UsartPrintf(USART_TypeDef *USARTx, char *fmt,...);

#endif

8266.c

8266

需要修改的地方有:
#define ESP8266_WIFI_INFO       "AT+CWJAP=\"WIFI名称\",\"WIFI密码\"\r\n"
​
#define ESP8266_ONENET_INFO     "AT+CIPSTART=\"TCP\",\"broker.emqx.io\",1883\r\n"
/**
	************************************************************
	************************************************************
	************************************************************
	*	文件名: 	esp8266.c
	*
	*	作者: 		张继瑞
	*
	*	日期: 		2017-05-08
	*
	*	版本: 		V1.0
	*
	*	说明: 		ESP8266的简单驱动
	*
	*	修改记录:	
	************************************************************
	************************************************************
	************************************************************
**/

//单片机头文件
#include "stm32f10x.h"

//网络设备驱动
#include "esp8266.h"

//硬件驱动
#include "Delay.h"
#include "usart.h"

//C库
#include <string.h>
#include <stdio.h>


#define ESP8266_WIFI_INFO		"AT+CWJAP=\"WIFI名称\",\"密码\"\r\n"

#define ESP8266_ONENET_INFO		"AT+CIPSTART=\"TCP\",\"broker.emqx.io\",1883\r\n"


unsigned char esp8266_buf[128];
unsigned short esp8266_cnt = 0, esp8266_cntPre = 0;


//==========================================================
//	函数名称:	ESP8266_Clear
//
//	函数功能:	清空缓存
//
//	入口参数:	无
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void ESP8266_Clear(void)
{

	memset(esp8266_buf, 0, sizeof(esp8266_buf));
	esp8266_cnt = 0;

}

//==========================================================
//	函数名称:	ESP8266_WaitRecive
//
//	函数功能:	等待接收完成
//
//	入口参数:	无
//
//	返回参数:	REV_OK-接收完成		REV_WAIT-接收超时未完成
//
//	说明:		循环调用检测是否接收完成
//==========================================================
_Bool ESP8266_WaitRecive(void)
{

	if(esp8266_cnt == 0) 							//如果接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数
		return REV_WAIT;
		
	if(esp8266_cnt == esp8266_cntPre)				//如果上一次的值和这次相同,则说明接收完毕
	{
		esp8266_cnt = 0;							//清0接收计数
			
		return REV_OK;								//返回接收完成标志
	}
		
	esp8266_cntPre = esp8266_cnt;					//置为相同
	
	return REV_WAIT;								//返回接收未完成标志

}

//==========================================================
//	函数名称:	ESP8266_SendCmd
//
//	函数功能:	发送命令
//
//	入口参数:	cmd:命令
//				res:需要检查的返回指令
//
//	返回参数:	0-成功	1-失败
//
//	说明:		
//==========================================================
_Bool ESP8266_SendCmd(char *cmd, char *res)
{
	
	unsigned char timeOut = 200;

	Usart_SendString(USART2, (unsigned char *)cmd, strlen((const char *)cmd));
	
	while(timeOut--)
	{
		if(ESP8266_WaitRecive() == REV_OK)							//如果收到数据
		{
			if(strstr((const char *)esp8266_buf, res) != NULL)		//如果检索到关键词
			{
				ESP8266_Clear();									//清空缓存
				
				return 0;
			}
		}
		
		Delay_ms(10);
	}
	
	return 1;

}

//==========================================================
//	函数名称:	ESP8266_SendData
//
//	函数功能:	发送数据
//
//	入口参数:	data:数据
//				len:长度
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void ESP8266_SendData(unsigned char *data, unsigned short len)
{

	char cmdBuf[32];
	
	ESP8266_Clear();								//清空接收缓存
	sprintf(cmdBuf, "AT+CIPSEND=%d\r\n", len);		//发送命令
	if(!ESP8266_SendCmd(cmdBuf, ">"))				//收到‘>’时可以发送数据
	{
		Usart_SendString(USART2, data, len);		//发送设备连接请求数据
	}

}

//==========================================================
//	函数名称:	ESP8266_GetIPD
//
//	函数功能:	获取平台返回的数据
//
//	入口参数:	等待的时间(乘以10ms)
//
//	返回参数:	平台返回的原始数据
//
//	说明:		不同网络设备返回的格式不同,需要去调试
//				如ESP8266的返回格式为	"+IPD,x:yyy"	x代表数据长度,yyy是数据内容
//==========================================================
unsigned char *ESP8266_GetIPD(unsigned short timeOut)
{

	char *ptrIPD = NULL;
	
	do
	{
		if(ESP8266_WaitRecive() == REV_OK)								//如果接收完成
		{
			ptrIPD = strstr((char *)esp8266_buf, "IPD,");				//搜索“IPD”头
			if(ptrIPD == NULL)											//如果没找到,可能是IPD头的延迟,还是需要等待一会,但不???超过设定的时间
			{
				//UsartPrintf(USART_DEBUG, "\"IPD\" not found\r\n");
			}
			else
			{
				ptrIPD = strchr(ptrIPD, ':');							//找到':'
				if(ptrIPD != NULL)
				{
					ptrIPD++;
					return (unsigned char *)(ptrIPD);
				}
				else
					return NULL;
				
			}
		}
		
		Delay_ms(5);
		timeOut--;		//延时等待
	} while(timeOut>0);
	
	return NULL;														//超时还未找到,返回空指针

}

//==========================================================
//	函数名称:	ESP8266_Init
//
//	函数功能:	初始化ESP8266
//
//	入口参数:	无
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void ESP8266_Init(void)
{
	
	GPIO_InitTypeDef GPIO_Initure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

	//ESP8266复位引脚
	GPIO_Initure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Initure.GPIO_Pin = GPIO_Pin_14;					//GPIOC14-复位
	GPIO_Initure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOC, &GPIO_Initure);
	
	GPIO_WriteBit(GPIOC, GPIO_Pin_14, Bit_RESET);
	Delay_ms(250);
	GPIO_WriteBit(GPIOC, GPIO_Pin_14, Bit_SET);
	Delay_ms(500);
	
	ESP8266_Clear();
	
	UsartPrintf(USART_DEBUG, "1. AT\r\n");
	while(ESP8266_SendCmd("AT\r\n", "OK"))
		Delay_ms(500);
	UsartPrintf(USART_DEBUG, "1. RST\r\n");
	ESP8266_SendCmd("AT+RST\r\n", "");
		Delay_ms(500);
	ESP8266_SendCmd("AT+CIPCLOSE\r\n", "");
		Delay_ms(500);
	
	UsartPrintf(USART_DEBUG, "2. CWMODE\r\n");
	while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))
		Delay_ms(500);
	
	UsartPrintf(USART_DEBUG, "3. AT+CWDHCP\r\n");
	while(ESP8266_SendCmd("AT+CWDHCP=1,1\r\n", "OK"))
		Delay_ms(500);
	
	UsartPrintf(USART_DEBUG, "4. CWJAP\r\n");
	while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP"))
		Delay_ms(500);
	
	UsartPrintf(USART_DEBUG, "5. CIPSTART\r\n");
	while(ESP8266_SendCmd(ESP8266_ONENET_INFO, "CONNECT"))
		Delay_ms(500);
	
	UsartPrintf(USART_DEBUG, "6. ESP8266 Init OK\r\n");

}

//==========================================================
//	函数名称:	USART2_IRQHandler
//
//	函数功能:	串口2收发中断
//
//	入口参数:	无
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void USART2_IRQHandler(void)
{

	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收中断
	{
		if(esp8266_cnt >= sizeof(esp8266_buf))	esp8266_cnt = 0; //防止串口被刷爆
		esp8266_buf[esp8266_cnt++] = USART2->DR;
		
		USART_ClearFlag(USART2, USART_FLAG_RXNE);
	}

}

 8266.h


#ifndef _ESP8266_H_
#define _ESP8266_H_





#define REV_OK		0	//接收完成标志
#define REV_WAIT	1	//接收未完成标志


void ESP8266_Init(void);

void ESP8266_Clear(void);

void ESP8266_SendData(unsigned char *data, unsigned short len);

unsigned char *ESP8266_GetIPD(unsigned short timeOut);


#endif

MQTT.c

/**
	************************************************************
	************************************************************
	************************************************************
	*	文件名: 	MqttKit.c
	*
	*	作者: 		张继瑞
	*
	*	日期: 		2018-04-27
	*
	*	版本: 		V1.6
	*
	*	说明: 		MQTT协议
	*
	*	修改记录:	V1.1:解决MQTT_PacketSubscribe订阅不为2个topic
	*						个数时协议错误的bug
	*				V1.2:修复MQTT_PacketCmdResp的bug
	*				V1.3:将strncpy替换为memcpy,解决潜在bug
	*				V1.4:修复	MQTT_PacketPublishAck
	*							MQTT_PacketPublishRel
	*							函数封包错误的bug
	*				V1.5:增加	MQTT_UnPacketCmd
	*							MQTT_UnPacketPublish
	*							接口对消息内容长度的提取参数
	*				V1.6:增加二进制文件上传接口
	************************************************************
	************************************************************
	************************************************************
**/

//协议头文件
#include "MqttKit.h"

//C库
#include <string.h>
#include <stdio.h>


#define CMD_TOPIC_PREFIX		"$creq"


//==========================================================
//	函数名称:	EDP_NewBuffer
//
//	函数功能:	申请内存
//
//	入口参数:	edpPacket:包结构体
//				size:大小
//
//	返回参数:	无
//
//	说明:		1.可使用动态分配来分配内存
//				2.可使用局部或全局数组来指定内存
//==========================================================
void MQTT_NewBuffer(MQTT_PACKET_STRUCTURE *mqttPacket, uint32 size)
{
	
	uint32 i = 0;

	if(mqttPacket->_data == NULL)
	{
		mqttPacket->_memFlag = MEM_FLAG_ALLOC;
		
		mqttPacket->_data = (uint8 *)MQTT_MallocBuffer(size);
		if(mqttPacket->_data != NULL)
		{
			mqttPacket->_len = 0;
			
			mqttPacket->_size = size;
			
			for(; i < mqttPacket->_size; i++)
				mqttPacket->_data[i] = 0;
		}
	}
	else
	{
		mqttPacket->_memFlag = MEM_FLAG_STATIC;
		
		for(; i < mqttPacket->_size; i++)
			mqttPacket->_data[i] = 0;
		
		mqttPacket->_len = 0;
		
		if(mqttPacket->_size < size)
			mqttPacket->_data = NULL;
	}

}

//==========================================================
//	函数名称:	MQTT_DeleteBuffer
//
//	函数功能:	释放数据内存
//
//	入口参数:	edpPacket:包结构体
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void MQTT_DeleteBuffer(MQTT_PACKET_STRUCTURE *mqttPacket)
{

	if(mqttPacket->_memFlag == MEM_FLAG_ALLOC)
		MQTT_FreeBuffer(mqttPacket->_data);
	
	mqttPacket->_data = NULL;
	mqttPacket->_len = 0;
	mqttPacket->_size = 0;
	mqttPacket->_memFlag = MEM_FLAG_NULL;

}

int32 MQTT_DumpLength(size_t len, uint8 *buf)
{
	
	int32 i = 0;
	
	for(i = 1; i <= 4; ++i)
	{
		*buf = len % 128;
		len >>= 7;
		if(len > 0)
		{
			*buf |= 128;
			++buf;
		}
		else
		{
			return i;
		}
	}

	return -1;
}

int32 MQTT_ReadLength(const uint8 *stream, int32 size, uint32 *len)
{
	
	int32 i;
	const uint8 *in = stream;
	uint32 multiplier = 1;

	*len = 0;
	for(i = 0; i < size; ++i)
	{
		*len += (in[i] & 0x7f) * multiplier;

		if(!(in[i] & 0x80))
		{
			return i + 1;
		}

		multiplier <<= 7;
		if(multiplier >= 2097152)		//128 * *128 * *128
		{
			return -2;					// error, out of range
		}
	}

	return -1;							// not complete

}

//==========================================================
//	函数名称:	MQTT_UnPacketRecv
//
//	函数功能:	MQTT数据接收类型判断
//
//	入口参数:	dataPtr:接收的数据指针
//
//	返回参数:	0-成功		其他-失败原因
//
//	说明:		
//==========================================================
uint8 MQTT_UnPacketRecv(uint8 *dataPtr)
{
	
	uint8 status = 255;
	uint8 type = dataPtr[0] >> 4;				//类型检查
	
	if(type < 1 || type > 14)
		return status;
	
	if(type == MQTT_PKT_PUBLISH)
	{
		uint8 *msgPtr;
		uint32 remain_len = 0;
		
		msgPtr = dataPtr + MQTT_ReadLength(dataPtr + 1, 4, &remain_len) + 1;
		
		if(remain_len < 2 || dataPtr[0] & 0x01)					//retain
			return 255;
		
		if(remain_len < ((uint16)msgPtr[0] << 8 | msgPtr[1]) + 2)
			return 255;
		
		if(strstr((int8 *)msgPtr + 2, CMD_TOPIC_PREFIX) != NULL)	//如果是命令下发
			status = MQTT_PKT_CMD;
		else
			status = MQTT_PKT_PUBLISH;
	}
	else
		status = type;
	
	return status;

}

//==========================================================
//	函数名称:	MQTT_PacketConnect
//
//	函数功能:	连接消息组包
//
//	入口参数:	user:用户名:产品ID
//				password:密码:鉴权信息或apikey
//				devid:设备ID
//				cTime:连接保持时间
//				clean_session:离线消息清除标志
//				qos:重发标志
//				will_topic:异常离线topic
//				will_msg:异常离线消息
//				will_retain:消息推送标志
//				mqttPacket:包指针
//
//	返回参数:	0-成功		其他-失败
//
//	说明:		
//==========================================================
uint8 MQTT_PacketConnect(const int8 *user, const int8 *password, const int8 *devid,
						uint16 cTime, uint1 clean_session, uint1 qos,
						const int8 *will_topic, const int8 *will_msg, int32 will_retain,
						MQTT_PACKET_STRUCTURE *mqttPacket)
{
	
	uint8 flags = 0;
	uint8 will_topic_len = 0;
	uint16 total_len = 15;
	int16 len = 0, devid_len = strlen(devid);
	
	if(!devid)
		return 1;
	
	total_len += devid_len + 2;
	
	//断线后,是否清理离线消息:1-清理	0-不清理--------------------------------------------
	if(clean_session)
	{
		flags |= MQTT_CONNECT_CLEAN_SESSION;
	}
	
	//异常掉线情况下,服务器发布的topic------------------------------------------------------
	if(will_topic)
	{
		flags |= MQTT_CONNECT_WILL_FLAG;
		will_topic_len = strlen(will_topic);
		total_len += 4 + will_topic_len + strlen(will_msg);
	}
	
	//qos级别--主要用于PUBLISH(发布态)消息的,保证消息传递的次数-----------------------------
	switch((unsigned char)qos)
	{
		case MQTT_QOS_LEVEL0:
			flags |= MQTT_CONNECT_WILL_QOS0;							//最多一次
		break;
		
		case MQTT_QOS_LEVEL1:
			flags |= (MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_QOS1);	//最少一次
		break;
		
		case MQTT_QOS_LEVEL2:
			flags |= (MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_QOS2);	//只有一次
		break;
		
		default:
		return 2;
	}
	
	//主要用于PUBLISH(发布态)的消息,表示服务器要保留这次推送的信息,如果有新的订阅者出现,就把这消息推送给它。如果不设那么推送至当前订阅的就释放了
	if(will_retain)
	{
		flags |= (MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_RETAIN);
	}
	
	//账号为空 密码为空---------------------------------------------------------------------
	if(!user || !password)
	{
		return 3;
	}
	flags |= MQTT_CONNECT_USER_NAME | MQTT_CONNECT_PASSORD;
	
	total_len += strlen(user) + strlen(password) + 4;
	
	//分配内存-----------------------------------------------------------------------------
	MQTT_NewBuffer(mqttPacket, total_len);
	if(mqttPacket->_data == NULL)
		return 4;
	
	memset(mqttPacket->_data, 0, total_len);
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------连接请求类型---------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_CONNECT << 4;
	
	//固定头部----------------------剩余长度值-----------------------------------------------
	len = MQTT_DumpLength(total_len - 5, mqttPacket->_data + mqttPacket->_len);
	if(len < 0)
	{
		MQTT_DeleteBuffer(mqttPacket);
		return 5;
	}
	else
		mqttPacket->_len += len;
	
/*************************************可变头部***********************************************/
	
	//可变头部----------------------协议名长度 和 协议名--------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 0;
	mqttPacket->_data[mqttPacket->_len++] = 4;
	mqttPacket->_data[mqttPacket->_len++] = 'M';
	mqttPacket->_data[mqttPacket->_len++] = 'Q';
	mqttPacket->_data[mqttPacket->_len++] = 'T';
	mqttPacket->_data[mqttPacket->_len++] = 'T';
	
	//可变头部----------------------protocol level 4-----------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 4;
	
	//可变头部----------------------连接标志(该函数开头处理的数据)-----------------------------
    mqttPacket->_data[mqttPacket->_len++] = flags;
	
	//可变头部----------------------保持连接的时间(秒)----------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(cTime);
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(cTime);
	 
/*************************************消息体************************************************/

	//消息体----------------------------devid长度、devid-------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(devid_len);
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(devid_len);
	
	strncat((int8 *)mqttPacket->_data + mqttPacket->_len, devid, devid_len);
	mqttPacket->_len += devid_len;
	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值