📕 ESP8266介绍
什么是ESP8266呢?这个是WiFi模块,是一个由安可信科技公司开发出来的模块,这个模块的核心处理器ESP8266在比较小的尺寸封装中集成了业界领先的微型的MCU,它带有了16位精简的模式,主要的频率支持80MHz和160MHz,支持RTOS,集成WiFi,板载天线。这个模块是支持标准的IEE802.11b/g/n协议,完整的TCP/IP协议栈,用户可以使用该模块为县城的设备添加联网模块,也可以构建独立的网络控制器,这个模块还是一个高性能的无羡SOC,以最低成本提供最大的实用性,为WiFi功能嵌入其他系统提供了无限的可能。
💬主要参数
我们可以根据官方给到的数据,在这里列出所有的参数,我们可以看到ESP8266支持的网络标准广泛,几乎现代的WiFi都支持了。
懒得看理论,我们直接上实操就好了,我们做一个ESP8266接入我们的阿里云,然后新建一个手机WiFi控制的温湿度加上我们的光照检测。
📕 ESP8266接入阿里云
📝创建阿里云产品
首先,我们可以到阿里云官网进行注册登录,申请使用一个账号,阿里云的地址是,
进入我们的生活物联部分,下面的演示图:
进入到我们的生活物联网平台(飞燕平台),点击我们的“管理控制台” ,到我们的下一个界面;
下一步,我们新建一个项目,命上我们的名字,命中这里最好用的是英文大写开头,不用那么复杂,因为后面还有一些模块啥的,你命名复杂后面难记,完成以后我选择自主品牌就好了,
进入到界面之后,我们选择“创建新产品”,“产品名称”我们可以用中文名字,分类这一项没太大打紧,你甚至什么都不会影响到后续的操作,“联网方式”我们选择的是蜂窝移动网络模式不用WiFi模式,我们可以使用手机开上热点连上我们的阿里云,
然后我们自定义添加三个功能,分别是温度、湿度、光照强度;
最后我们完整的功能列表就是如下图所示:
然后我们进入到下一步“人机交互”的步骤,分别进行设置一下的几个功能;但是在这个之前我们记得要把右上角的“使用公版app控制产品”这个选项要选上,然后再分别设置下面的各个功能;
然后下一个功能“设备面板” ,我们进行app面板的操作;
我们设置相应的三个功能的面板,具体的操作如下面所示;
完整的制作(三个功能的模块如下);弄完这三个功能后记得全部点击为保存,不然就不会生效的;
我们的“人机交互”的部分我们完成以后,我们就到下一个操作步骤“设备调试”,这个步骤我们需要设置调摄选择我们选择的芯片的模组的信息,这个模组没有太多的要求,我们随意的选择一款你喜欢的就可以了;
然后我们就可以选择“新增侧测试设备”就可以完成你这个模块的三元组的设备设置;但是这个时候还是没有激活的状态我们,还需要进行一些后续的操作才能将它激活在线;
我们点击下面的设备证书,就可以看到我们的设置完成后的设备的三元组的信息了,这个东西是要将它写到我们的代码当中;
然后我们使用手机热点来进行连接阿里云,运行的结果如下,这要出现这样的结果就代表这我们就已经连接上我们的阿里云了,
使用WiFi热点连接上我们的阿里云的代码设计这要是在我们的ESP8266.h进行宏定义,具体的代码码源如下:
#ifndef _ESP8266_H_ #define _ESP8266_H_ #include "stm32f4xx.h" #include "string.h" #include "stdio.h" #include "stdbool.h" #include <stdlib.h> #define SSID "lss" //wifi热点名称 #define PWD "12345679" //wifi热点密码 #define IP "203.107.45.14" //服务器IP或域名 //#define IP "a1prIyDGvtv.iot-as-mqtt.cn-shanghai.aliyuncs.com" //服务器IP或域名 #define PORT 1883 //连接端口号,MQTT默认1883 //阿里云三元组 #define DeviceName "qbt1" //设备名称 #define ProductKey "a1RTc48iOAJ" //产品密匙 #define DeviceSecret "83fbc94709e6fa696adf6e1851f76bd3" //设备密匙 //计算哈希算法用到 加密 #define Client "clientId123deviceName" #define productKey "productKey" #define Encryption (Client DeviceName productKey ProductKey) //AT指令的 #define AND "&" #define ClientId "123|securemode=3\\,signmethod=hmacsha1|" //客户端ID #define UserName (DeviceName AND ProductKey) //用户名 //订阅发布的主题 #define SYS "/sys/" #define LINK "/" #define TOP "/thing/event/property/" #define POST "post" #define ESET "set" #define PublishMessageTopPost (SYS ProductKey LINK DeviceName TOP POST) #define PublishMessageTopSet (SYS ProductKey LINK DeviceName TOP ESET) struct RGB { unsigned char R; unsigned char G; unsigned char B; }; typedef struct { struct RGB Rgb; //数组类型的值读取 char key[50]; //键名读取 char values[20];//读取到的值,类型字符串 short value; //普通值读取 }JSON; //上传数据结构体 typedef struct { char keyname[50]; //键读取 char value[20];//读取到的值,类型字符串 }JSON_PUBLISH; void ESP12_AP_Init(void); bool ESP12_Send_Cmd(char *cmd,char *ack,u16 waitms,u8 cnt); u8 ESP12_Send_TO_Client(u8 id,char * data); void ESP12_STA_Init(void); void JsonString_Parsing(char *str, JSON *json); void JsonString_Dispose(JSON *json); void Publish_MQTT_message(JSON_PUBLISH *data,u8 data_num); extern JSON json; extern JSON_PUBLISH publish_mqtt_message[4]; #endif
当你连上了阿里云之后就可以看到我们的设置的功能部分已经激活在线了,如下:
然后我们进行我们的下一步,联网以及app界面显示;
然后我们扫码进去我们看到一下这个界面就代表这我们已经连上去,已经完成了app这边的联网的功能配置,
到这里我们完成了ESP8266接入我们的阿里云并完成了创建了一个属于自己的阿里云的品牌,但是上面没有数据,所以我们要到代码上面去设置我们的数据,并把这一些数据发到我们的阿里云,阿里云发到我们手机app上面这个步骤。
📕 功能代码配置
SHT31温湿度检测
我们将温湿度检测放到一个模块上面去写,SHT31这个温湿度模块,博主我在往期的博客已经有写了,大家感兴趣的话可以到主义进行关键字的搜索就好了,这里就不进行重复的诉说了,我们直接上代码就好了:
#include "SHT31.h" #include "IIC.h" #include "uart1.h" #include "systick.h" /*通用开漏输出 PB6 PB7*/ void sht31_init(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB , ENABLE);//使能B口时钟 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_OType = GPIO_OType_OD; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_25MHz; GPIO_Init(GPIOB, &GPIO_InitStruct); IIC_SCL = 1; IIC_SDA = 1; } T_H TMP={0.0,0.0}; u8 date[6]={0}; void sht31_read_T_H(void) { int i=0; IIC_Start(); IIC_write_byte( (0x44<<1)|0 ); //写器件指令 0x44<<+0 if(IIC_Wait_ACK( )== 1 ) { printf("无应答,请检测总线是否挂接有从机或从机损坏\r\n"); return ; } IIC_write_byte(0x24); //设置时钟延伸性,1S采样的次数(0x240b不使能) if(IIC_Wait_ACK( )== 1 ) { printf("从机不响应\r\n"); return ; } IIC_write_byte(0x0b); if(IIC_Wait_ACK( )== 1 ) { printf("从机不响应\r\n"); return ; } VIP: IIC_Stop(); IIC_SCL = 1; IIC_Start(); IIC_write_byte( (0x44<<1)|1 ); //读器件指令 0x44<<+1 if(IIC_Wait_ACK( )== 1 ) //从机非应答 { i++; Delay_Ms(1); if(i>20) {printf("从机不鸟我\r\n"); return ;} goto VIP; } date[0]=IIC_read_byte(); IIC_ACK_NACK(0);//主机应答 date[1]=IIC_read_byte(); IIC_ACK_NACK(0);//主机应答 date[2]=IIC_read_byte(); IIC_ACK_NACK(0);//主机应答 date[3]=IIC_read_byte(); IIC_ACK_NACK(0);//主机应答 date[4]=IIC_read_byte(); IIC_ACK_NACK(0);//主机应答 date[5]=IIC_read_byte(); IIC_ACK_NACK(1);//主机应答 IIC_Stop(); if( crc8(date,2)==date[2] && crc8(date+3,2)==date[5] ) { TMP.T = (date[0]<<8|date[1])/65535.0*175-45; TMP.H = (date[3]<<8|date[4])/65535.0*100; } } unsigned char crc8(const unsigned char *data, int len) { const unsigned char POLYNOMIAL = 0x31; unsigned char crc = 0xFF; int j, i; for (j=0; j<len; j++) { crc ^= *data++; for ( i = 0; i <8; i++ ) { crc = ( crc & 0x80 ) ? (crc << 1) ^ POLYNOMIAL : (crc << 1); } } return crc; }
ADC光照强度检测
我们光照强度的采集,我们可以使用ADC采集通道进行光照强度的数据采集,这个光照强度的数据采集,我们还是已经写过了相关的文章,还是那句话,感兴趣的可以去主业进行相关博文的搜索,我们这里直接上代码:(因为有点长,ADC的配置什么的就不上传了,后面完成的工程大家感兴趣的可以私聊我,我会分享的!)
#include "adc.h" /********************************************************************************************************* * 函 数 名 : Adc_Init * 功能说明 : 初始化ADC1 * 形 参 : 无 * 返 回 值 : 无 * 备 注 : NTC_CH:PC0,IR_CH:PC1 *********************************************************************************************************/ void Adc_Init(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; ADC_CommonInitTypeDef ADC_CommonInitStructure = {0}; ADC_InitTypeDef ADC_InitStructure = {0}; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); //使能GPIOA时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能ADC1时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; //模拟输入 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //不带上下拉 GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化 RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1, ENABLE); //ADC1复位 RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1, DISABLE); //复位结束 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; //独立模式 ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;//两个采样阶段之间的延迟5个时钟 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //禁止DMA直接访问 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; //预分频4分频。ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36Mhz ADC_CommonInit(&ADC_CommonInitStructure); //初始化 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; //12位模式 ADC_InitStructure.ADC_ScanConvMode = DISABLE; //非扫描模式 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //禁止触发检测,使用软件触发 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //右对齐 ADC_InitStructure.ADC_NbrOfConversion = 2; //2个转换在规则序列中 也就是只转换规则序列1 ADC_Init(ADC1, &ADC_InitStructure); //ADC初始化 ADC_Cmd(ADC1, ENABLE); //开启AD转换器 } /********************************************************************************************************* * 函 数 名 : Get_AdcValue * 功能说明 : 获取ADC通道值 * 形 参 : ch:通道号 * 返 回 值 : 采集到的模拟量 * 备 注 : 无 *********************************************************************************************************/ unsigned short Get_AdcValue(unsigned char ch) { ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_480Cycles ); //ADC1,ADC通道,转换数量,480个周期,提高采样时间可以提高精确度 ADC_SoftwareStartConv(ADC1); //使能指定的ADC1的软件转换启动功能 while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); //等待转换结束 return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果 } /********************************************************************************************************* * 函 数 名 : Get_AverageValue * 功能说明 : 简单滤波算法,排序取中间求平均 * 形 参 : ch:通道号 * 返 回 值 : 处理后的数据 * 备 注 : 无 *********************************************************************************************************/ unsigned short Get_AverageValue(unsigned char ch) { unsigned char i = 0, j = 0; unsigned short tem[10] = {0}, n = 0; for(i=0; i<10; i++) tem[i] = Get_AdcValue(ch); for(i=0; i<10; i++) { for(j=9; j>i; j--) { if(tem[j] < tem[j-1]) { n = tem[j]; tem[j] = tem[j-1]; tem[j-1] = n; } } } return (tem[4] + tem[5]) / 2; }
ESP8266使用
前面已经有了esp8266的.h文件,我们这里写上我们的.c文件,这里写的是我们的热点的连接以及是否已经连接上我们的阿里云这么一个代码操作:
#include "esp8266.h" #include "usart2.h" #include "systick.h" #include "led.h" #include "hmacsha1.h" #include "adc.h" #include "SHT31.h" static unsigned char ConnectFlag = false; //true:已连接,false:未连接 static void CalculateSha1(unsigned char *password); static void mstrcat(char *s1, const char *s2); void ESP12_AP_Init(void) { ESP12_Send_Cmd("AT\r\n","OK",10,3);//测试指令AT ESP12_Send_Cmd("AT+CWMODE=2\r\n","OK",30,3); //配置WIFI AP模式 ESP12_Send_Cmd("AT+CWSAP=\"WWW888\",\"0123456789\",11,4\r\n","OK",30,3); //设置wifi账号与密码 ESP12_Send_Cmd("AT+RST\r\n","ready",800,3); //重启 ESP12_Send_Cmd("AT+CIPMUX=1\r\n","OK",50,3); //开启多个连接 ESP12_Send_Cmd("AT+CIPSERVER=1,5000\r\n","OK",50,3); //开启服务器设置端口号 } void ESP12_STA_Init(void) { char AT_CMD[150]={0}; u8 PassWord[50] = {0}; //存放的是哈希计算的密钥 RST: ESP12_Send_Cmd("AT\r\n","OK",100,3);//测试指令AT; //配置WIFI STA ESP12_Send_Cmd("AT+CWMODE=1\r\n","OK",300,3); //设置时区 NTSP服务器 用于调整客户端自身所在系统的时间,达到同步时间的目的 ESP12_Send_Cmd("AT+CIPSNTPCFG=1,8,\"ntp1.alliyun.com\"\r\n","OK",100,3); //连接wifi 账号&密码 sprintf(AT_CMD,"AT+CWJAP=\"%s\",\"%s\"\r\n",SSID,PWD); if(ESP12_Send_Cmd(AT_CMD,"OK",3000,3)==0) { printf("WIFI名称或密码有错,复位重启\r\n"); ESP12_Send_Cmd("AT+RST\r\n","ready",1000,1); //wifi连接不上,重启 goto RST; } memset(AT_CMD,0,sizeof(AT_CMD)); //清0数组,备用 CalculateSha1(PassWord); //计算哈希 // printf("haxi=%s\r\n",PassWord); sprintf(AT_CMD,"AT+MQTTUSERCFG=0,1,\"NULL\",\"%s\",\"%s\",0,0,\"\"\r\n", UserName, PassWord); ESP12_Send_Cmd(AT_CMD,"OK",2000,3); //设置连接客户端ID memset(AT_CMD,0,sizeof(AT_CMD)); //清0数组,备用 sprintf(AT_CMD,"AT+MQTTCLIENTID=0,\"%s\"\r\n",ClientId); ESP12_Send_Cmd(AT_CMD,"OK",1000,3); //连接到MQTT代理(阿里云平台) memset(AT_CMD,0,sizeof(AT_CMD)); sprintf(AT_CMD,"AT+MQTTCONN=0,\"%s\",1883,1\r\n",IP); if(ESP12_Send_Cmd(AT_CMD,"OK",1000,3)==0) { printf("连接aliyu失败,复位STM32重连\r\n"); ESP12_Send_Cmd("AT+RST\r\n","ready",1000,2); //wifi连接不上,重启 1000延时1S 2链接次数 __set_FAULTMASK(1); //STM32程序软件复位 NVIC_SystemReset(); } //订阅主题 memset(AT_CMD,0,sizeof(AT_CMD)); sprintf(AT_CMD, "AT+MQTTSUB=0,\"%s\",1\r\n", PublishMessageTopSet); ESP12_Send_Cmd(AT_CMD,"OK",1000,3); printf("连接aliyu成功\r\n"); Publish_MQTT_message(publish_mqtt_message,4); //发布主题 } //参数:1.指令,2.等待应答延时,3.重发次数。while 4.想要的应答 bool ESP12_Send_Cmd(char *cmd,char *ack,u16 waitms,u8 cnt) { SendUsart2Data((u8*)cmd);//1.发送AT指令 printf("%s\r\n",cmd); //串口1输出 while(cnt--) { delay_ms(waitms); //2.串口中断接收wifi应答 if(Usart2.RecFlag) { Usart2.RecFlag = 0; Usart2.FlagLen = 0; if(strstr((char*)Usart2.RxBuff,ack)!=NULL) { printf("ok\r\n"); return 1; } memset(Usart2.RxBuff,0,sizeof(Usart2.RxBuff)); } } Usart2.RecFlag = 0; Usart2.FlagLen = 0; return 0; //3.延时些许时间等待中断接收应答,判断应答 回复的应答是字符串 例如"ok" strcmp strstr /*if(strstr(Rx_buf,"ok")!=NULL) { //成功,得到想要的回复 } else { //失败,再发3-5次再重复判断。 //发送3-5次之后还是失败,应该复位一下模块 RST } */ } u8 ESP12_Send_TO_Client(u8 id,char * data) { u8 send_buf[20]={0}; sprintf((char*)send_buf,"AT+CIPSEND=%d,%d\r\n",id,strlen(data)); /* SendUsart2Data(send_buf); delay_ms(20); if(strstr((char*)Usart2.RxBuff,">")!=NULL) { SendUsart2Data(data); } */ if(ESP12_Send_Cmd((char*)send_buf,">",20,3)) { SendUsart2Data((u8*)data); return 1; } return 0; } /***************************韦工************************************/ //Data_TypeDef DATA; JSON json; //存放解析处理的键值对 /********************************************************************** *函数名:JsonString_Parsing *功 能:解析阿里云服务器下发的数据json格式 *参 数:str:指向串口2接收的阿里云下发数据 json:解析后数据保存的结构体 *返 回:无 *备 注:JsonString_Parsing(Usart2.RxBuff, &json); +MQTTSUBRECV:0,"/sys/a1prIyDGvtv/ST01/thing/service/property/set",99,{"method":"thing.service.property.set", "id":"937812926","params":{"LEDSwitch":0},"version":"1.0.0"} **********************************************************************/ void JsonString_Parsing(char *str, JSON *json) { char str1[100]={0};//LEDSwitch":0},"version":"1.0.0"} char str2[50]={0}; strcpy(str1,strstr(str,"params")+10); //"params"偏移10个地址开始拷贝 //strcspn:检索字符串 str1 开头连续有几个字符都不含字符串 str2 中的字符 strncpy(str2,str1,strcspn(str1,"}")); //拷贝strcspn(str1,"}"返回的字符个数 //此时str2的冒号后面就是我们需要的值 strcpy(json->values,strstr(str2,":")+1); //键在哪里?双引号前面就是键 strncpy(json->key,str2,strcspn(str1,"\"")); } /********************************************************************** *函数名:JsonString_Dispose *功 能:使用解析后的数据进行控制 *参 数:json:解析后数据保存的结构体 *返 回:无 *备 注:JsonString_Dispose(&json);; **********************************************************************/ void JsonString_Dispose(JSON *json) { u16 i=0; u8 state = 0; if(strstr(json->key, "LEDSwitch")) { //服务器下发的数据是字符串转为整型数,atoi(json->values) // DATA.LEDSwitch = atoi(json->values); state = atoi(json->values)? 0 : 1; if(state==0) { LED1= 0; printf("开灯\r\n"); } else { LED1= 1; printf("关灯\r\n"); } } // else if(strstr(json->key, "lightingFunction")) // { // //服务器下发的数据是字符串转为整型数,atoi(json->values) // DATA.LEDSwitch = atoi(json->values); // state = DATA.LEDSwitch? 0 : 1; // LED2 = state; LED3 = state; // } // else if(strstr(json->key, "motorDirection")) // { // DATA.MotorDirection = atoi(json->values); // state = DATA.MotorDirection? 0 : 1; // for(i=0;i<800;i++) // { // //步进电机控制 // } // //步进电机停止 // if(state==0) // { // // } // else // { // // } // } // //直流马达 // else if(strstr(json->key, "KitchenVentilator_MotorStall")) // { // //服务器下发的数据是字符串转为整型数,atoi(json->values) // DATA.KitchenVentilator_MotorStall = atoi(json->values); // motor_contorl(DATA.KitchenVentilator_MotorStall);//调用直流电机驱动代码 // } // else if(strstr(json->key, "RGBColor")) // { // RGBDisplay(json->values);//控制RGB // } } /********************************************************************************************************* * 函 数 名 : mstrcat * 功能说明 : 字符串连接 * 形 参 : s1:目标, s2:源 * 返 回 值 : 无 * 备 注 : 无 s1[100]="123" *********************************************************************************************************/ static void mstrcat(char *s1, const char *s2) { if(*s1 != NULL) while(*++s1); while((*s1++ = *s2++)); } /********************************************************************************************************* * 函 数 名 : CalculateSha1 * 功能说明 : 计算sha1密匙 * 形 参 : password:密匙存放缓冲区 * 返 回 值 : 无 * 备 注 : 无 *********************************************************************************************************/ static void CalculateSha1(unsigned char *password) { unsigned char temp[3] = {0}; unsigned char digest[30]={0}; unsigned char cnt = 0; hmac_sha1((unsigned char *)DeviceSecret,32,(unsigned char *)Encryption,46,digest); memset(temp, 0, sizeof(temp)); for(cnt=0;cnt<20;cnt++) { sprintf((char *)temp,"%02X",digest[cnt]); mstrcat((char *)password,(char *)temp); } } unsigned char Esp12_Get_ConnectionStatus(void) { return ConnectFlag; } void Esp12_Set_ConnectionStatus(unsigned char value) { ConnectFlag = value; } /********************************************************************************************************* * 函 数 名 : Esp12SendCmd * 功能说明 : 向esp12模组发送指令并等待希望的应答 * 形 参 : cmd:发送的命令,ack:希望的应答,waittime:等待应答的时间(ms) * 返 回 值 : 1没有得到希望的应答,0得到了希望的应答 * 备 注 : 无 *********************************************************************************************************/ unsigned char Esp12SendCmd(char *cmd, char *ack, unsigned short waittime) { Usart2.FlagLen = 0; //标示位、长度清零 waittime /= 10; //超时时间 SendUsart2Data((unsigned char *)cmd); //发送命令 while(--waittime) //等待串口接收完毕或超时退出 { if(Usart2.RecFlag == true) { if(strstr((char *)Usart2.RxBuff, (char *)ack)) { Usart2.FlagLen = 0; Usart2.RecFlag = false; //printf("%s\r\n", WifiUsart.RxBuff); break; } Usart2.FlagLen = 0; Usart2.RecFlag = false; //printf("%s\r\n", WifiUsart.RxBuff); } delay_ms(10); } if(waittime) return 1; return 0; } //初始化 JSON_PUBLISH publish_mqtt_message[4]= { { "\\\"temperature\\\":","0" }, { "\\\"Humidity\\\":","0" }, { "\\\"RunningState\\\":","0" }, { "\\\"LightLux\\\":","0" } }; extern int len; extern unsigned short value; //发布主题 ,上发多个数据 void Publish_MQTT_message(JSON_PUBLISH *data,u8 data_num) { char AT_CMD[384]={0}; char params[256]={0},i,*sp; sp=params; // sprintf(data[0].value,"%f",Get_AdcValue(ADC_Channel_10)*3.3/4096); //把传感器的值赋值给json结构体的value // sprintf(data[1].value,"%d",35); // sprintf(data[2].value,"%d",80); // sprintf(data[3].value,"%d",90); sprintf(data[0].value,"%f",TMP.T); //把传感器的值赋值给json结构体的value sprintf(data[1].value,"%f",TMP.H); sprintf(data[2].value,"%d",80); sprintf(data[3].value,"%f",Get_AdcValue(ADC_Channel_10)*3.3/4096); // 4 for(i=0;i<data_num;i++) { // 3 if(i<(data_num-1)) { sprintf(sp,"%s%s%s",data[i].keyname,data[i].value,"\\,"); while(*sp!=0) {sp++;} //防止覆盖 } //"\\\"temperature\\\":20\\,\\\"humidity\\\":30\\,\\\"harmfulGas\\\":40\\,\\\"GasConcentration\\\":50" else sprintf(sp,"%s%s",data[i].keyname,data[i].value); } // printf("data=%s\r\n",params); // sprintf(AT_CMD,"AT+MQTTPUB=0,\"%s\",\"{\\\"params\\\":{\\\"temperature\\\":50\\,\\\"humidity\\\":77}}\",1,0\r\n",PublishMessageTopPost); sprintf(AT_CMD,"AT+MQTTPUB=0,\"%s\",\"{\\\"params\\\":{%s}}\",1,0\r\n",PublishMessageTopPost,params); ESP12_Send_Cmd(AT_CMD,"OK",1000,1); } //RST 换成复位单片机 加断开连接
主函数进行调用
ESP12_STA_Init();//这里是WiFi的初始化 while(1){ u8 sp[100]; //使用一个数组来接收,这个下面可以知道用来接收温湿度 u8 sp1[100]; //使用一个数组来接收,这个下面可以知道用来接收光照 //sprintf("关照:%d, 电压:%.3f%%",value,value*3.3/4096); sht31_read_T_H(); //这里是sht31读取温湿度的代码初始化 printf("%f,%f\r\n",TMP.T,TMP.H); sprintf(sp,"现在的温度:%.3fC, 现在的湿度:%.3f%%",TMP.T,TMP.H); value=Get_AdcValue(ADC_Channel_10); //这里是使用通道10采集我们的光照强度 printf("光照ad=%d\r\n",value); printf("电压V=%.3f\r\n",value*3.3/4096); //计算电压 sprintf(sp1,"光照:%d",value); LCD_ShowFlashString(0, 0, sp, LCD_RED, LCD_WHITE); //我们还可以使用LCDx显示出来在我们的板载上面,当然你不喜欢也可以不用的 LCD_ShowFlashString(0, 40, sp1, LCD_RED, LCD_WHITE); //这里是我们的阿里云发布主题 Publish_MQTT_message(publish_mqtt_message,4); delay_ms(500); delay_ms(500);
🎮 功能展示
我们的功能展示分为三个部分显示,
串口助手显示数据
板载LCD显示
APP显示