模组 :ESP-12F || ESP-12S || 待补充 ...
平台 :阿里云物联网平台
MCU :STM32F103RCT6
固件 :ESP8266 MQTT透传AT固件
准备工作:实现《ESP8266 AT指令连接阿里云物联网平台》
1.烧录ESP8266 MQTT透传 AT固件
2.部署好阿里云物联网平台
3.计算出MQTT的连接参数
4.AT指令实现连接阿里云物联网平台
5.AT指令实现阿里云物联网平台通讯
文章目录:
一、下载 ESP8266的STM32工程示例
二、解读 ESP8266的STM32工程示例
三、测试 MQTT通讯
四、工程的存在问题
下载地址:https://docs.ai-thinker.com/esp8266/examples/at_demo
下载说明:工程示例归ai-thinker所有,资源是在2020/05/20更新的,存在很多bug,笔者看着有点头疼,改了一段时间。
1. 我下载《使用文档》一直出错,没有下载成功,所以demo包都是自己阅读代码理解的,如果有错误,大家指正一下,谢谢。
2. 我用MDK5打开ESP8266的STM32工程,点击某个文件会闪退,然后重新下载了几次,工程才变正常,不知道具体原因。所以,为大家附上官方demo源码包(该demo更新时间为2020/05/20),以及我个人做了修改的demo源码包。
3. 官方工程bug很多,如果大家不想自己修改,建议使用我修改过的工程,当然,我的工程也有很多bug,逐步完善中... ...
链接:https://pan.baidu.com/s/1YWhsK6STZVUouneQYa152A
提取码:j4k2
说明:解读以笔者的工程为示例,官方示例那个真的欲哭无泪,我花费了很长时间去修改,我还需要慢慢完善自己的工程 !!
1. 默认连线方式:
UASRT3 : 用来打印信息(大家可以根据自己的需要改为其他串口)
UASRT2 : 用来与ESP8266通信
引脚 | 连接 | 引脚说明 |
---|---|---|
GPIOA2 | U2_TX | 连接ESP8266的 RX 引脚 |
GPIOA3 | U2_RX | 连接ESP8266的 TX 引脚 |
GPIOA4 | ESP8266_RST | 连接ESP8266的 RST 引脚 |
GPIOA5 | ESP8266_EN | 连接ESP8266的 EN 引脚 |
GPIOB10 | U3_TX | 连接USB转TTL的 RX 引脚 |
GPIOB11 | U3_RX | 连接USB转TTL的 TX 引脚 |
特别提醒:各个模块记得共地,不然可能模块不工作,或者打印不出信息,或者打印各种乱码,我最近才意识到“共地”的问题
2.用户需要修改:
(1)esp8266.h
(2)mqtt.h :
3. 串口接收协议
ESP8266串口(即USART2)接收结构体定义
#define RX_BUF_MAX_LEN 1024 //最大字节数,最大可以设为2^14
extern struct STRUCT_USART_Fram //数据帧结构体
{
char Data_RX_BUF[RX_BUF_MAX_LEN];
union
{
__IO u16 InfAll; //所有信息
struct
{
__IO u16 FramLength :15; // 接收字节长度 14:0
__IO u16 FramFinishFlag :1; // 接收完成标志 15
}InfBit; //按位信息
};
}ESP8266_Fram_Record_Struct;
ESP8266串口配置参数
void uart2_Init(u32 bound)//串口2 引脚为PA2--U2_TX PA3--U2_RX
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能指定端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA2
//USART2 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//USART2 参数 配置
USART_InitStructure.USART_BaudRate = bound; //设置串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8
USART_InitStructure.USART_StopBits = USART_StopBits_1; //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(USART2, &USART_InitStructure); //配置USART参数
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); //配置了接收中断
USART_ITConfig(USART2, USART_IT_IDLE, ENABLE); //配置总线空闲中断
USART_Cmd(USART2, ENABLE); //使能USART2
}
ESP8266串口(即UASRT2)接收数据的过程
void USART2_IRQHandler( void )
{
u8 ucCh;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //检测到接收区非空
{
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
ucCh = USART_ReceiveData(USART2);
/*未超出1024个字节的字符串*/
if(ESP8266_Fram_Record_Struct .InfBit .FramLength < ( RX_BUF_MAX_LEN - 1 ) ) // -1的目的:至少保留最后一位做结束位,补'\0'
{
ESP8266_Fram_Record_Struct .Data_RX_BUF[ ESP8266_Fram_Record_Struct .InfBit .FramLength ++ ] = ucCh;
}
/*对超出1024个字节的字符串做容错处理*/
}
else if(USART_GetFlagStatus(USART2, USART_FLAG_IDLE) != RESET) //检测到总线空闲
{
USART2->SR;
USART2->DR;
ESP8266_Fram_Record_Struct .InfBit .FramFinishFlag = 1;
ESP8266_Fram_Record_Struct.Data_RX_BUF[ESP8266_Fram_Record_Struct.InfBit.FramLength] = '\0';
// TcpClosedFlag = strstr ( ESP8266_Fram_Record_Struct .Data_RX_BUF, "CLOSED" ) ? 1 : 0;
// TcpReceiveFlag = strstr ( ESP8266_Fram_Record_Struct .Data_RX_BUF, "+IPD" ) ? 1 : 0;
MQTTReceiveFlag = strstr ( ESP8266_Fram_Record_Struct .Data_RX_BUF, "+MQTTSUBRECV" ) ? 1 : 0;
// MQTTClosedFlag = strstr ( ESP8266_Fram_Record_Struct .Data_RX_BUF, "CLOSED" ) ? 1 : 0;
}
}
void ESP8266_STA_MQTTClient_Test(void)
{
char mqtt_message[1024];
char str[128] = {0};
u8 cnt = 0;
printf("正在配置 ESP8266 MQTT ...\r\n");
ESP8266_AT_Test(); //恢复出厂默认
ESP8266_Net_Mode_Choose(STA); //配置热点信息
while(!ESP8266_JoinAP(User_ESP8266_SSID, User_ESP8266_PWD));
ESP8266_MQTTUSERCFG(User_ESP8266_client_id,User_ESP8266_username,User_ESP8266_password);
ESP8266_MQTTCONN( User_ESP8266_MQTTServer_IP, User_ESP8266_MQTTServer_PORT);
ESP8266_MQTTSUB( User_ESP8266_MQTTServer_Topic);
ESP8266_MQTTSUB( User_ESP8266_MQTTServer_Topic_Property_Post_Reply);
ESP8266_MQTTSUB(User_ESP8266_MQTTServer_Topic_Property_Set);
printf("ESP8266 MQTT 配置完成 ...\r\n");
ESP8266_Fram_Record_Struct.InfAll = 0;
while(1)
{
//每32s发送一次
if(cnt % 32 == 0)
{
memset(str, sizeof(str),0);
memset(mqtt_message,sizeof(mqtt_message),0);
sprintf(str,"I AM ESP8266");//格式化发送字符串到MQTT服务器
MQTT_SendString (User_ESP8266_MQTTServer_Topic,str);//发送数据到MQTT服务器
sprintf(mqtt_message,"{\\\"method\\\":\\\"thing.service.property.post\\\"\\,\\\"id\\\":\\\"2012934115\\\"\\,\\\"params\\\":{\\\"PowerSwitch\\\":1}\\,\\\"version\\\":\\\"1.0.0\\\"}");
MQTT_SendString (User_ESP8266_MQTTServer_Topic_Property_Post,mqtt_message);//发送数据到MQTT服务器
}
if(MQTTReceiveFlag == 1) //判断是否接收到TCP网络数据
{
printf("Message From ESP8266 : %s\r\n",ESP8266_Fram_Record_Struct .Data_RX_BUF);
printf("Length Of Message : %d\r\n",ESP8266_Fram_Record_Struct.InfBit.FramLength);
ESP8266_Fram_Record_Struct.InfAll = 0; //清空ESP8266_Fram_Record_Struct接收标志,准备接收下一条消息
MQTTReceiveFlag = 0;
}
delay_ms(1000);
cnt++;
}
}
- - 云端下发设置指令
++ ESP 接收到设置指令
1. 粘包问题 :
2. 混合度中: