3.STM32通过串口发送AT命令控制ESP8266连接阿里云的代码
目录
模块简介
ESP-01s接线
使用注意
模块代码
usart.h
usart.c
esp8266.h
esp8266.c
main.c
解析json多个标识符函数
视频演示
前言
1.ESP8266 模块 AT(含MQTT)固件下载教程_安信可esp8266 mqtt固件下载-CSDN博客
2.单片机通过AT指令控制ESP8266+TCP 实现收发数据_单片机发送at指令到通信模块-CSDN博客
模块简介
ESP-01S 是由安信可科技开发的 Wi-Fi 模块.
1.该模块核心处理器 ESP8266 在较小尺寸封装中集成了业界领先的 Tensilica L106 超低功耗 32 位微型 MCU,带有 16 位精简模式,主频支持 80 MHz 和 160 MHz,支持 RTOS,集成 Wi-Fi MAC/ BB/RF/PA/LNA。
2.ESP-01S Wi-Fi 模块支持标准的 IEEE802.11 b/g/n 协议,完整的 TCP/IP 协议栈》用户可以使用该模块为现有的设备添加联网功能,也可以构建独立的网络控制器。
3.ESP8266 是高性能无线 SoC,以最低成本提供最大实用性,为 Wi-Fi 功能嵌入其他系统提供无限可能。
ESP-01s接线
ESP8266-01S | STM32F103C8T6 |
VCC | 3.3V |
GND | 接地 |
TX | PA2 |
Rx | PA3 |
使用注意
1.esp8266模块需要烧录MQTT固件才能使用相关的AT命令
不同固件AT命令使用方法:
.基础 AT 命令集 – ESP32 – — ESP-AT 用户指南 latest 文档 (espressif.com)
2. 使用printf重定向需要勾选这个
3.如果代码编译时,keil中出现:
Error: L6218E: Undefined symbol __aeabi_assert (referred from core_json.o).
解决方法:
4.程序中需要解析json数据,需要文件的可以联系我
5.代码烧录前需要配置个人WIFI与阿里云信息
模块代码
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
usart.c
//头文件
#include "stm32f10x.h" // Device header
//硬件驱动
#include "usart.h"
//C库
#include <stdarg.h>
#include <stdio.h>
//串口1为调试串口 主要功能是发送数据到电脑
/**
* @brief USART1初始化
* @param baud-波特率
* @retval none
*/
void USART1_Init(unsigned int baud)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; //PA9 TXD
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//PA10 RXD
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
USART_InitTypeDef USART_InitStruct;
USART_InitStruct.USART_BaudRate = baud;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Tx; //USART_Mode_Rx | USART_Mode_Tx
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStruct);
// USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//
// NVIC_InitTypeDef NVIC_InitStruct;
// NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
// NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
// NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
// NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
// NVIC_Init(&NVIC_InitStruct);
USART_Cmd(USART1, ENABLE);
}
/**
* @brief USART2初始化
* @param baud-波特率
* @retval none
*/
void USART2_Init(unsigned int baud)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//PA2 TXD
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//PA3 RXD
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
USART_InitTypeDef USART_InitStruct;
USART_InitStruct.USART_BaudRate = baud;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_Init(USART2, &USART_InitStruct);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//放在主函数内初始化
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStruct);
USART_Cmd(USART2, ENABLE);
}
/**
* @brief 串口数据发送
* @param USARTx-串口号 str-待发送数据 len-数据长度
* @retval none
*/
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); //等待发送寄存器为空
}
}
int fputc(int ch,FILE *f ) //printf重定向
{
USART_SendData(USART2,(uint8_t)ch);
while(USART_GetFlagStatus (USART2,USART_FLAG_TC) == RESET);
return ch;
}
/**
* @brief 格式化打印
* @param USARTx-串口号 fmt 不定长参数
* @retval none
*/
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);
}
}
///**
// * @brief 串口1收发中断
// * @param none
// * @retval none
// */
//void USART1_IRQHandler(void)
//{
// if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
// {
// USART_ClearFlag(USART1, USART_FLAG_RXNE);
// }
//}
esp8266.h
#ifndef _ESP8266_H_
#define _ESP8266_H_
#include "stm32f10x.h"
#define REV_OK 0 //接收完成标志位
#define REV_WAIT 1 //接受未完成标志位
void ESP8266_Init(void);
void ESP8266_Clear(void);
_Bool ESP8266_SendCmd(char *cmd, char *res);
void ESP8266_SendDatas(uint8_t Humi,uint8_t Temp);
uint8_t esp8266_receive_msg(void);
#endif
esp8266.c
//头文件
#include "stm32f10x.h"
//硬件驱动
#include "delay.h"
#include "usart.h"
#include "DHT11.h"
#include "LED.h"
#include "esp8266.h"
//C库
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
//cjson解析
#include "core_json.h"
#include "OLED.h"
#define WIFI_SSID "k50"
#define WIFI_PASSWD "123456abc"
#define MQTT_CLIENT_ID "mqtt_stm32|securemode=2\\,signmethod=hmacsha2\\,timestamp=1717031289607|"
#define MQTT_USER_NAME "mqtt_stm32&k2c6ceYexiH"
#define MQTT_PASSWD "1C176535D76A1735FD212DEBE0CDA04D0D5E6532"
#define BROKER_ASDDRESS "a1k1c9ceYexiH.iot-as-mqtt.cn-shanghai.aliyuncs.com"
#define SUB_TOPIC "/sys/k2c6ceYexiH/mqtt_stm32/thing/service/property/set"
#define PUB_TOPIC "/sys/k2c6ceYexiH/mqtt_stm32/thing/event/property/post"
#define JSON_FORMAT "{\\\"params\\\":{\\\"temp\\\":%d\\,\\\"humi\\\":%d\\,\\\"led\\\":%d}\\,\\\"version\\\":\\\"1.0.0\\\"}\",0,0\r\n"
unsigned char esp8266_buf[512]; //数据缓存
uint16_t esp8266_cnt = 0, esp8266_cntPre = 0;
unsigned char receive_start = 0; //串口2接收开始标志位
uint16_t receive_finish = 0; //串口2接收结束标志位
/**
* @brief 清楚缓存
* @param none
* @retval none
*/
void ESP8266_Clear(void)
{
memset(esp8266_buf, 0, sizeof(esp8266_buf));
esp8266_cnt = 0;
receive_start = 0;
receive_finish = 0;
}
/**
* @brief 等待接收完成
* @param none
* @retval REV_OK-接收完成 REV_WAIT-接收超时未完成
*/
_Bool ESP8266_WaitRecive(void)
{
if(esp8266_cnt == 0) //接收计数为0,则说明没有处于接收数据中-esp8266_cnt没在中断函数++
return REV_WAIT;
if(esp8266_cnt == esp8266_cntPre) //如果这一次的值和上一次相同,则说明接收完毕
{
esp8266_cnt = 0; //清0接收计数
return REV_OK; //返回接收完成标志位
}
esp8266_cntPre = esp8266_cnt; //将这次的数存起来,esp8266_cnt存储下一个数
return REV_WAIT; //返回接收未完成标志位
}
/**
* @brief 发送命令
* @param cmd-命令 res-需要对比的返回指令
* @retval 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;
}
/**
* @brief ESP8266-初始化
* @param none
* @retval none
*/
void ESP8266_Init(void)
{
ESP8266_Clear();
UsartPrintf(USART_DEBUG, " 1. CWMODE\r\n");
OLED_ShowString(1,1,"1.SET CWMODE");
while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))//Station 模式
Delay_ms(500);
UsartPrintf(USART_DEBUG, " 2. ATE0\r\n");
OLED_ShowString(1,1,"2.SET ATE0 ");
while(ESP8266_SendCmd("ATE0\r\n", "OK"))//0-关闭回显
Delay_ms(500);
UsartPrintf(USART_DEBUG, " 3. AT+CWDHCP\r\n");
OLED_ShowString(1,1,"3.SET CWDHCP ");
while(ESP8266_SendCmd("AT+CWAUTOCONN=0\r\n", "OK"))//0-上电不自动连接 AP 1-上电自动连接 AP(默认)
Delay_ms(500);
UsartPrintf(USART_DEBUG, " 4. AT+RST\r\n");
OLED_ShowString(1,1,"4.SET RST ");
while(ESP8266_SendCmd("AT+RST\r\n", "OK"))//重启模块
Delay_ms(500);
UsartPrintf(USART_DEBUG, " 5. CWJAP\r\n");
OLED_ShowString(1,1,"5.Link WIFI ");
while(ESP8266_SendCmd("AT+CWJAP=\""WIFI_SSID"\",\""WIFI_PASSWD"\"\r\n", "GOT IP"))//连接WIFI
Delay_ms(500);
UsartPrintf(USART_DEBUG, " 6. MQTTUSERCFG\r\n");//设置 MQTT 用户属性
OLED_ShowString(1,1,"6.MQTTUSERCFG ");
while(ESP8266_SendCmd("AT+MQTTUSERCFG=0,1,\""MQTT_CLIENT_ID"\",\""MQTT_USER_NAME"\",\""MQTT_PASSWD"\",0,0,\"\"\r\n","OK"))
Delay_ms(500);
UsartPrintf(USART_DEBUG, " 7. MQTTCONN\r\n");//连接 MQTT Broker
OLED_ShowString(1,1,"7.MQTTCONN ");
while(ESP8266_SendCmd("AT+MQTTCONN=0,\""BROKER_ASDDRESS"\",1883,0\r\n","OK"))
Delay_ms(500);
UsartPrintf(USART_DEBUG, " 8. MQTTSUB\r\n");//订阅 MQTT Topic
OLED_ShowString(1,1,"8. MQTTSUB ");
while(ESP8266_SendCmd("AT+MQTTSUB=0,\""SUB_TOPIC"\",0\r\n","OK"))
Delay_ms(500);
OLED_ShowString(1,1,"9.ESP Init OK!!");
UsartPrintf(USART_DEBUG, " 9. ESP8266 Init OK\r\n");
}
/**
* @brief ESP8266发送数据到阿里云
* @param Humi-湿度 Temp-温度
* @retval none
*/
void ESP8266_SendDatas(uint8_t Humi,uint8_t Temp)
{
printf("AT+MQTTPUB=0,\""PUB_TOPIC"\",\""JSON_FORMAT"\"",Temp,Humi,LED_Status);//发布 MQTT 消息
Delay_ms(500);//删去
}
/**
* @brief 解析json数据
* @param json_msg-json数据 json_len-json数据长度
* @retval 0-找到指定json数据 1-未找到
*/
uint8_t parse_json_msg(uint8_t *json_msg,uint8_t json_len)
{
uint8_t retval =0;
JSONStatus_t result;
char query[] = "params.led"; //修改
size_t queryLength = sizeof( query ) - 1;
char * value;
size_t valueLength;
result = JSON_Validate((const char *)json_msg, json_len);
if( result == JSONSuccess)
{
result = JSON_Search((char *)json_msg, json_len, query, queryLength,&value, &valueLength );
if( result == JSONSuccess)
{
char save = value[valueLength];
value[valueLength] = '\0';
UsartPrintf(USART_DEBUG,"Found: %s %d-> %s\n", query, valueLength,value);//调试信息
value[valueLength] = save;
LED_Status=atoi(value); //LED_Status修改
retval = 0;
}
else
{
retval = 1;
}
}
else
{
retval = 1;
}
return retval;
}
/**
* @brief esp8266接收数据
* @param[in] none
* @retval 0-接收数据正常 1-接收数据异常或无数据
*/
uint8_t esp8266_receive_msg(void)
{
uint8_t retval =0;
int msg_len=0;
uint8_t msg_body[128] = {0};
if(receive_start == 1) //接收到数据,中断置1
{
do
{
receive_finish++; //等待串口接收不到数据后再延时5ms
Delay_ms(1);
}while(receive_finish < 5);
if(strstr((const char*)esp8266_buf,"+MQTTSUBRECV:"))//如果数据中有关键字
{
UsartPrintf(USART_DEBUG,"esp8266_buf:%s\r\n",esp8266_buf);
sscanf((const char *)esp8266_buf,"+MQTTSUBRECV:0,\""SUB_TOPIC"\",%d,%s",&msg_len,msg_body);
UsartPrintf(USART_DEBUG,"len:%d,msg:%s\r\n",msg_len,msg_body);
if(strlen((const char*)msg_body)== msg_len)//校验数据
{
retval = parse_json_msg(msg_body,msg_len);
}
else
{
retval = 1;
}
}
else
{
retval = 1;
}
}
else
{
retval = 1;
}
ESP8266_Clear();
return retval;
}
/**
* @brief USART2收发中断
* @param[in] none
* @retval none
*/
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;
receive_start = 1; //串口2接收数据开始位置1
receive_finish = 0; //串口2接收数据完成位清0
USART_ClearFlag(USART2, USART_FLAG_RXNE);
}
}
main.c
#include "stm32f10x.h" // Device header
#include "LED.h"
#include "DHT11.h"
#include "OLED.h"
#include "Delay.h"
#include "esp8266.h"
#include "usart.h"
#include "Timer.h"
uint8_t temp,humi;
uint8_t Send_msg_index=0;
int main(void)
{
LED_init();
OLED_Init();
Timer_Init();
USART1_Init(115200);
USART2_Init(115200);
ESP8266_Init();
OLED_ShowString(2,1,"Humi:");
OLED_ShowString(3,1,"Temp:");
OLED_ShowString(4,1,"LED:0");
while (1)
{
DHT11_GetData(&humi,&temp);
OLED_ShowNum(2,6,humi,2);
OLED_ShowNum(3,6,temp,2);
if(esp8266_receive_msg()==0)
{
LED_Turn();
OLED_ShowNum(4,5,LED_Status,1);
}
if(Send_msg_index)
{
ESP8266_SendDatas(humi,temp);
Send_msg_index=0;
}
Delay_ms(10);
}
}
void TIM2_IRQHandler(void)
{
static uint8_t count=0;
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
count++;
if(count>=5)
{
Send_msg_index=1;
count=0;
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
解析json多个标识符函数
替换esp8266代码中的对应函数
/**
* @brief 解析json数据
* @param json_msg-json数据 json_len-json数据长度
* @retval 0-找到指定json数据 1-未找到
*/
uint8_t parse_json_msg(uint8_t *json_msg,uint8_t json_len)
{
uint8_t retval = 0;
JSONStatus_t result;
char *queries[] = {"params.led", "params.temperature", "params.humidity"}; // 修改:添加更多查询项
size_t numQueries = sizeof(queries) / sizeof(queries[0]);
for (size_t i = 0; i < numQueries; ++i) {
char *query = queries[i];
size_t queryLength = strlen(query);
char *value;
size_t valueLength;
result = JSON_Validate((const char *)json_msg, json_len);
if (result == JSONSuccess) {
result = JSON_Search((char *)json_msg, json_len, query, queryLength, &value, &valueLength);
if (result == JSONSuccess) {
char save = value[valueLength];
value[valueLength] = '\0';
UsartPrintf(USART_DEBUG, "Found: %s %d-> %s\n", query, valueLength, value); // 调试信息
value[valueLength] = save;
// 在这里处理找到的数据,可以根据不同的查询项进行不同的处理
if (strcmp(query, "params.led") == 0) {
LED_Status = atoi(value);
// 处理 LED 数据
} else if (strcmp(query, "params.temperature") == 0) {
// 处理温度数据
} else if (strcmp(query, "params.humidity") == 0) {
// 处理湿度数据
}
retval = 0;
} else {
retval = 1;
}
} else {
retval = 1;
}
}
return retval;
}
视频演示
ESP8266-01s连接阿里云实验
作者:我不吃代码