Controlador simple del módulo ESP8266: realice la función de nube basada en el firmware STM32F103 y Atomic Cloud


1. Descripción

Este sencillo programa de controlador se basa en el módulo ESP8266 de átomo puntual , que se utiliza principalmente para realizar la función de conectar la nube atómica . La MCU es STM32F103ZET6


Nota: AT+ATKCLDSTA y AT+ATKCLDCLS se agregan al firmware de Atomic Cloud para
conectarse a la plataforma Atomic Cloud de Zhengdian Atom. El comando AT original no se verá afectado de ninguna manera.

Este programa realiza principalmente las siguientes funciones:

  1. Establecer el modo de trabajo
  2. conectar el enrutador
  3. Conectarse al servidor TCP
  4. Conéctese a Atomic Cloud (módulo ESP8266 con firmware de Atomic Cloud flasheado)
  5. Enviar datos (incluido el envío normal, la transmisión transparente, el envío en la nube)

2. Dependencia de archivos

2.1 Las dependencias del archivo de encabezado de esp8266.c son las siguientes (modifique usted mismo las rutas relevantes)

#include "../../Basic/sys/sys.h"
#include "../../Basic/usart/usart.h"
#include "../../Basic/delay/delay.h"
#include <string.h>

2.2 Los archivos de encabezado de usart.c dependen de lo siguiente (modifique usted mismo las rutas relevantes)

#include "stdio.h"
#include "stdarg.h"
#include <string.h>
#include "../../Basic/sys/sys.h"
#include "../../Hardware/ESP8266/esp8266_timer.h"

2.3 Las dependencias del archivo de encabezado de esp8266_timer.c son las siguientes (modifique usted mismo las rutas relevantes)

#include "../../Basic/sys/sys.h"
#include "../../Basic/usart/usart.h"

3. Documentos relacionados con USART

3.1 Archivo usart.h

#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "stdarg.h"
#include <string.h>
#include "../../Basic/sys/sys.h"
#include "../../Hardware/ESP8266/esp8266_timer.h"

#define printfByUSARTx  USART1 //定义支持printf函数的串口

#define USART1_REC_LEN	200  	//定义最大接收字节数 200
#define	USART3_REC_LEN	600		//定义最大接收字节数 600
#define USART3_SEN_LEN	600		//定义最大发送字节数 600

#define EN_USART1	1		//1使能,0禁止  串口1接收
#define EN_USART2	0
#define EN_USART3	1

#if EN_USART1
extern u8  USART1_RX_BUF[USART1_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART1_RX_STA;         		 //接收状态标记	
#endif // EN_USART1

#if EN_USART2
extern u8  USART2_RX_BUF[USART2_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART2_RX_STA;         		 //接收状态标记	
#endif // EN_USART2

#if EN_USART3
extern u8  USART3_RX_BUF[USART3_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u8  USART3_TX_BUF[USART3_SEN_LEN]; //发送缓冲
extern u16 USART3_RX_STA;         		 //接收状态标记	
#endif // EN_USART3

#if EN_USART1
void USART1_Init(u32 baudRate);
#endif // EN_USART1

#if EN_USART2
void USART2_Init(u32 baudRate);
#endif // EN_USART2

#if EN_USART3
/**
 * @brief	串口3初始化
*/
void USART3_Init(u32 baudRate);

/**
 * @brief	串口3 printf
*/
void USART3_printf(char* fmt, ...);

/**
 * @brief	USART3_RX_BUF串口3数据缓冲清空
*/
void USART3_RX_BUF_CLEAR(void);
#endif // EN_USART3

#endif


3.2 Archivo usart.c

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

//
//加入以下代码,支持printf函数,而不需要选择use MicroLIB	  
#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 ((printfByUSARTx->SR & 0X40) == 0);//循环发送,直到发送完毕   
	printfByUSARTx->DR = (u8)ch;
	return ch;
}
#endif 

/*使用microLib的方法*/
 /* 
int fputc(int ch, FILE *f)
{
	USART_SendData(USART1, (uint8_t) ch);

	while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {}	
   
    return ch;
}
int GetKey (void)  { 

    while (!(USART1->SR & USART_FLAG_RXNE));

    return ((int)(USART1->DR & 0x1FF));
}
*/

#if EN_USART1   //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   	
u8 USART1_RX_BUF[USART1_REC_LEN];     //接收缓冲,最大USART1_REC_LEN个字节.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
u16 USART1_RX_STA = 0;       //接收状态标记	  

/**
 * @brief 串口1初始化
*/
void USART1_Init(u32 baudRate) {
    
    
	//GPIO端口设置
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

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

	USART_DeInit(USART1); //复位USART1

	//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 = baudRate;//串口波特率
	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 
}

/**
 * @brief	串口1中断服务程序
*/
void USART1_IRQHandler(void) {
    
    
	u8 Res;

#if SYSTEM_SUPPORT_OS 		//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntEnter();
#endif

	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) {
    
     //接收中断(接收到的数据必须是0x0d 0x0a结尾)
		Res = USART_ReceiveData(USART1);	//读取接收到的数据
		//注意在主函数处理完串口数据后,要将USART1_RX_STA清0
		if ((USART1_RX_STA & 0x8000) == 0) {
    
    //最高位为0,还未接受完成
			if (USART1_RX_STA & 0x4000) {
    
    //接收到了0x0d
				if (Res != 0x0a) USART1_RX_STA = 0;//接收错误,重新开始
				else USART1_RX_STA |= 0x8000;	//如果最后一位是0a,则标记为接受完成
			}
			else {
    
     //还没收到0d
				if (Res == 0x0d) USART1_RX_STA |= 0x4000;
				else {
    
    
					USART1_RX_BUF[USART1_RX_STA & 0X3FFF] = Res;
					USART1_RX_STA++;
					if (USART1_RX_STA > (USART1_REC_LEN - 1)) USART1_RX_STA = 0;//接收数据错误,重新开始接收	  
				}
			}
		}
	}

#if SYSTEM_SUPPORT_OS 	//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntExit();
#endif
}
#endif	

#if EN_USART3
u8  USART3_RX_BUF[USART3_REC_LEN];  //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
u8  USART3_TX_BUF[USART3_SEN_LEN];  //发送缓冲
u16 USART3_RX_STA = 0;				//接收状态标记	

/**
 * @brief	串口3初始化
*/
void USART3_Init(u32 baudRate) {
    
    
	//GPIO端口设置
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);	//使能USART3,GPIOB时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

	USART_DeInit(USART3); //复位USART3

	//USART3_TX   GPIOB.10
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	//USART3_RX	  GPIOB.11
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;//PB11
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	//Usart3 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	

	//USART 初始化设置
	USART_InitStructure.USART_BaudRate = baudRate;//串口波特率
	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(USART3, &USART_InitStructure); //初始化串口
	USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启串口接受中断
	USART_Cmd(USART3, ENABLE);                    //使能串口

	TIM7_Int_Init(1000 - 1, 7200 - 1);	//TIM7初始化,每10ms触发中断
	TIM_Cmd(TIM7, DISABLE);	//关闭定时器7
}

/**
 * @brief	串口3中断服务程序
*/
void USART3_IRQHandler(void) {
    
    
	u8 res;
	if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) {
    
     //串口3产生中断
		res = USART_ReceiveData(USART3); //暂存数据
		if ((USART3_RX_STA & 0x8000) == 0) {
    
     //最高位接收完成标志还为0时
			if (USART3_RX_STA < USART3_REC_LEN) {
    
     //如果USART3接收缓存仍有余量
				TIM_SetCounter(TIM7, 0); //清空TIM7计数值
				if (USART3_RX_STA == 0)	 TIM_Cmd(TIM7, ENABLE);	//使能TIM7
				USART3_RX_BUF[USART3_RX_STA++] = res; //存储数据
			}
			else {
    
     //否则当达到最大接受缓冲时强制结束存储
				USART3_RX_STA |= 0x8000; //强制标记接收完成,最高位赋值为1
			}
		}
	}
}

/**
 * @brief	串口3 printf
*/
void USART3_printf(char* fmt, ...) {
    
    
	u16 i, j;
	va_list ap;
	va_start(ap, fmt);
	vsprintf((char*)USART3_TX_BUF, fmt, ap);
	va_end(ap);
	i = strlen((const char*)USART3_TX_BUF);//此次发送数据的长度
	for (j = 0; j < i; j++) {
    
     //循环发送
		while (USART_GetFlagStatus(USART3, USART_FLAG_TC) != SET);  //等待上次传输完成 
		USART_SendData(USART3, (uint8_t)USART3_TX_BUF[j]); 	 //发送数据到串口3 
	}
}

/**
 * @brief	USART3_RX_BUF串口3数据缓冲清空
*/
void USART3_RX_BUF_CLEAR(void) {
    
    
	memset(USART3_RX_BUF, 0, USART3_REC_LEN);
	USART3_RX_STA = 0;
}
#endif


4. Documentos relacionados con ESP8266

  1. esp8266_timer.c (el archivo del temporizador usa TIM7 para medir el tiempo durante la transmisión usart3)
  2. esp8266_temporizador.h
  3. esp8266.c
  4. esp8266.h

4.1 archivos relacionados con esp8266_timer

4.1.1 archivo esp8266_timer.h

#ifndef __ESP8266_TIMER_H
#define __ESP8266_TIMER_H
#include "../../Basic/sys/sys.h"
#include "../../Basic/usart/usart.h"

/**
 * @brief	定时器7初始化
 * @param	arr,计数器值
 * @param	psc,预分频值
 */
void TIM7_Int_Init(u16 arr, u16 psc);

#endif // !__ESP8266_TIMER_H


4.1.2 archivo esp8266_timer.c

#include "esp8266_timer.h"

extern u16 USART3_RX_STA;

/**
 * @brief	定时器7中断服务程序
 */
void TIM7_IRQHandler(void) {
    
    
	if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET) {
    
     //TIM7触发中断
		USART3_RX_STA |= 0x8000;	//超时,强制标记串口3数据接收完成
		TIM_ClearITPendingBit(TIM7, TIM_IT_Update);  //清除TIM7更新中断标志    
		TIM_Cmd(TIM7, DISABLE);  //关闭TIM7
	}
}

/**
 * @brief	定时器7初始化
 * @param	arr,计数器值
 * @param	psc,预分频值
 */
void TIM7_Int_Init(u16 arr, u16 psc) {
    
    
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);//TIM7时钟使能    

	//定时器TIM7初始化
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler = psc; //设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位

	TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE); //使能指定的TIM7中断,允许更新中断

	TIM_Cmd(TIM7, ENABLE);//开启定时器7

	NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;		//子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
}


4.2 documentos relacionados con esp8266

Nota: definí el tipo de enumeración operatorSta en sys.h para marcar si la operación es exitosa. Puede agregarlo usted mismo en el archivo esp8266.h

typedef enum {
    
    
	FAIL = 0,
	SUCCEED
} operateSta; //操作状态

4.2.1 archivo esp8266.h

#ifndef __ESP8266_H
#define __ESP8266_H
// <头文件> //
#include "../../Basic/sys/sys.h"
#include "../../Basic/usart/usart.h"
#include "../../Basic/delay/delay.h"
#include <string.h>
// <头文件> //

#define	FIRMWARE_YUANZI_SUPPORT	1	//是否为刷了原子云固件的ESP8266

/
//							-- 枚举类型定义 --				   		   //
/

//ESP8266 工作模式
typedef enum {
    
    
	STA_MODE = 1, /* STA模式 */
	AP_MODE,	  /* AP模式 */
	AP_STA_MODE	  /* AP+STA模式 */
}ESP8266_WORK_MODE;

//ESP8266 加密方式
typedef enum {
    
    
	OPEN = 0,
	WPA_PSK = 2,
	WPA2_PSK,
	WPA_WPA2_PSK
}ESP8266_ENCRYPTION_TYPE;

//AP模式下最大可连接客户端数量
typedef enum {
    
    
	MAX_CLIENT_NUMBER_1 = 1, /* 设置最大可连接的客户端数量为1 */
	MAX_CLIENT_NUMBER_2,	 /* 设置最大可连接的客户端数量为2 */
	MAX_CLIENT_NUMBER_3,	 /* 设置最大可连接的客户端数量为3 */
	MAX_CLIENT_NUMBER_4		 /* 设置最大可连接的客户端数量为4 */
}MAX_CLIENT_NUMBER;

/
//							-- 相关结构体定义 --				   		   //
/

//STA相关参数
typedef struct {
    
    
	const u8* STA_SSID;		//要连接的 WIFI SSID
	const u8* STA_PWD;		//要连接的 WIFI 密码
	u8 WIFI_CONNECTED;		//WIFI连接标志位
}STA_Parameter_Type;
extern STA_Parameter_Type STA_Parameters;

//AP相关参数
typedef struct {
    
    
	const u8* AP_SSID;		//软路由 AP SSID
	const u8* AP_PWD; 		//软路由 AP 密码(至少8位)
	u8 AP_CHANNEL;			//通道号
	ESP8266_ENCRYPTION_TYPE AP_ENCRYPTION; //加密方式
	MAX_CLIENT_NUMBER MAX_CLIENT; //最大客户端数量
	u8 BROADCAST;			//是否广播AP的SSID
}AP_Parameter_Type;
extern AP_Parameter_Type AP_Parameters;

//需连接的TCP服务器相关参数
typedef struct {
    
    
	const u8* serverIP;		//TCP服务器IP
	const u8* serverPort;	//TCP服务器连接端口
	u8 TCP_SERVER_CONNECTED;//TCP服务器连接标志位
	u8 TRANSPARENT_MODE;	//透传模式标志位
}TCP_Server_Parameter_Type;
extern TCP_Server_Parameter_Type TCP_Server_Parameters;

#if FIRMWARE_YUANZI_SUPPORT	//如果为刷了原子云固件的ESP8266
//原子云设备ID及密码
typedef struct {
    
    
	const u8* cloudID;		//原子云设备ID
	const u8* cloadPwd;		//原子云设备密码
	u8 CLOUD_CONNECTED;		//原子云连接标志位
}Cloud_Parameter_Type;
extern Cloud_Parameter_Type Cloud_Parameters;
#endif // FIRMWARE_YUANZI_SUPPORT


//							-- 硬件相关定义 --				   		  //
//				USART3_TX引脚为PB10,USART3_RX引脚为PB11				  //


#define ESP8266_RST_PIN			GPIO_Pin_14				//ESP8266模块RST引脚
#define ESP8266_RST_PORT		GPIOE					//ESP8266模块RST端口
#define ESP8266_RST_OUT			PEout(14)				//ESP8266模块RST输出
#define	ESP8266_RST_PORT_CLOCK	RCC_APB2Periph_GPIOE	//ESP8266模块RST引脚端口时钟


//							-- 相关操作函数 --				   		  //


/**
 * @brief	检查收到的应答
 * @param	res	预期应答字符串
 * @retval	res首次出现的位置指针,如果为0则说明响应无该字符串
*/
u8* ESP8266_Check_Response(u8* res);

/**
 * @brief	发送命令给ESP8266
 * @param	cmd	命令
 * @param	ack 期待的应答结果,如果为空则不等待应答
 * @param	waitTime	等待时间(单位ms)
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_SendCmd(u8* cmd, u8* ack, u16 waitTime);

/**
 * @brief	ESP8266发送数据内容。
 *			如果连接了原子云,消息收发会被云占用,无法和TCP服务器收发
 * @param	data	数据
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_SendData(u8* data);

/**
 * @brief	ESP8266进入透传模式
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Enter_TransparentTransmit(void);

/**
 * @brief	ESP8266通过透传发送数据内容。
 *			如果连接了原子云,消息收发会被云占用,无法和TCP服务器收发
 * @note	进入透传模式后,直接发送数据即可,无需先发送AT+CIPSEND=%d说明要发送的长度
 * @param	data	数据
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_TransparentSendData(u8* data);

/**
 * @brief	ESP8266退出透传模式
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Exit_TransparentTransmit(void);

#if FIRMWARE_YUANZI_SUPPORT	//如果为刷了原子云固件的ESP8266
/**
 * @brief	ESP8266连接原子云
 * @note	只有刷了原子云固件的才可以使用
 * @param	parameters, 原子云相关参数结构体指针
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Connect_YuanZiCloud(Cloud_Parameter_Type* parameters);

/**
 * @brief	ESP8266发送数据内容给原子云。
 *			如果连接了原子云,消息收发会被云占用,无法和TCP服务器收发
 * @note	只有刷了原子云固件的才可以使用
 * @param	data	数据
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta  ESP8266_CloudSendData(u8* data);

/**
 * @brief	ESP8266断开与原子云的连接
 * @note	只有刷了原子云固件的才可以使用
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Disconnect_YuanZiCloud(void);
#endif // FIRMWARE_YUANZI_SUPPORT

/**
 * @brief	AT指令测试
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_ATCmd_Test(void);

/**
 * @brief	查询AT固件版本信息
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Check_FirmWare_Info(void);

/**
 * @brief	设置ESP8266工作模式
 * @param	mode 工作模式.
			@arg	取值为: STA_MODE, AP_MODE, AP_STA_MODE
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_WorkMode_Conf(ESP8266_WORK_MODE mode);

/**
 * @brief	设置ESP8266软路由相关参数
 * @param	parameters, AP模式相关参数结构体指针
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_SoftAP_Conf(AP_Parameter_Type* parameters);

/**
 * @brief	ESP8266设置AP参数后,查询与ESP8266建立连接的客户端信息
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Check_Connected_ClientInfo(void);

/**
 * @brief	ESP8266连接WIFI
 * @param	parameters, STA模式下的WIFI相关参数结构体指针
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Connect_WIFI(STA_Parameter_Type* parameters);

/**
 * @brief	ESP8266连接TCP服务器
 * @param	parameters, TCP服务器相关参数结构体指针
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Connect_TCP_Server(TCP_Server_Parameter_Type* parameters);

/**
 * @brief	断开与TCP服务器的连接
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Disconnect_TCP_Server(void);

/**
 * @brief	获取ip地址
 * @param	ipbuf	ip地址字符串缓冲区
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_GetIP(u8* ipbuf);


//							-- 初始化相关函数 --				   		  //


/**
 * @brief	ESP8266恢复出厂设置
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Restore_Default(void);

/**
 * @brief	ESP8266软件复位
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_SW_Reset(void);

/**
 * @brief	ESP8266初始化
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Init(void);

#endif // !__ESP8266_H


4.2.2 archivo esp8266.c

#include "esp8266.h"

// <全局变量声明> //
STA_Parameter_Type STA_Parameters;				//STA模式参数
AP_Parameter_Type AP_Parameters;				//AP模式参数
TCP_Server_Parameter_Type TCP_Server_Parameters;//TCP Server参数
#if FIRMWARE_YUANZI_SUPPORT	//如果为刷了原子云固件的ESP8266
Cloud_Parameter_Type Cloud_Parameters;			//原子云设备参数
#endif // FIRMWARE_YUANZI_SUPPORT
// <全局变量声明> //

/
//						-- 结构体参数初始化 --				   		   //
/

//STA参数初始化
void STA_Info_Init(STA_Parameter_Type* parameters) {
    
    
	parameters->STA_SSID = "***"; //自行修改WIFI名称
	parameters->STA_PWD = "********"; //自行修改WIFI密码
	parameters->WIFI_CONNECTED = 0;
}

//AP参数初始化
void AP_Info_Init(AP_Parameter_Type* parameters) {
    
    
	parameters->AP_SSID = "ESP_8266"; //自行修改软路由名称
	parameters->AP_PWD = "123456789"; //自行修改软路由密码
	parameters->AP_CHANNEL = 5;
	parameters->AP_ENCRYPTION = WPA_WPA2_PSK;
	parameters->MAX_CLIENT = MAX_CLIENT_NUMBER_1;
	parameters->BROADCAST = 0;
}

//TCP_Server参数初始化
void TCP_Server_Info_Init(TCP_Server_Parameter_Type* parameters) {
    
    
	parameters->serverIP = "192.168.0.10"; //自行修改TCP服务器ip
	parameters->serverPort = "9090";	   //自行修改TCP服务器端口
	parameters->TCP_SERVER_CONNECTED = 0;
	parameters->TRANSPARENT_MODE = 0;
}

#if FIRMWARE_YUANZI_SUPPORT	//如果为刷了原子云固件的ESP8266
//Cloud参数初始化
void Cloud_Info_Init(Cloud_Parameter_Type* parameters) {
    
    
	parameters->cloudID = "60002472859501******"; //自行修改原子云设备编号
	parameters->cloadPwd = "12345678";			  //自行修改原子云设备密码
	parameters->CLOUD_CONNECTED = 0;
}
#endif // FIRMWARE_YUANZI_SUPPORT


/
//							-- 相关操作函数 --				   		   //
/

/**
 * @brief	检查收到的应答
 * @param	res	预期应答字符串
 * @retval	res首次出现的位置指针,如果为0则说明响应无该字符串
*/
u8* ESP8266_Check_Response(u8* res) {
    
    
	char* index = 0;
	//接收到数据
	if (USART3_RX_STA & 0x8000) {
    
    
		USART3_RX_BUF[USART3_RX_STA & 0x3FFF] = '\0'; //添加结束符
		index = strstr((const char*)USART3_RX_BUF, (const char*)res);
	}
	return (u8*)index;
}

/**
 * @brief	发送命令给ESP8266
 * @param	cmd	命令
 * @param	ack 期待的应答结果,如果为空则不等待应答
 * @param	waitTime	等待时间(单位ms)
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_SendCmd(u8* cmd, u8* ack, u16 waitTime) {
    
    
	USART3_RX_STA = 0;			  //初始化串口3接收标记
	USART3_printf("%s\r\n", cmd); //发送命令
	if (ack && waitTime) {
    
    
		while (waitTime--) {
    
    
			if (USART3_RX_STA & 0x8000) {
    
    
				if (ESP8266_Check_Response(ack) != 0) return SUCCEED;
				USART3_RX_STA = 0;
			}
			delay_ms(1);
		}
	}
	if (ack == NULL) return SUCCEED;
	return FAIL;
}

/**
 * @brief	ESP8266发送数据内容。
 *			如果连接了原子云,消息收发会被云占用,无法和TCP服务器收发
 * @param	data	数据
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_SendData(u8* data) {
    
    
	u8 state;
	u8 cmd[12];
	u16 len = strlen((const char*)data) + 2; //要发送的数据长度+2个结束字符0d0a
	//如果TCP服务器未连接成功则直接返回FAIL
	if (!(&TCP_Server_Parameters)->TCP_SERVER_CONNECTED) return FAIL;
#if FIRMWARE_YUANZI_SUPPORT	//如果为刷了原子云固件的ESP8266
	if ((&Cloud_Parameters)->CLOUD_CONNECTED) return FAIL;
#endif // FIRMWARE_YUANZI_SUPPORT
	sprintf((char*)cmd, "AT+CIPSEND=%d", len);
	state = ESP8266_SendCmd(cmd, ">", 500);
	if (state == FAIL)	return FAIL;
	state = ESP8266_SendCmd(data, "SEND OK", 1000);
	if (state == SUCCEED)	return SUCCEED;
	return FAIL;
}

/**
 * @brief	ESP8266进入透传模式
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Enter_TransparentTransmit(void) {
    
    
	u8 state;
	state = ESP8266_SendCmd("AT+CIPMODE=1", "OK", 500);
	if (state == FAIL) return FAIL;
	state = ESP8266_SendCmd("AT+CIPSEND", ">", 500);
	if (state == SUCCEED) return SUCCEED;
	return FAIL;
}

/**
 * @brief	ESP8266通过透传发送数据内容。
 *			如果连接了原子云,消息收发会被云占用,无法和TCP服务器收发
 * @note	进入透传模式后,直接发送数据即可,无需先发送AT+CIPSEND=%d说明要发送的长度
 * @param	data	数据
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_TransparentSendData(u8* data) {
    
    
	u8 state;
	//如果TCP服务器未连接成功则直接返回FAIL
	if (!(&TCP_Server_Parameters)->TCP_SERVER_CONNECTED) return FAIL;
#if FIRMWARE_YUANZI_SUPPORT	//如果为刷了原子云固件的ESP8266
	if ((&Cloud_Parameters)->CLOUD_CONNECTED) return FAIL;
#endif // FIRMWARE_YUANZI_SUPPORT
	if (!(&TCP_Server_Parameters)->TRANSPARENT_MODE) {
    
    
		state = ESP8266_Enter_TransparentTransmit();
		if (state != SUCCEED) return FAIL;
		(&TCP_Server_Parameters)->TRANSPARENT_MODE = 1;
	}
	state = ESP8266_SendCmd(data, NULL, 500);
	if (state == SUCCEED) return SUCCEED;
	return FAIL;
}

/**
 * @brief	ESP8266退出透传模式
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Exit_TransparentTransmit(void) {
    
    
	u8 state;
	if (!(&TCP_Server_Parameters)->TRANSPARENT_MODE) return SUCCEED;
	USART3_printf("+++");
	delay_ms(1500);
	state = ESP8266_SendCmd("AT+CIPMODE=0", "OK", 500);
	if (state == SUCCEED) {
    
    
		(&TCP_Server_Parameters)->TRANSPARENT_MODE = 0;
		return SUCCEED;
	}
	return FAIL;
}

#if FIRMWARE_YUANZI_SUPPORT	//如果为刷了原子云固件的ESP8266
/**
 * @brief	ESP8266连接原子云
 * @note	只有刷了原子云固件的才可以使用
 * @param	parameters, 原子云相关参数结构体指针
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Connect_YuanZiCloud(Cloud_Parameter_Type* parameters) {
    
    
	u8 state;
	u8 cmd[50];

	sprintf((char*)cmd, "AT+ATKCLDSTA=\"%s\",\"%s\"",
		parameters->cloudID,
		parameters->cloadPwd);
	state = ESP8266_SendCmd(cmd, "CLOUD CONNECTED", 10000);
	if (state == SUCCEED) {
    
    
		parameters->CLOUD_CONNECTED = 1;
		return SUCCEED;
	}
	return FAIL;
}

/**
 * @brief	ESP8266发送数据内容给原子云。
 *			如果连接了原子云,消息收发会被云占用,无法和TCP服务器收发
 * @note	只有刷了原子云固件的才可以使用
 * @param	data	数据
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta  ESP8266_CloudSendData(u8* data) {
    
    
	u8 state;

	if (!(&Cloud_Parameters)->CLOUD_CONNECTED) return FAIL;
	state = ESP8266_SendCmd(data, NULL, 500);
	if (state == SUCCEED) return SUCCEED;
	return FAIL;
}

/**
 * @brief	ESP8266断开与原子云的连接
 * @note	只有刷了原子云固件的才可以使用
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Disconnect_YuanZiCloud(void) {
    
    
	u8 state;
	state = ESP8266_SendCmd("AT+ATKCLDCLS", "CLOUD DISCONNECT", 500);
	if (state == SUCCEED) {
    
    
		(&Cloud_Parameters)->CLOUD_CONNECTED = 0;
		return SUCCEED;
	}
	return FAIL;
}
#endif // FIRMWARE_YUANZI_SUPPORT

/**
 * @brief	AT指令测试
 * @note	单独发送"AT"给ESP8266,会返回"OK"
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_ATCmd_Test(void) {
    
    
	u8 i;
	u8 state;
	for (i = 0; i < 10; i++) {
    
    
		state = ESP8266_SendCmd("AT", "OK", 500);
		if (state == SUCCEED) return SUCCEED;
	}
	return FAIL;
}

/**
 * @brief	查询AT固件版本信息
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Check_FirmWare_Info(void) {
    
    
	u8 state;
	state = ESP8266_SendCmd("AT+GMR", "OK", 500);
	if (state == SUCCEED) return SUCCEED;
	return FAIL;
}

/**
 * @brief	设置ESP8266工作模式
 * @param	mode 工作模式
			@arg	STA_MODE, AP_MODE, AP_STA_MODE
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_WorkMode_Conf(ESP8266_WORK_MODE mode) {
    
    
	u8 state;
	switch (mode) {
    
    
		case STA_MODE: {
    
    
			state = ESP8266_SendCmd("AT+CWMODE_DEF=1", "OK", 500); break;
		}
		case AP_MODE: {
    
    
			state = ESP8266_SendCmd("AT+CWMODE_DEF=2", "OK", 500); break;
		}
		case AP_STA_MODE: {
    
    
			state = ESP8266_SendCmd("AT+CWMODE_DEF=3", "OK", 500); break;
		}
		default: return FAIL;
	}
	if (state == SUCCEED) return SUCCEED;
	return FAIL;
}

/**
 * @brief	设置ESP8266软路由相关参数
 * @param	parameters, AP模式相关参数结构体指针
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_SoftAP_Conf(AP_Parameter_Type* parameters) {
    
    
	u8 state;
	u8 cmd[50];

	sprintf((char*)cmd, "AT+CWSAP_DEF=\"%s\",\"%s\",%d,%d,%d,%d", 
		parameters->AP_SSID, 
		parameters->AP_PWD,
		parameters->AP_CHANNEL,
		parameters->AP_ENCRYPTION,
		parameters->MAX_CLIENT,
		parameters->BROADCAST);
	state = ESP8266_SendCmd(cmd, "OK", 5000);
	if (state == SUCCEED) return SUCCEED;
	return FAIL;
}

/**
 * @brief	ESP8266设置AP参数后,查询与ESP8266建立连接的客户端信息
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Check_Connected_ClientInfo(void) {
    
    
	u8 state;
	state = ESP8266_SendCmd("AT+CWLIF", "192.", 5000);
	if (state == SUCCEED) return SUCCEED;
	return FAIL;
}

/**
 * @brief	ESP8266连接WIFI
 * @param	parameters, STA模式下的WIFI相关参数结构体指针
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Connect_WIFI(STA_Parameter_Type* parameters) {
    
    
	u8 state;
	u8 cmd[50];

	sprintf((char*)cmd, "AT+CWJAP_DEF=\"%s\",\"%s\"", 
		parameters->STA_SSID, 
		parameters->STA_PWD);
	state = ESP8266_SendCmd(cmd, "WIFI GOT IP", 10000);
	if (state == SUCCEED) {
    
    
		parameters->WIFI_CONNECTED = 1;
		return SUCCEED;
	}
	return FAIL;
}

/**
 * @brief	ESP8266连接TCP服务器
 * @param	parameters, TCP服务器相关参数结构体指针
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Connect_TCP_Server(TCP_Server_Parameter_Type* parameters) {
    
    
	u8 state;
	u8 cmd[50];

	state = ESP8266_SendCmd("AT+CIPMUX=0", "OK", 500);
	if (state != SUCCEED) return FAIL;
	sprintf((char*)cmd, "AT+CIPSTART=\"TCP\",\"%s\",%s", 
		parameters->serverIP,
		parameters->serverPort);
	state = ESP8266_SendCmd(cmd, "CONNECT", 5000);
	if (state == SUCCEED) {
    
    
		parameters->TCP_SERVER_CONNECTED = 1;
		return SUCCEED;
	}
	return FAIL;
}

/**
 * @brief	断开与TCP服务器的连接
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Disconnect_TCP_Server(void) {
    
    
	u8 state;
	state = ESP8266_SendCmd("AT+CIPCLOSE", "CLOSED", 500);
	if (state == SUCCEED) {
    
    
		(&TCP_Server_Parameters)->TCP_SERVER_CONNECTED = 0;
		return SUCCEED;
	}
	return FAIL;
}

/**
 * @brief	获取ip地址
 * @param	ipbuf	ip地址字符串缓冲区
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_GetIP(u8* ipbuf) {
    
    
	u8* startIndex;
	u8* endIndex;
	u8 state;

	state = ESP8266_SendCmd("AT+CIFSR", "OK", 500);
	//如果获取IP地址失败
	if (state != SUCCEED) return FAIL;
	//如果获取IP成功
	startIndex = ESP8266_Check_Response("\""); //找到开始的("符号)指针位置
	endIndex = (u8*)strstr((const char*)(startIndex + 1), "\""); //找到结束的("符号)指针位置
	*endIndex = '\0'; //把最后一个"变为结束符
	sprintf((char*)ipbuf, "%s", startIndex + 1); //把""内的ip地址字符串赋给ipbuf
	return SUCCEED;
}


//							-- 初始化相关函数 --				   		  //


/**
 * @brief	ESP8266硬件初始化
*/
void ESP8266_HW_Init(void) {
    
    
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(ESP8266_RST_PORT_CLOCK, ENABLE);

	GPIO_InitStructure.GPIO_Pin = ESP8266_RST_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(ESP8266_RST_PORT, &GPIO_InitStructure);
}

/**
 * @brief	ESP8266硬件复位
*/
void ESP8266_HW_Reset(void) {
    
    
	ESP8266_RST_OUT = 0;
	delay_ms(100);
	ESP8266_RST_OUT = 1;
	delay_ms(500);
}

/**
 * @brief	ESP8266软件复位
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_SW_Reset(void) {
    
    
	u8 state;
	state = ESP8266_SendCmd("AT+RST", "OK", 500);
	if (state == SUCCEED) return SUCCEED;
	return FAIL;
}

/**
 * @brief	ESP8266恢复出厂设置
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Restore_Default(void) {
    
    
	u8 state;
	state = ESP8266_SendCmd("AT+RESTORE", "ready", 3000);
	if (state == SUCCEED) return SUCCEED;
	return FAIL;
}

/**
 * @brief	ESP8266初始化
 * @retval	成功SUCCEED,失败FAIL
*/
operateSta ESP8266_Init(void) {
    
    
	u8 state;

	USART3_Init(115200); //初始化串口3
	ESP8266_HW_Init();   //硬件初始化
	ESP8266_HW_Reset();  //硬件复位
	STA_Info_Init(&STA_Parameters);	//初始化STA模式相关参数
	AP_Info_Init(&AP_Parameters);	//初始化AP模式相关参数
	TCP_Server_Info_Init(&TCP_Server_Parameters); //初始化TCP Server相关参数
#if FIRMWARE_YUANZI_SUPPORT	//如果为刷了原子云固件的ESP8266
	Cloud_Info_Init(&Cloud_Parameters);	//初始化云平台相关参数
#endif // FIRMWARE_YUANZI_SUPPORT
	state = ESP8266_ATCmd_Test();	//测试AT指令
	if (state == SUCCEED) return SUCCEED;
	return FAIL;
}


5. Ejemplo de uso (observar los resultados a través del asistente de depuración del puerto serie)

5.1 archivo principal.c

// <头文件> //
#include "../CMSIS/stm32f10x.h"
#include "../Basic/sys/sys.h"
#include "../Basic/delay/delay.h"
#include "../Basic/usart/usart.h"
#include "../Hardware/ESP8266/esp8266.h"
// <头文件> //

// <变量> //
// <变量> //

int main(void) {
    
    
	u8 t = 0;
	u8 state;
	u8 time = 5;
	
	delay_init();
	delay_ms(200);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	USART1_Init(115200);
	//ESP8266初始化检查
	while (ESP8266_Init() != SUCCEED) {
    
    
		printf("ESP8266 Error\r\n");
		delay_ms(100);
	}
	printf("ESP8266 Initialization Succeed\r\n");
	//检查固件信息
	state = ESP8266_Check_FirmWare_Info();
	if (state != SUCCEED) printf("Firware Info Get Failed\r\n");
	else if (USART3_RX_STA & 0x8000){
    
    
		USART3_RX_BUF[USART3_RX_STA & 0x3fff] = '\0';
		printf("Firmware: %s\r\n", USART3_RX_BUF);
		USART3_RX_BUF_CLEAR();
	}
	//配置工作模式
	state = ESP8266_WorkMode_Conf(AP_STA_MODE);
	if (state != SUCCEED)	printf("WorkMode Setting Error\r\n");
	else  printf("AP STA Mode\r\n");
	//配置软路由
	state = ESP8266_SoftAP_Conf(&AP_Parameters);
	if (state != SUCCEED)  printf("SoftAP Configuration Fail\r\n");
	else  printf("Soft AP Established\r\n");
	//连接WIFI路由器
	state = ESP8266_Connect_WIFI(&STA_Parameters);
	while (time--) {
    
    
		if (time == 4) printf("Waiting for connecting with router...\r\n");
		delay_ms(1000);	//等待WIFI重连成功
	}
	if (state != SUCCEED) printf("Router Connecting Error\r\n");
	else printf("Router Connected\r\n");
	//连接TCP服务器
	state = ESP8266_Connect_TCP_Server(&TCP_Server_Parameters);
	if (state != SUCCEED)  printf("TCP Server Connecting Error\r\n");
	else  printf("TCP Server Connected\r\n");
	//连接原子云
	state = ESP8266_Connect_YuanZiCloud(&Cloud_Parameters);
	if (state != SUCCEED) printf("Cloud Connecting Error\r\n");
	else printf("Cloud Connected\r\n");
	//清空USART3数据
	USART3_RX_BUF_CLEAR();

	while (1) {
    
    
		//如果已连接TCP服务器或云平台,且串口3收到数据,就通过串口发送到电脑
		if (((&TCP_Server_Parameters)->TCP_SERVER_CONNECTED || 
			(&Cloud_Parameters)->CLOUD_CONNECTED) && 
			(USART3_RX_STA & 0x8000)) {
    
    
			
			USART3_RX_BUF[USART3_RX_STA & 0x3FFF] = '\0'; //添加结束符
			printf("Rec: %s\r\n", USART3_RX_BUF);
			USART3_RX_BUF_CLEAR();
		}
		t++;
		delay_ms(10);
		if (t == 200) {
    
    
			ESP8266_TransparentSendData("STM32F103ZE");
			ESP8266_CloudSendData("原子云");
			t = 0;
		}
	}
}


5.2 Resultados de ejecución del módulo ESP8266 de firmware de nube no atómica

inserte la descripción de la imagen aquí


5.3 Resultados de ejecución del módulo puntual atom ESP8266

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/ArthurCai/article/details/128890203
Recomendado
Clasificación