使用stm32通过串口连接esp8266,再使用AT指令来连接mqtt,话不多说,直接上干货
固件烧录
使用安信可的esp8266AT固件
下载地址
使用说明
STM32配置
为esp8266配置串口,并初始化波特率为115200;并开启中断
hal库直接cubeMX生成代码;
标准库初始化如下;
void Usart3_Init(u32 baud) //串口初始化
{
GPIO_InitTypeDef gpioInitStruct;
USART_InitTypeDef usartInitStruct;
NVIC_InitTypeDef nvicInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, 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);
}
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_TXE) == RESET); //等待发送完成
}
//记得加上main里中断分组NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
esp8266初始化
HAL库
该代码使用tcp透传的方式连接mqtt
#define WIFI_SSID "wif名"
#define WIFI_PASSWD "WiFi密码"
#define MQTT_CONNECT_ID "emqx_MzgzMT"
#define MQTT_CONNECT_IP "MQTT服务器IP"
#define MQTT_USER "MQTT用户账号"
#define MQTT_PASSWD "MQTT用户密码"
unsigned char receive_buf[512]; //串口2接收缓存数组
unsigned char receive_start = 0; //串口2接收开始标志位
uint16_t receive_count = 0; //串口2接收数据计数器
uint16_t receive_finish = 0; //串口2接收结束标志位
typedef struct {
int connection_id;
int data_length;
char data_content[512]; // Adjust the size as needed
} ParsedData;
void USART4_SendByte(uint8_t ch)
{
HAL_UART_Transmit(&huart4,&ch,1,100);
}
uint8_t esp8266_ClientServer(void)
{
__HAL_UART_ENABLE_IT(&huart4,UART_IT_RXNE); //打开串口2接收中断
uint16_t sendbuff[256];
printf("1.SETTING STATION MODE\r\n");
while(esp8266_send_cmd((uint8_t *)"AT+CWMODE=1\r\n",strlen("AT+CWMODE=1\r\n"),"OK")!=0)
{
HAL_Delay(1000);
}
printf("2.CLOSE ESP8266 ECHO\r\n");
while(esp8266_send_cmd((uint8_t *)"ATE0\r\n",strlen("ATE0\r\n"),"OK")!=0)
{
HAL_Delay(1000);
}
printf("3.NO AUTO CONNECT WIFI\r\n");
while(esp8266_send_cmd((uint8_t *)"AT+CWAUTOCONN=0\r\n",strlen("AT+CWAUTOCONN=0\r\n"),"OK")!=0)
{
HAL_Delay(1000);
}
printf("4.RESET ESP8266\r\n");
while(esp8266_reset() != 0)
{
HAL_Delay(1000);
}
printf("5.CONFIG WIFI NETWORK\r\n");
while(esp8266_config_network() != 0)
{
HAL_Delay(2000);
}
printf("6.TCP CONNECT MUX \r\n");
while(esp8266_send_cmd((uint8_t *)"AT+CIPMUX=0\r\n",strlen("AT+CIPMUX=0\r\n"),"OK")!=0)
{
HAL_Delay(2000);
}
printf("Esp8266 CONNECT IP: \r\n");
while(esp8266_send_cmd((uint8_t *)"AT+CIFSR\r\n",strlen("AT+CIFSR\r\n"),"")!=0)
{
HAL_Delay(2000);
}
sprintf((char*)sendbuff,"AT+CIPSTART=\"TCP\",\"%s\",1883\r\n",MQTT_CONNECT_IP);
printf("连接TCP:%s",(char*)sendbuff);
printf("7.TCP CONNECT IP\r\n");
while(esp8266_send_cmd((uint8_t *)sendbuff,strlen((const char*)sendbuff),"OK")!=0)
{
HAL_Delay(2000);
}
printf("8.TCP CONNECT MODE \r\n");
while(esp8266_send_cmd((uint8_t *)"AT+CIPMODE=1\r\n",strlen("AT+CIPMODE=1\r\n"),"OK")!=0)
{
HAL_Delay(2000);
}
while(esp8266_send_cmd((uint8_t *)"AT+CIPSEND\r\n",strlen("AT+CIPSEND\r\n"),"OK")!=0)
{
HAL_Delay(2000);
}
printf("9.ESP8266 CONNECT Server OK!!!\r\n");
esp_connect_ok = ESP_STA_CONNECTED;
return 0;
}
uint8_t esp8266_send_cmd(unsigned char *cmd,unsigned char len,char *rec_data)
{
unsigned char retval =0;
unsigned int count = 0;
HAL_UART_Transmit(&huart4, cmd, len, 1000);
while((receive_start == 0)&&(count<1000))
{
count++;
HAL_Delay(1);
}
if(count >= 1000)
{
retval = 1;
}
else
{
do
{
receive_finish++;
HAL_Delay(1);
}
while(receive_finish < 500);
retval = 2;
if(strstr((const char*)receive_buf, rec_data))
{
printf("%s",receive_buf);
retval = 0;
}
}
uart4_receiver_clear(receive_count);
return retval;
}
void uart4_receiver_clear(uint16_t len)
{
memset(receive_buf,0x00,len);
receive_count = 0;
receive_start = 0;
receive_finish = 0;
}
void USART4_Send_Poll(uint8_t *buff, uint16_t Size)
{
uint16_t i;
printf("USART4_SendByte\r\n");
for(i = 0; i < Size; i++)
{
USART4_SendByte(*buff++);
}
}
void ESP_Send(uint8_t *buff, uint16_t len)
{
USART4_Send_Poll(buff,len);
printf("ESP_Send\r\n");
}
标准库
#define REV_OK 0 //接收完成标志
#define REV_WAIT 1 //接收未完成标志
#define INIT_FINSH 1 //连接置0,连接完成置1
#define MQTT_TOPIC_SEND "attributes"
#define MQTT_TOPIC_RECV "attributes/push"
#define MQTT_CLIENT_ID "1234kkk"
//需要更改
#define ESP8266_WIFI_INFO "AT+CWJAP=\"WiFi名\",\"WiFi密码\"\r\n"
#define ESP8266_ONENET_INFO "AT+MQTTCONN=0,\"mqttip地址\",1883,1\r\n" //MQTT接入地址
#define MQTT_USERNAME "mqtt账号" //账号
#define MQTT_PASSWORD "mqtt密码" //密码
unsigned char esp8266_buf[128];
unsigned short esp8266_cnt = 0, esp8266_cntPre = 0;
u8 init_finish = 1;
void ESP8266_Clear(void)
{
memset(esp8266_buf, 0, sizeof(esp8266_buf));
esp8266_cnt = 0;
}
void ESP8266_Init(void)
{
char str123[100]={0};
init_finish = 0;
delay_ms(1000);
ESP8266_Clear();
printf("\r\n0. 检查WiFi模块\r\n");
while(ESP8266_SendCmd("AT\r\n", "OK"))
delay_ms(500);
printf("\r\n1. 重置wifi模块\r\n");
ESP8266_SendCmd("AT+RST\r\n","");
delay_ms(500);
printf("\r\n2. 设置模块为STA模式\r\n");
while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))
delay_ms(500);
printf("\r\n3. 连接wifi\r\n");
while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP"))
delay_ms(500);
printf("\r\n4. 设置时区为:中国早上八点\r\n");
while(ESP8266_SendCmd("AT+CIPSNTPCFG=1,8,\"ntp1.aliyun.com\"\r\n", ""))
delay_ms(500);
printf("\r\n5. 设置MQTT用户名和密码\r\n");
sprintf(str123, "AT+MQTTUSERCFG=0,1,\"%s\",\"%s\",\"%s\",0,0,\"\"\r\n",MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD);
while(ESP8266_SendCmd(str123, "OK"))
delay_ms(500);
printf("\r\n6. 设置MQTT接入地址\r\n");
while(ESP8266_SendCmd(ESP8266_ONENET_INFO, "OK"))
delay_ms(500);
printf("\r\n7. 订阅平台消息\r\n");
memset(str123,0,100);
sprintf(str123, "AT+MQTTSUB=0,\"%s\",1\r\n",MQTT_TOPIC_RECV);
while(ESP8266_SendCmd(str123, "OK"))
delay_ms(500);
printf("\r\n8. ESP8266初始化完成\r\n");
init_finish = 1;
}
//判断是否接收完成
_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; //返回接收未完成标志
}
//发送命令
_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) //如果检索到关键词
{
printf("%s\r\n",esp8266_buf);
ESP8266_Clear(); //清空缓存
return 0;
}
}
delay_ms(30);
}
return 1;
}
//上传消息
void ESP8266_SendData_Float(char *property,float val)
{
char *buf = malloc(100 * sizeof(char));
memset(buf,0,100);
sprintf(buf,"AT+MQTTPUB=0,\"%s\",\"{\\\"%s\\\":%.1f}\",0,0\r\n",MQTT_TOPIC_SEND,property,val);
Usart_SendString(USART2, (u8 *)buf,strlen(buf));
delay_ms(500);
free(buf);
}
void ESP8266_SendData_Int(char *property,int val)
{
char *buf = malloc(100 * sizeof(char));
memset(buf,0,100);
sprintf(buf,"AT+MQTTPUB=0,\"%s\",\"{\\\"%s\\\":%d}\",0,0\r\n",MQTT_TOPIC_SEND,property,val);
Usart_SendString(USART2, (u8 *)buf,strlen(buf));
delay_ms(500);
free(buf);
}
void ESP8266_SendData_Bool(char *property,char* val)
{
char *buf = malloc(100 * sizeof(char));
memset(buf,0,100);
sprintf(buf,"AT+MQTTPUB=0,\"%s\",\"{\\\"%s\\\":%s}\",0,0\r\n",MQTT_TOPIC_SEND,property,val);
Usart_SendString(USART2, (u8 *)buf,strlen(buf));
delay_ms(500);
free(buf);
}
void Usart2_Init(u32 baud)
{
GPIO_InitTypeDef gpioInitStruct;
USART_InitTypeDef usartInitStruct;
NVIC_InitTypeDef nvicInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, 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);
}
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_TXE) == RESET); //等待发送完成
}
}
void USART2_IRQHandler(void)
{
if(USART_GetFlagStatus(USART2, USART_FLAG_RXNE) != RESET)
{
u8 t = USART2 -> DR;
esp8266_buf[esp8266_cnt++] =t;
if(init_finish)
{
if(t == '\n' && esp8266_buf[esp8266_cnt-2] == '\r')
{
esp8266_buf[esp8266_cnt] = '\0';
printf("%s",esp8266_buf);
esp8266_cnt = 0;
}
}
}
}
ThingCluod
ThingCluod简介
ThingsCloud 在设备和用户之间建立开箱即用的云平台和云应用,实现数据采集、实时控制、数据可视化、零代码应用开发、开放 API,构建灵活强大的物联网应用。
ThingCluod配置
注册账号,创建设备,看说明操作
将这些加在代码中
订阅主题
以下主题用于 设备向云平台发布消息。
消息类型 | 主题 |
---|---|
设备上报属性值 | attributes |
设备获取当前属性值 | attributes/get/<id> |
设备上报事件 | event/report/<id> |
设备回复命令 | command/reply/<id> |
设备自定义数据上报 | data/<identifier> |
以下主题用于 设备接收云平台下发的消息。
消息类型 | 主题 |
---|---|
接收属性上报的响应 | attributes/response |
接收属性获取的响应 | attributes/get/response/+ |
接收下发的属性 | attributes/push |
接收事件上报的响应 | event/response/+ |
接收下发的命令 | command/send/+ |
接收命令回复的响应 | command/reply/response/+ |
接收自定义数据下发 | data/<identifier> /set |
一般使用attributes作为设备上报,使用attributes/push,来接受云平台下发
注意传输格式的json,需要注意格式