目录
- 前言
- 设计目标
- 硬件介绍
- 手机app
- 软件设计
- 连接ESP01S
- 代码部分
- 串口
- Usart.h
- Usart.c
- Serial.h
- Serial.c
- ESP01S
- ESP01S.h
- ESP01S.c
- 定时器
- Timer.h
- Timer.c
- DHT11温湿度传感器
- DHT11.h
- DHT11.c
- LED
- LED.h
- LED.c
- OLED
- 按键
- Key.h
- Key.c
- 主函数main
- App Inventor
- 结语
前言
翻东西时发现一个ESP01S模块,想着玩一下
本篇学习ESP01S连接巴法云,AT指令参考:https://espressif-docs.readthedocs-hosted.com/projects/esp-at/zh-cn/release-v2.2.0.0_esp8266/AT_Command_Set/index.html
设计目标
- STM32通过DHT11获取温湿度,通过ESP01S连接巴法云发布温湿度,手机app订阅巴法云获取温湿度
- STM32连接LED灯,实现通过手机app控制LED灯的状态
硬件介绍
- STM32F103C8T6最小系统板
- ESP01S模块
- DHT11温湿度传感器
手机app
手机app使用App Inventor平台开发,可视化编程,简单方便
软件设计
连接ESP01S
STM32通过USART2连接ESP01S
STM32 ESP01S PA2(TX) RX PA3(RX) TX VCC RST VCC EN 3.3 3V3 GND GND 注意:根据EPS01S规格书可查,3V3供电引脚需要外部供电电源输出电流在 500mA 以上,如果上电后不稳定(自动重启),可能是供电不足,单片机连接的电源电流有限,建议更换或增加电源(最小系统板尾部有USB-mrico连接手机充电器即可,建议先连接充电器再连接ST-LINK,防止电脑USB口电压不稳导致电脑出问题)
代码部分
串口
USART1连接电脑(使用串口工具)用于调试显示,USART2连接ESP01S
USART使用两组中断,接收中断和空闲中断实现“接收”和“接收完成”的功能
用数组接收串口数据,初始化时把外部指针指向数组的地址,获取接收数据标志位时,直接对外部指针进行处理即可(不通过extern使用全局变量,便于移植),不需要调用函数传出接收数据(第二次接收数据时直接覆盖,因此需要及时处理)
Usart.h
#ifndef __USART_H #define __USART_H #include "stm32f10x.h" #include #include #include #define USART_BUF_SIZE 100 /* USART一次收发数据长度 */ void Usart1_Init(unsigned int baud); /* 串口1初始化 */ void Usart2_Init(unsigned int baud); /* 串口2初始化 */ void Usart_SendString(USART_TypeDef *USARTx, uint8_t *str, uint16_t len); /* 串口数据发送 */ void UsartPrintf(USART_TypeDef *USARTx, char *fmt, ...); /* 串口格式化打印 */ void USART1_IRQHandler_Callback(uint8_t data, FlagStatus idle); /* 串口1中断回调函数 */ void USART2_IRQHandler_Callback(uint8_t data, FlagStatus idle); /* 串口2中断回调函数 */ #endif
Usart.c
#include "Usart.h" /* ************************************************************ * 函数名称: Usart1_Init * 函数功能: 串口1初始化 * 入口参数: baud:设定的波特率 * 返回参数: 无 * 说明: ************************************************************ */ void Usart1_Init(unsigned int baud) { GPIO_InitTypeDef gpioInitStruct; USART_InitTypeDef usartInitStruct; NVIC_InitTypeDef nvicInitStruct; //开启时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); // PA9 TXD gpioInitStruct.GPIO_Mode = GPIO_Mode_AF_PP; gpioInitStruct.GPIO_Pin = GPIO_Pin_9; gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &gpioInitStruct); // PA10 RXD gpioInitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; gpioInitStruct.GPIO_Pin = GPIO_Pin_10; gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &gpioInitStruct); //初始化USART1 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(USART1, &usartInitStruct); USART_Cmd(USART1, ENABLE); // 使能串口 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 使能接收中断 USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); // 使能串口总线空闲中断 nvicInitStruct.NVIC_IRQChannel = USART1_IRQn; nvicInitStruct.NVIC_IRQChannelCmd = ENABLE; nvicInitStruct.NVIC_IRQChannelPreemptionPriority = 0; nvicInitStruct.NVIC_IRQChannelSubPriority = 2; NVIC_Init(&nvicInitStruct); } /* ************************************************************ * 函数名称: Usart2_Init * 函数功能: 串口2初始化 * 入口参数: baud:设定的波特率 * 返回参数: 无 * 说明: TX-PA2 RX-PA3 ************************************************************ */ void Usart2_Init(unsigned int baud) { GPIO_InitTypeDef gpioInitStruct; USART_InitTypeDef usartInitStruct; NVIC_InitTypeDef nvicInitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, 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); // 使能接收中断 USART_ITConfig(USART2, USART_IT_IDLE, ENABLE); // 使能串口总线空闲中断 nvicInitStruct.NVIC_IRQChannel = USART2_IRQn; nvicInitStruct.NVIC_IRQChannelCmd = ENABLE; nvicInitStruct.NVIC_IRQChannelPreemptionPriority = 0; nvicInitStruct.NVIC_IRQChannelSubPriority = 0; NVIC_Init(&nvicInitStruct); } /* ************************************************************ * 函数名称: Usart_SendString * 函数功能: 串口数据发送 * 入口参数: USARTx:串口组 * str:要发送的数据 * len:数据长度 * 返回参数: 无 * 说明: ************************************************************ */ void Usart_SendString(USART_TypeDef *USARTx, uint8_t *str, uint16_t len) { uint16_t count = 0; for (; count
Serial.h
#ifndef __SERIAL_H #define __SERIAL_H #include "Usart.h" #define SERIAL_USART USART1 /* 打印串口连接的串口 */ #define SERIAL_BUF_SIZE USART_BUF_SIZE /* 打印串口一次收发数据长度 */ #define SERIAL_USART_INIT(x) Usart1_Init(x) /* 打印串口连接串口初始化 */ #define Serial_Printf(...) UsartPrintf(SERIAL_USART, __VA_ARGS__) /* 打印串口发送数据 */ void Serial_Init(uint8_t **buf); /* 打印串口初始化 */ FlagStatus Serial_Rec_Flag(void); /* 串口接收到数据标志位 */ #endif
Serial.c
#include "Serial.h" static FlagStatus Serial_Flag = RESET; /* 接收到数据标志位 */ static uint8_t Serial_Buf[SERIAL_BUF_SIZE]; /* 接收到的数据数组 */ //========================================================== // 函数名称: Serial_Init // 函数功能: 打印串口初始化 // 入口参数: buf:存储获取数据的指针地址 // 返回参数: 无 // 说明: //========================================================== void Serial_Init(uint8_t **buf) { SERIAL_USART_INIT(9600); *buf = Serial_Buf; } //========================================================== // 函数名称: Serial_Rec_Flag // 函数功能: Serial接收到数据标志位 // 入口参数: 无 // 返回参数: SET:接收完成 RESET:未完成接收 // 说明: //========================================================== FlagStatus Serial_Rec_Flag(void) { if (Serial_Flag == SET) { Serial_Flag = RESET; return SET; } return RESET; } //========================================================== // 函数名称: USART1_IRQHandler_Callback // 函数功能: 串口1中断回调函数 // 入口参数: data:获取数据 idle:空闲,接收完成 // 返回参数: 无 // 说明: //========================================================== void USART1_IRQHandler_Callback(uint8_t data, FlagStatus idle) { static uint8_t RxState = 0; /* 状态变量 */ static uint8_t RxData_length = 0; /* 接收数据数量 */ if (idle == SET) { RxState = 0; /* 状态置0 */ Serial_Buf[RxData_length] = '\0'; /* 结尾 */ Serial_Flag = SET; /* 接收完成 */ } else if (RxState == 0) /* 未接收 */ { RxState = 1; /* 状态置1 */ RxData_length = 0; /* 接收数据数量清零 */ Serial_Buf[0] = data; /* 获取接收数据 */ RxData_length++; /* 接收数据数量加1 */ } else if (RxState == 1) /* 接收中 */ { Serial_Buf[RxData_length] = data; /* 获取接收数据 */ if (RxData_length
ESP01S
ESP01S通过WiFi连接巴法云
根据巴法云接入文档提示,可根据主题后三位判断主题类型,有主题类型的设备可以在巴法云手机app上直接查看和控制设备,如果不需要巴法云手机app可不需要加后三位数字
ESP01S.h
#ifndef _ESP01S_H #define _ESP01S_H #include #include "Usart.h" #include "Serial.h" #include "Delay.h" #define ESP01S_USART USART2 /* ESP01S连接的串口 */ #define ESP01S_BUF_SIZE USART_BUF_SIZE /* ESP01S一次收发数据长度 */ #define ESP01S_USART_INIT(x) Usart2_Init(x) /* ESP01S连接串口初始化 */ #define ESP01S_Printf(...) UsartPrintf(ESP01S_USART, __VA_ARGS__) /* ESP01S发送数据 */ #define ESP01S_MQTT_INFO "AT+CIPSTART=\"TCP\",\"bemfa.com\",8344\r\n" /* 连接巴法云的AT指令 */ #define MQTT_PING_CMD "cmd=0&msg=ping\r\n" /* 心跳命令 */ #define MQTT_PING_REC "cmd=0&res=1" /* 心跳返回信息 */ #define MQTT_PING_TIME_MAX 30 /* MQTT心跳最长时间(秒) */ extern char ESP01S_MQTT_TOPIC_LED[]; /* 连接巴法云的主题LED */ typedef enum { MQTT_Cmd_Add = 1, /* 添加订阅 */ MQTT_Cmd_Send = 2, /* 发布 */ MQTT_Cmd_AddAndRec = 3, /* 订阅并获取一次历史信息 */ MQTT_Cmd_RecTime = 7, /* 获取时间 */ MQTT_Cmd_RecSend = 9, /* 获取一次已发消息 */ } _MQTT_Cmd; /* MQTT命令 */ void ESP01S_Init(uint8_t **buf); /* 初始化ESP01S */ FlagStatus ESP01S_Rec_Flag(void); /* ESP01S接收到数据标志位 */ void ESP01S_ALL(void); /* ESP01S循环执行部分 */ void ESP01S_Loop_1s(void); /* ESP01S定时执行部分 */ void MQTT_Set_LED(FunctionalState state, uint8_t num); /* LED控制 */ void MQTT_Send_humi_temp(uint8_t humi, uint8_t humi_dec, uint8_t temp, uint8_t temp_dec); /* 发送温湿度 */ void ESP01S_On_Line_Feedback(void); /* ESP01S在线反馈 */ void ESP01S_Send_String(uint8_t *string); /* 发送数据到ESP01S */ #endif
ESP01S.c
#include "ESP01S.h" static char ESP01S_MQTT_UID[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; /* 连接巴法云的秘钥 */ char ESP01S_MQTT_TOPIC_LED[] = "led002"; /* 连接巴法云的主题LED */ char ESP01S_MQTT_TOPIC_HUMI[] = "humi004"; /* 连接巴法云的主题湿度 */ char ESP01S_MQTT_TOPIC_TEMP[] = "temp004"; /* 连接巴法云的主题温度 */ static char ESP01S_WIFI_SSID[] = "xxxxxxx"; /* 连接wifi的名称 */ static char ESP01S_WIFI_PASSWORD[] = "xxxxxxxx"; /* 连接wifi的密码 */ static uint8_t ESP01S_buf[ESP01S_BUF_SIZE]; /* 接收ESP-01s的返回数据数组 */ static FlagStatus ESP01S_buf_continue = RESET; /* 是否允许接收多组数据 */ static FlagStatus Recive_end_Flag = RESET; /* ESP01S数据接收完成标志位 */ static FlagStatus Recive_Busy = RESET; /* ESP01S数据接收中标志位 */ static FlagStatus MQTT_On_Line_Flag = RESET; /* MQTT在线标志位 */ static FlagStatus MQTT_Ping_Flag = RESET; /* MQTT发送心跳标志位 */ static uint8_t MQTT_Ping_Time_s = 0; /* MQTT心跳时间(s) */ static uint16_t RxData_length = 0; /* 接收数据长度 */ //========================================================== // 函数名称: ESP01S_Recive_Clean // 函数功能: 接收信息清除 // 入口参数: 无 // 返回参数: 无 // 说明: //========================================================== static void ESP01S_Recive_Clean(void) { RxData_length = 0; /* 接收数据数量清零 */ ESP01S_buf[0] = '\0'; /* 清除接收数据 */ Recive_Busy = RESET; /* 清除数据接收中标志位 */ Recive_end_Flag = RESET; /* 清除ESP01S接收数据标志位 */ } //========================================================== // 函数名称: ESP01S_SendCmd_Printf // 函数功能: 发送命令 // 入口参数: cmd:命令 // fmt:输入信息 // 返回参数: SET-成功 RESET-失败 // 说明: //========================================================== static FlagStatus ESP01S_SendCmd_Printf(char *res, char *fmt, ...) { char String[ESP01S_BUF_SIZE]; /* 接收输入变量数组,如果数组不够大,可以修改一下 */ uint8_t times = 20; /* 检查返回数据次数 */ va_list arg; va_start(arg, fmt); vsprintf(String, fmt, arg); ESP01S_buf_continue = SET; /* 允许接收多组数据 */ do { while (Recive_Busy == SET) /* 等待串口空闲 */ { Delay_ms(1); } ESP01S_Recive_Clean(); /* 接收信息清零 */ ESP01S_Printf(String); /* 发送命令 */ Delay_ms(5); } while ((strstr((const char *)ESP01S_buf, "busy s...") != NULL) || (strstr((const char *)ESP01S_buf, "busy p...") != NULL)); /* 输入正常 */ while (times--) { while (Recive_Busy == SET) /* 等待接收完成 */ { Delay_ms(1); } if (strstr((const char *)ESP01S_buf, res) != NULL) /* 如果检索到关键词 */ { ESP01S_buf_continue = RESET; /* 禁止接收多组数据 */ Recive_end_Flag = RESET; /* 清除ESP01S接收数据标志位 */ return SET; } Delay_ms(10); } Recive_end_Flag = RESET; /* 清除ESP01S接收数据标志位 */ ESP01S_buf_continue = RESET; /* 禁止接收多组数据 */ return RESET; } //========================================================== // 函数名称: ESP01S_EXIT_CIPMODE // 函数功能: ESP01S退出穿透模式 // 入口参数: 无 // 返回参数: 无 // 说明: //========================================================== static void ESP01S_EXIT_CIPMODE(void) { if (ESP01S_SendCmd_Printf("OK", "AT\r\n") == SET) return; Serial_Printf("退出透传模式\r\n"); Delay_ms(40); while (Recive_Busy == SET) ; /* 等待串口空闲 */ ESP01S_Printf("+++"); /* 退出透传发送 */ Delay_ms(40); ESP01S_SendCmd_Printf("OK", "AT+CIPMODE=0\r\n"); /* 退出透传模式 */ ESP01S_SendCmd_Printf("OK", "AT+CIPCLOSE\r\n"); /* 断开连接 */ } //========================================================== // 函数名称: ESP01S_Status // 函数功能: ESP01S状态 // 入口参数: 无 // 返回参数: 状态 // 说明: 0: ESP station 为未初始化状态 // 1: ESP station 为已初始化状态,但还未开始 Wi-Fi 连接 // 2: ESP station 已连接 AP,获得 IP 地址 // 3: ESP station 已建立 TCP、UDP 或 SSL 传输 // 4: ESP 设备所有的 TCP、UDP 和 SSL 均断开 // 5: ESP station 开始过 Wi-Fi 连接,但尚未连接上 AP 或从 AP 断开 //========================================================== static uint8_t ESP01S_Status(void) { uint8_t status = 0; ESP01S_EXIT_CIPMODE(); /* 退出透传模式 */ if (ESP01S_SendCmd_Printf("OK", "AT+CIPSTATUS\r\n") == SET) /* 查询连接状态和信息 */ { status = atoi(strstr((char *)ESP01S_buf, "STATUS:") + strlen("STATUS:")); /* 获取STATUS:后一位数字 */ Serial_Printf("ESP01S连接模式为:%d\r\n", status); /* 串口打印 */ } return status; } //========================================================== // 函数名称: MQTT_SendCmd // 函数功能: MQTT发送命令 // 入口参数: cmd:命令 // topic:主题 // 返回参数: 无 // 说明: //========================================================== static void MQTT_SendCmd(_MQTT_Cmd cmd, char *topic) { ESP01S_SendCmd_Printf("cmd", "cmd=%d&uid=%s&topic=%s\r\n", cmd, ESP01S_MQTT_UID, topic); } //========================================================== // 函数名称: WIFI_Connect // 函数功能: WIFI设置 // 入口参数: ssid:WIFI名称 // pwd:WIFI密码 // 返回参数: 是否连接成功 // 说明: //========================================================== static FlagStatus WIFI_Connect(char *ssid, char *pwd) { Serial_Printf("\r\nWIFI连接\r\n"); /* 串口打印 */ if (ESP01S_SendCmd_Printf("OK", "AT+CWMODE=1\r\n") == SET) /* 1 station模式 2 AP路由器模式 3 station+AP混合模式 */ return ESP01S_SendCmd_Printf("CONNECTED", "AT+CWJAP=\"%s\",\"%s\"\r\n", ssid, pwd); /* 连接WIFI */ return RESET; } //========================================================== // 函数名称: MQTT_Connect // 函数功能: 连接MQTT // 入口参数: 是否连接成功 // 返回参数: 无 // 说明: //========================================================== static FlagStatus MQTT_Connect(void) { Serial_Printf("MQTT连接\r\n"); /* 串口打印 */ if (ESP01S_SendCmd_Printf("OK", "AT+CIPMODE=1\r\n") == SET) /* 设置为透传模式 */ { if (ESP01S_SendCmd_Printf("OK", ESP01S_MQTT_INFO) == SET) /* 连接到MQTT服务器 */ { if ((ESP01S_SendCmd_Printf(">", "AT+CIPSEND\r\n")) == SET) /* 进入透传模式,下面发的都会无条件传输 */ { Delay_ms(200); MQTT_SendCmd(MQTT_Cmd_Add, ESP01S_MQTT_TOPIC_LED); /* 订阅主题 */ MQTT_SendCmd(MQTT_Cmd_Add, ESP01S_MQTT_TOPIC_HUMI); /* 订阅主题 */ MQTT_SendCmd(MQTT_Cmd_Add, ESP01S_MQTT_TOPIC_TEMP); /* 订阅主题 */ MQTT_On_Line_Flag = ESP01S_SendCmd_Printf(MQTT_PING_REC, MQTT_PING_CMD); /* 发送MATT心跳,判断是否连接 */ if (MQTT_On_Line_Flag == SET) Serial_Printf("MQTT订阅成功\r\n"); /* 串口打印 */ return MQTT_On_Line_Flag; } } } return RESET; } //========================================================== // 函数名称: ESP01S_Init // 函数功能: 初始化ESP01S // 入口参数: buf:存储获取数据的指针地址 // 返回参数: 无 // 说明: //========================================================== void ESP01S_Init(uint8_t **buf) { uint8_t status; /* ESP01S连接状态 */ ESP01S_USART_INIT(115200); /* ESP01S连接串口初始化 */ *buf = ESP01S_buf; /* 传递参数 */ Serial_Printf("\r\nESP01S初始化\r\n"); /* 串口打印 */ Delay_ms(10); MQTT_On_Line_Flag = ESP01S_SendCmd_Printf(MQTT_PING_REC, MQTT_PING_CMD); /* 心跳连接,cpu重启,ESP01S保持上电 */ if (MQTT_On_Line_Flag == SET) { MQTT_SendCmd(MQTT_Cmd_Add, ESP01S_MQTT_TOPIC_LED); /* 订阅主题 */ MQTT_SendCmd(MQTT_Cmd_Add, ESP01S_MQTT_TOPIC_HUMI); /* 订阅主题 */ MQTT_SendCmd(MQTT_Cmd_Add, ESP01S_MQTT_TOPIC_TEMP); /* 订阅主题 */ Serial_Printf("\r\nMQTT在线\r\n"); /* 串口打印 */ return; } status = ESP01S_Status(); /* 获取ESP01S连接状态 */ if (status == 1 || status == 5) /* 未连接或连接后断开 */ { WIFI_Connect(ESP01S_WIFI_SSID, ESP01S_WIFI_PASSWORD); /* 连接FIWI */ MQTT_Connect(); /* 连接MQTT */ } else MQTT_Connect(); /* 连接MQTT */ } //========================================================== // 函数名称: ESP01S_On_Line_Feedback // 函数功能: ESP01S在线反馈 // 入口参数: 无 // 返回参数: 无 // 说明:100ms执行一次 //========================================================== void ESP01S_On_Line_Feedback(void) { MQTT_Ping_Time_s = 0; /* 心跳时间清理 */ MQTT_On_Line_Flag = SET; /* MQTT在线 */ } //========================================================== // 函数名称: ESP01S_ALL // 函数功能: ESP01S循环执行部分 // 入口参数: 无 // 返回参数: 无 // 说明: //========================================================== void ESP01S_ALL(void) { uint8_t status; /* ESP01S连接状态 */ if (MQTT_Ping_Flag == SET) /* MQTT发送心跳标志位 */ { MQTT_On_Line_Flag = ESP01S_SendCmd_Printf(MQTT_PING_REC, MQTT_PING_CMD); /* 发送MATT心跳,判断是否连接 */ if (MQTT_On_Line_Flag == RESET) { Serial_Printf("MQTT离线\r\n"); /* 串口打印 */ } MQTT_Ping_Flag = RESET; /* 清除标志位 */ } if (MQTT_On_Line_Flag == RESET) /* MQTT不在线 */ { status = ESP01S_Status(); /* 获取ESP01S连接状态 */ if (status == 0 || status == 1 || status == 5) /* 未连接或连接后断开 */ { WIFI_Connect(ESP01S_WIFI_SSID, ESP01S_WIFI_PASSWORD); /* 连接FIWI */ MQTT_Connect(); /* 连接MQTT */ } else MQTT_Connect(); /* 连接MQTT */ } } //========================================================== // 函数名称: ESP01S_Loop_1s // 函数功能: ESP01S定时执行部分 // 入口参数: 无 // 返回参数: 无 // 说明:1s执行一次 //========================================================== void ESP01S_Loop_1s(void) { MQTT_Ping_Time_s++; if (MQTT_Ping_Time_s >= MQTT_PING_TIME_MAX) /* 心跳 */ { MQTT_Ping_Flag = SET; /* MQTT心跳 */ MQTT_Ping_Time_s = 0; } } //========================================================== // 函数名称: USART2_IRQHandler_Callback // 函数功能: 串口2中断回调函数 // 入口参数: data:获取数据 idle:空闲,接收完成 // 返回参数: 无 // 说明: //========================================================== void USART2_IRQHandler_Callback(uint8_t data, FlagStatus idle) { Recive_Busy = SET; /* 数据接收中标志位 */ static uint8_t RxState = 0; /* 接收状态 */ if (idle == SET) /* 接收完成 */ { RxState = 0; /* 状态置0 */ Recive_end_Flag = SET; /* 接收完成 */ Recive_Busy = RESET; /* 清除数据接收中标志位 */ if (ESP01S_buf_continue == RESET) /* 禁止接收多组数据状态下,接收完成后加'\0'结尾 */ ESP01S_buf[RxData_length] = '\0'; /* 结尾 */ } else if (RxState == 0) /* 未接收 */ { Recive_end_Flag = RESET; /* 未接收 */ RxState = 1; /* 状态置1 */ if (ESP01S_buf_continue == RESET) /* 禁止接收多组数据状态下,接收第一个data时,RxData_length置0 */ RxData_length = 0; /* 接收数据数量清零 */ ESP01S_buf[RxData_length] = data; /* 获取接收数据 */ if (RxData_length
上文中xxxxx的部分替换成自己的数据
ESP01S_Send_String函数可用于前期对ESP01S进行测试,也可直接使用ESP01S直接转接电脑的方式进行测试,但是需要多接几次线,嫌麻烦没试,该函数还可用于后期功能拓展(如:更换wifi、更换巴法云秘钥或主题,连接上位机进行控制显示等)
定时器
为了保障连接稳定,需要定时发送心跳信号,所以还需要一个定时器
Timer.h
#ifndef __TIMER_H #define __TIMER_H #include "stm32f10x.h" void Timer2_Init(void); /* 定时器2初始化 */ void TIM2_IRQHandler_Loop(void); /* 定时器2中断回调函数,中断间隔1ms */ #endif
Timer.c
#include "Timer.h" //========================================================== // 函数名称: Timer2_Init // 函数功能: 初始化定时器2 // 入口参数: 无 // 返回参数: 无 // 说明: 设定为1ms中断1次 //========================================================== void Timer2_Init(void) { // 开启时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 选择时基单元的时钟 TIM_InternalClockConfig(TIM2); // 配置时基单元 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStruct.TIM_Period = 1000 - 1; TIM_TimeBaseInitStruct.TIM_Prescaler = SystemCoreClock / 1000 / 1000 - 1; TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct); // 清除TIM2的挂起标志 TIM_ClearFlag(TIM2, TIM_FLAG_Update); // 使能中断 TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // 配置NVIC // 优先级分组 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // NVIC初始化 NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStruct); // 启动定时器 TIM_Cmd(TIM2, ENABLE); } //========================================================== // 函数名称: TIM2_IRQHandler // 函数功能: 定时器2中断函数,中断间隔1ms // 入口参数: 无 // 返回参数: 无 // 说明: //========================================================== void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) /* 判断中断标志位 */ { TIM2_IRQHandler_Loop(); /* 中断回调函数,中断间隔1ms */ TIM_ClearITPendingBit(TIM2, TIM_IT_Update); /* 清除标志位 */ } }
DHT11温湿度传感器
DHT11网上资料很多,就不解释了
DHT11.h
#ifndef __DHT11_H #define __DHT11_H #include "stm32f10x.h" #include "Delay.h" #define DHT11_DATA_IN GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) /* 获取STH11数据引脚状态 */ #define DHT11_DATA_OUT_H GPIO_SetBits(GPIOB, GPIO_Pin_14) /* 置STH11数据引脚为高电平 */ #define DHT11_DATA_OUT_L GPIO_ResetBits(GPIOB, GPIO_Pin_14) /* 置STH11数据引脚为低电平 */ void DHT11_Init(void); /* DHT11初始化 */ uint8_t DHT11_Read(uint8_t *data); /* 获取DHT11数据 */ #endif
DHT11.c
#include "DHT11.h" /********************************************************* 函数名称:DHT11_Init 函数功能:初始化DHT11 入口参数:无 返回结果:无 函数说明: **********************************************************/ void DHT11_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); /* 开启GPIOB外设时钟 */ } /********************************************************* 函数名称:DHT11_GPIO_OUT 函数功能:初始化数据引脚为输出 入口参数:无 返回结果:无 函数说明: **********************************************************/ static void DHT11_GPIO_OUT(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); } /********************************************************* 函数名称:DHT11_GPIO_IN 函数功能:初始化数据引脚为输入 入口参数:无 返回结果:无 函数说明: **********************************************************/ static void DHT11_GPIO_IN(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOB, &GPIO_InitStructure); } /********************************************************* 函数名称:DHT11_Start 函数功能:开启 入口参数:无 返回结果:无 函数说明: **********************************************************/ static void DHT11_Start(void) { DHT11_GPIO_OUT(); /* 输出模式 */ DHT11_DATA_OUT_H; /* 拉高 */ Delay_us(2); /* 2us */ DHT11_DATA_OUT_L; /* 拉低 */ Delay_ms(20); /* 至少18ms */ DHT11_DATA_OUT_H; /* 拉高 */ Delay_us(30); /* 20-40us */ DHT11_GPIO_IN(); /* 输入模式 */ } /********************************************************* 函数名称:DHT11_Ask 函数功能:应答 入口参数:无 返回结果:1:成功 0:失败 函数说明:开始信号结束,DHT11发送80us低电平响应信号,发送响应信号后,再把总线拉高80us **********************************************************/ static uint8_t DHT11_Ask(void) { uint8_t retry = 0; if (DHT11_DATA_IN == 0) { while (DHT11_DATA_IN == 0 && retry = 100) //超过100us退出,以免卡死 return 0; } retry = 0; while (DHT11_DATA_IN == 1 && retry = 100) //超过100us退出,以免卡死 return 0; } } return 1; } /********************************************************* 函数名称:DHT11_Read_Byte 函数功能:读一个字节 入口参数:无 返回结果:获取的字节 函数说明: **********************************************************/ static uint8_t DHT11_Read_Byte(void) { uint8_t i, retry; uint8_t data = 0; for (i = 0; i