串口1仅作为调试输出串口,设置波特率为9600,并不设置中断 。
#include "esp8266_at.h"
步骤与2.1相同,就不多赘述
以下函数皆在main.c添加
HAL_UART_Receive_IT(&huart3,usart3_rxone,1);
ES8266_MQTT_Init();
//MQTT初始化函数
void ES8266_MQTT_Init(void)
{
uint8_t status=0;
//初始化
if(ESP8266_Init())
{
status++;
printf("ESP8266初始化成功!status=%d\n",status);
}
else Enter_ErrorMode(0);
//连接热点
if(status==1)
{
if(ESP8266_ConnectAP(WIFI_NAME,WIFI_PASSWD))
{
status++;printf("ESP8266连接热点成功!status=%d\n",status);
}
else Enter_ErrorMode(1);
}
//阿里云MQTT配置
if(status==2)
{
if(MQTT_PeiZhi(MQTT_CLIENTID, MQTT_USARNAME, MQTT_PASSWD) != 0)
{
status++;printf("ESP8266阿里云MQTT配置成功!status=%d\n",status );
}
else Enter_ErrorMode(2);
}
//登陆MQTT
if(status==3)
{
if(ESP8266_ConnectServer(MQTT_BROKERADDRESS,1883)!=0)
{
status++;printf("ESP8266登录阿里云MQTT服务器成功!status=%d \n",status );
}
else Enter_ErrorMode(3);
}
//订阅主题
if(status==4)
{
if(MQTT_SubscribeTopic(MQTT_SUBSCRIBE_TOPIC) != 0)
{
printf("ESP8266阿里云MQTT订阅主题成功!\r\n");
}
else Enter_ErrorMode(4);
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART3) // 判断是由哪个串口触发的中断
{
//将接收到的数据放入接收usart3接收数组
usart3_rxbuf[usart3_rxcounter] = usart3_rxone[0];
usart3_rxcounter++; //接收数量+1
//重新使能串口3接收中断
HAL_UART_Receive_IT(&huart3,usart3_rxone,1);
}
}
//进入错误模式等待手动重启
void Enter_ErrorMode(uint8_t mode)
{
while(1)
{
switch(mode){
case 0:printf("ESP8266初始化失败!\r\n");break;
case 1:printf("ESP8266连接热点失败!\r\n");break;
case 2:printf("ESP8266阿里云MQTT配置服务器失败!\r\n");break;
case 3:printf("ESP8266阿里云MQTT登陆失败!\r\n");break;
case 4:printf("ESP8266阿里云MQTT订阅主题失败!\r\n");break;
default:printf("Nothing\r\n");break;
}
printf("请重启开发板");
HAL_Delay(200);
}
}
//单片机状态上报
void STM32DHT11_StatusReport(void)
{
//获取温湿度信息
uint8_t temperature;
uint8_t humidity;
char StrBuf[64]= {
0};
if( Read_DHT11(&DHT11_Data)==0) //“\”表示转向一下行
{
printf("****读取DHT11成功!****\r\n湿度为%d.%d %RH ,温度为 %d.%d℃ \r\n",\
DHT11_Data.humi_int,DHT11_Data.humi_deci,DHT11_Data.temp_int,DHT11_Data.temp_deci);
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
temperature = (int8_t)DHT11_Data.temp_int; //温度,单位:℃
humidity = (int8_t)DHT11_Data.humi_int; //湿度,单位:%
memset(StrBuf, '\0', 64);
sprintf(StrBuf, " %d Degree",temperature);
OLED_ShowString(0,4,(uint8_t *)StrBuf);//OLED显示当前温度
memset(StrBuf, '\0', 64);
sprintf(StrBuf, " %d %%",humidity);
OLED_ShowString(0,6,(uint8_t *)StrBuf);//OLED显示当前相对湿度
//jsion 格式
sprintf(mqtt_message,
"{\\\"method\\\":\\\"thing.event.property.post\\\"\\,\\\"params\\\":{\\\"CurrentTemperature\\\":%d\\,\\\"CurrentHumidity\\\":%d}}",
(int)temperature,
(int)humidity
);
MQTT_PublishData(MQTT_PUBLISH_TOPIC,mqtt_message);
}
else
{
printf("Read DHT11 ERROR!\r\n");//采集温湿度数据
HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin);
}
}
下载程序,查看串口助手与阿里云物模型
本项目多次用到的几个函数
属于C标准库
描述:C 库函数 int sprintf(char *str, const char *format, …) 发送格式化输出到 str 所指向的字符串。
声明
int sprintf(char *str, const char *format, ...)
specifier(说明符) | 输出 |
---|---|
c | 字符 |
d 或 i | 有符号十进制整数 |
e | 使用 e 字符的科学科学记数法(尾数和指数) |
E | 使用 E 字符的科学科学记数法(尾数和指数) |
f | 十进制浮点数 |
g | 自动选择 %e 或 %f 中合适的表示法 |
G | 自动选择 %E 或 %f 中合适的表示法 |
o | 有符号八进制 |
s | 字符的字符串 |
u | 无符号十进制整数 |
x | 无符号十六进制整数 |
X | 无符号十六进制整数(大写字母) |
p | 指针地址 |
n | 无输出 |
% | 字符 |
flags(标识) | 描述 |
---|---|
- | 在给定的字段宽度内左对齐,默认是右对齐(参见 width 子说明符)。 |
+ | 强制在结果之前显示加号或减号(+ 或 -),即正数前面会显示 + 号。默认情况下,只有负数前面会显示一个 - 号。 |
(space) | 如果没有写入任何符号,则在该值前面插入一个空格。 |
# | 与 o、x 或 X 说明符一起使用时,非零值前面会分别显示 0、0x 或 0X。 与 e、E 和 f 一起使用时,会强制输出包含一个小数点,即使后边没有数字时也会显示小数点。默认情况下,如果后边没有数字时候,不会显示显示小数点。 与 g 或 G 一起使用时,结果与使用 e 或 E 时相同,但是尾部的零不会被移除。 |
0 | 在指定填充 padding 的数字左边放置零(0),而不是空格(参见 width 子说明符)。 |
width(宽度) | 描述 |
---|---|
(number) | 要输出的字符的最小数目。如果输出的值短于该数,结果会用空格填充。如果输出的值长于该数,结果不会被截断。 |
* | 宽度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。 |
.precision(精度) | 描述 |
---|---|
.number | 对于整数说明符(d、i、o、u、x、X):precision 指定了要写入的数字的最小位数。如果写入的值短于该数,结果会用前导零来填充。如果写入的值长于该数,结果不会被截断。精度为 0 意味着不写入任何字符。 对于 e、E 和 f 说明符:要在小数点后输出的小数位数。 对于 g 和 G 说明符:要输出的最大有效位数。 对于 s: 要输出的最大字符数。默认情况下,所有字符都会被输出,直到遇到末尾的空字符。 对于 c 类型:没有任何影响。 当未指定任何精度时,默认为 1。如果指定时不带有一个显式值,则假定为 0。 |
.* | 精度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。 |
length(长度) | 描述 |
---|---|
h | 参数被解释为短整型或无符号短整型(仅适用于整数说明符:i、d、o、u、x 和 X)。 |
l | 参数被解释为长整型或无符号长整型,适用于整数说明符(i、d、o、u、x 和 X)及说明符 c(表示一个宽字符)和 s(表示宽字符字符串)。 |
L | 参数被解释为长双精度型(仅适用于浮点数说明符:e、E、f、g 和 G)。 |
返回值:
如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。
实例:
在本项目中,多使用以下方法,将后面的字符串写入第一个参数
sprintf(name_pwd,"AT+MQTTUSERCFG=0,1,\"NULL\",\"%s\",\"%s\",0,0,\"\"\r\n",Username,Password);
//将后面的字符串写入到name_pwd
**描述:**查找字符串中是否包含另一个字符串
声明:uint8_t FindStr(char* dest,char* src,uint16_t retry_nms)
dest:是目标字符串
src:是原字符串
retry_nms:超时时间 ————>没用这个参数
定义:
uint8_t FindStr(char* dest,char* src,uint16_t retry_nms)
{
// retry_nms/=10; //超时时间
// while(strstr(dest,src)!=NULL )//等待串口接收完毕或超时退出
// {
HAL_Delay(100);
// }
if(strstr(dest,src)!=NULL) return 0;
else return 1;
}
在上述函数中使用了strstr()函数以下相关介绍
C 库函数 char *strstr(const char *haystack, const char *needle) 在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 ‘\0’。
声明
下面是 strstr() 函数的声明。
char *strstr(const char *haystack, const char *needle)
参数
返回值
该函数返回在 haystack 中第一次出现 needle 字符串的位置,如果未找到则返回 null。
实例
下面的实例演示了 strstr() 函数的用法。
实例
#include
#include
int main()
{
const char haystack[20] = "RUNOOB";
const char needle[10] = "NOOB";
char *ret;
ret = strstr(haystack, needle);
printf("子字符串是: %s\n", ret);
return(0);
}
让我们编译并运行上面的程序,这将产生以下结果:
子字符串是: NOOB
描述:向ESP8266发送字符串
声明:
void ESP8266_ATSendString(char* str);
参数:
str:发送的字符串
定义:
void ESP8266_ATSendString(char* str)
{
memset(usart3_rxbuf,0, 256);
//每次发送前将接收串口接收总数置0,为了接收
usart3_rxcounter = 0;
//发送方法1
// while(*str) USART1_SendOneByte(*str++);
//发送法法2
HAL_UART_Transmit(&huart3,(uint8_t *)str,strlen(str),0xFFFF);
}
### 4.3ESP8266_ATSendString()函数
**描述**:向ESP8266发送字符串
**声明:**
```c
void ESP8266_ATSendString(char* str);
参数:
str:发送的字符串
定义:
void ESP8266_ATSendString(char* str)
{
memset(usart3_rxbuf,0, 256);
//每次发送前将接收串口接收总数置0,为了接收
usart3_rxcounter = 0;
//发送方法1
// while(*str) USART1_SendOneByte(*str++);
//发送法法2
HAL_UART_Transmit(&huart3,(uint8_t *)str,strlen(str),0xFFFF);
}
完整的项目我放在我的百度网盘了