Controlador simple para el módulo ESP8266: conexión a la nube basada en el firmware de 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:
- Establecer el modo de trabajo
- conectar el enrutador
- Conectarse al servidor TCP
- Conéctese a Atomic Cloud (módulo ESP8266 con firmware de Atomic Cloud flasheado)
- 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
- esp8266_timer.c (el archivo del temporizador usa TIM7 para medir el tiempo durante la transmisión usart3)
- esp8266_temporizador.h
- esp8266.c
- 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
5.3 Resultados de ejecución del módulo puntual atom ESP8266