单片机通过串口usart向esp8266发送AT指令,上报信息。
其他设备上报的信息通过云,传送到单片机端的esp8266。
单片机通过串口usart接收esp8266所得到的云端信息。
【对于穿透的理解】
顾名思义,开启穿透就是不用管wifi协议怎么实现的~
我们只用专注于在A设备和B设备间使用串口收发数据,
就好像A和B直接用导线相连~ 就好像穿透了~
+++可推出穿透模式
【ESP8266的一般使用顺序】
这里的“一般”指的是:ESP8266连接当前环境的热点,与服务器建立TCP连接,传输数据。
AT+CWMODE=1:设置工作模式(STA模式)
AT+RST:模块重启(生效工作模式)
AT+CWJAP=“111”,“11111111”:连接当前环境的WIFI热点(热点名,密码)
AT+CIPMUX=0:设置单路连接模式
AT+CIPSTART=“TCP”,“xxx.xxx.xxx.xxx”,xxxx:建立TCP连接
AT+CIPMODE=1:开启透传模式
AT+CIPSEND:透传模式下,传输数据
+++:退出透传模式
普通的socket连接对服务器的消耗太大,所以出现了类似MQTT这种轻量级、低消耗的协议来维护长连接。维护长连接需要采用心跳机制…
这篇博客写的比较简练——感谢博主.
我之前博客的连接.
tips:点灯的产品流转规则~没必要用json格式,二进制就行。
所谓的产品流转规则就是数据的流转规则,而数据又依托存放在topic中。
故:产品流转规则就是设计A设备使用的topic数据传送到B设备使用的topic.
我之前的android studio 开发app博客专题合集——mqtt.jar包.
这个库有12个函数,对at指令做了封装,直接调用相应函数(不用死记at指令)
4.3.3 自定义函数
USART1接收中断代码
/****** USART1接收中断代码 *****/
// ES8266驱动串口接收中断处理函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1) // 判断是由哪个串口触发的中断
{
//将接收到的数据放入接收usart1接收数组
usart1_rxbuf[usart1_rxcounter] = usart1_rxone[0];
usart1_rxcounter++; //接收数量+1
//重新使能串口1接收中断
/**【易错~~接受回调函数中别忘再次使能】*/
HAL_UART_Receive_IT(&huart1,usart1_rxone,1);
}
}
进入错误模式代码
/************ 进入错误模式代码 ************/
//进入错误模式等待手动重启
void Enter_ErrorMode(uint8_t mode)
{
HAL_GPIO_WritePin(LED_G_GPIO_Port,LED_G_Pin,GPIO_PIN_SET);
while(1)
{
switch(mode){
case 0:user_main_error("ESP8266初始化失败!\r\n");break;
case 1:user_main_error("ESP8266连接热点失败!\r\n");break;
case 2:user_main_error("ESP8266连接阿里云服务器失败!\r\n");break;
case 3:user_main_error("ESP8266阿里云MQTT登陆失败!\r\n");break;
case 4:user_main_error("ESP8266阿里云MQTT订阅主题失败!\r\n");break;
default:user_main_info("Nothing\r\n");break;
}
user_main_info("请重启开发板");
//HAL_GPIO_TogglePin(LED_R_GPIO_Port,LED_R_Pin);
HAL_Delay(200);
}
}
初始化函数
/************* STM32 MQTT业务代码 **********/
//MQTT初始化函数
void ES8266_MQTT_Init(void)
{
uint8_t status=0;
//初始化|检查esp8266好坏
if(ESP8266_Init())
{
user_main_info("ESP8266初始化成功!\r\n");
status++;
}
else Enter_ErrorMode(0);
//连接手机热点|家庭wifi
if(status==1)
{
if(ESP8266_ConnectAP(WIFI_NAME,WIFI_PASSWD))
{
user_main_info("ESP8266连接热点成功!\r\n");
status++;
}
else Enter_ErrorMode(1);
}
//连接阿里云IOT服务器
if(status==2)
{
if(ESP8266_ConnectServer("TCP",MQTT_BROKERADDRESS,1883)!=0)
{
user_main_info("ESP8266连接阿里云服务器成功!\r\n");
status++;
}
else Enter_ErrorMode(2);
}
//登陆MQTT
if(status==3)
{
if(MQTT_Connect(MQTT_CLIENTID, MQTT_USARNAME, MQTT_PASSWD) != 0)
{
user_main_info("ESP8266阿里云MQTT登陆成功!\r\n");
status++;
}
else Enter_ErrorMode(3);
}
//订阅主题
if(status==4)
{
if(MQTT_SubscribeTopic(MQTT_SUBSCRIBE_TOPIC,0,1) != 0)
{
user_main_info("ESP8266阿里云MQTT订阅主题成功!\r\n");
}
else Enter_ErrorMode(4);
}
}
单片机状态上报——————依据项目修改
/******* 单片机状态上报 *************/
//单片机状态上报
void STM32DHT11_StatusReport(void)
{
//获取温湿度信息
uint8_t temperature;
uint8_t humidity;
uint8_t get_times;
// 获取温湿度信息并用串口打印,获取十次,直到成功跳出
for(get_times=0;get_times<10;get_times++)
{
if(!dht11Read(&temperature, &humidity))//Read DHT11 Value
{
user_main_info("temperature=%d,humidity=%d \n",temperature,humidity);
break;
}
}
//上报一次数据
uint8_t led_r_status = HAL_GPIO_ReadPin(LED_R_GPIO_Port,LED_R_Pin) ? 0:1;
uint8_t led_g_status = HAL_GPIO_ReadPin(LED_G_GPIO_Port,LED_G_Pin) ? 0:1;
uint8_t led_b_status = HAL_GPIO_ReadPin(LED_B_GPIO_Port,LED_B_Pin) ? 0:1;
sprintf(mqtt_message,
"{\"method\":\"thing.service.property.set\",\"id\":\"181454577\",\"params\":{\
\"DHT11_Temperature\":%.1f,\
\"DHT11_Humidity\":%.1f,\
\"Switch_LEDR\":%d,\
\"Switch_LEDG\":%d,\
\"Switch_LEDB\":%d\
},\"version\":\"1.0.0\"}",
(float)temperature,
(float)humidity,
led_r_status,
led_g_status,
led_b_status
); //阿里云数据上报格式~
MQTT_PublishData(MQTT_PUBLISH_TOPIC,mqtt_message,0); //
}
字符串处理函数*2
/*********** 自定义函数~方便处理str *******/
char temp_str[30]; // 临时子串
/**从母串中获取与子串长度相等的临时子串*/
void ReadStrUnit(char * str,char *temp_str,int idx,int len) // 从母串中获取与子串长度相等的临时子串
{
int index;
for(index = 0; index < len; index++)
{
temp_str[index] = str[idx+index];
}
temp_str[index] = '\0';
}
/** 返回子串第一个字符在母串中的位置*/
/** 返回值大于>0 找到了
返回值小于<0 没找到
*/
int GetSubStrPos(char *str1,char *str2)// 返回子串第一个字符在母串中的位置
{
int idx = 0;
int len1 = strlen(str1);
int len2 = strlen(str2);
if( len1 < len2)
{
//printf("error 1 \n"); // 子串比母串长
return -1;
}
while(1)
{
ReadStrUnit(str1,temp_str,idx,len2); // 不断获取的从 母串的 idx 位置处更新临时子串
if(strcmp(str2,temp_str)==0)break; // 若临时子串和子串一致,结束循环
idx++; // 改变从母串中取临时子串的位置
if(idx>=len1)return -1; // 若 idx 已经超出母串长度,说明母串不包含该子串
}
return idx; // 返回子串第一个字符在母串中的位置
}
处理MQTT下发的消息 ————依据项目修改
data[i]-=‘0’ ASCII转化成数值
data[i]+=‘0’ 数值转化成ASCII
/**** 处理MQTT下发的消息 *********/
/**
data[i]-='0' ASCII转化成数值
data[i]+='0' 数值转化成ASCII
*/
//处理MQTT下发的消息
void deal_MQTT_message(uint8_t* buf,uint16_t len)
{
uint8_t data[512];
memset(usart1_rxbuf,0,sizeof(usart1_rxbuf)); //清空接收缓冲
usart1_rxcounter=0;
//查找关键字
int i = GetSubStrPos((char*)data,"LEDR");
if( i>0 )
{
uint8_t ledr_status = data[i+6]-'0'; //【ASCII转化成数值的常用方法】
if(ledr_status)
HAL_GPIO_WritePin(LED_R_GPIO_Port,LED_R_Pin,GPIO_PIN_RESET);
else
HAL_GPIO_WritePin(LED_R_GPIO_Port,LED_R_Pin,GPIO_PIN_SET);
}
}
如果想再加个串口2与电脑通信——重写fputc方便调试
#include "stdio.h"
int fputc(int ch,FILE *f)
{
uint8_t temp[1]={ch};
HAL_UART_Transmit(&huart2,temp,1,2);
return 0;
}