当前位置: 首页 > news >正文

stm32通过esp8266连接阿里云平台代码讲解

连接服务器

首先,按照一定的规则,获取连接阿里服务器所需要的ClientID(客户端D)、Username(用户名)、Passward(密码),ServerIP(域名),ServerPort(端口号)

/*----------------------------------------------------------*/
/*函数名:阿里云初始化参数,得到客户端ID,用户名和密码      */
/*参  数:无                                                */     
/*返回值:无                                                */
/*----------------------------------------------------------*/      
void AliIoT_Parameter_Init(void)
{	char temp[128];                                                       //计算加密的时候,临时使用的缓冲区memset(ClientID,128,0);                                               //客户端ID的缓冲区全部清零sprintf(ClientID,"%s|securemode=3,signmethod=hmacsha1|",DEVICENAME);  //构建客户端ID,并存入缓冲区ClientID_len = strlen(ClientID);                                      //计算客户端ID的长度memset(Username,128,0);                                               //用户名的缓冲区全部清零sprintf(Username,"%s&%s",DEVICENAME,PRODUCTKEY);                      //构建用户名,并存入缓冲区Username_len = strlen(Username);                                      //计算用户名的长度memset(temp,128,0);                                                                      //临时缓冲区全部清零sprintf(temp,"clientId%sdeviceName%sproductKey%s",DEVICENAME,DEVICENAME,PRODUCTKEY);     //构建加密时的明文   utils_hmac_sha1(temp,strlen(temp),Passward,DEVICESECRE,DEVICESECRE_LEN);                 //以DeviceSecret为秘钥对temp中的明文,进行hmacsha1加密,结果就是密码,并保存到缓冲区中Passward_len = strlen(Passward);                                                         //计算用户名的长度memset(ServerIP,128,0);  sprintf(ServerIP,"%s.iot-as-mqtt.cn-shanghai.aliyuncs.com",PRODUCTKEY);                  //构建服务器域名ServerPort = 1883;                                                                       //服务器端口号1883u1_printf("服 务 器:%s:%d\r\n",ServerIP,ServerPort); //串口输出调试信息u1_printf("客户端ID:%s\r\n",ClientID);               //串口输出调试信息u1_printf("用 户 名:%s\r\n",Username);               //串口输出调试信息u1_printf("密    码:%s\r\n",Passward);               //串口输出调试信息
}

开始连接服务器

/*-------------------------------------------------*/
/*函数名:WiFi连接服务器                           */
/*参  数:无                                       */
/*返回值:0:正确   其他:错误                     */
/*-------------------------------------------------*/
char WiFi_Connect_IoTServer(void)
{	u1_printf("准备复位模块\r\n");                     //串口提示数据if(WiFi_Reset(50)){                                //复位,100ms超时单位,总计5s超时时间u1_printf("复位失败,准备重启\r\n");           //返回非0值,进入if,串口提示数据return 1;                                      //返回1}else u1_printf("复位成功\r\n");                   //串口提示数据u1_printf("准备设置STA模式\r\n");                  //串口提示数据if(WiFi_SendCmd("AT+CWMODE=1",50)){                //设置STA模式,100ms超时单位,总计5s超时时间u1_printf("设置STA模式失败,准备重启\r\n");    //返回非0值,进入if,串口提示数据return 2;                                      //返回2}else u1_printf("设置STA模式成功\r\n");            //串口提示数据if(wifi_mode==0){                                      //如果联网模式=0:SSID和密码写在程序里 u1_printf("准备取消自动连接\r\n");                 //串口提示数据if(WiFi_SendCmd("AT+CWAUTOCONN=0",50)){            //取消自动连接,100ms超时单位,总计5s超时时间u1_printf("取消自动连接失败,准备重启\r\n");   //返回非0值,进入if,串口提示数据return 3;                                      //返回3}else u1_printf("取消自动连接成功\r\n");           //串口提示数据u1_printf("准备连接路由器\r\n");                   //串口提示数据	if(WiFi_JoinAP(30)){                               //连接路由器,1s超时单位,总计30s超时时间u1_printf("连接路由器失败,准备重启\r\n");     //返回非0值,进入if,串口提示数据return 4;                                      //返回4	}else u1_printf("连接路由器成功\r\n");             //串口提示数据			}
#if (debug == 0)	else{                                                 //如果联网模式=1:Smartconfig方式,用APP发送if(KEY2_IN_STA==0){                                    //如果此时K2是按下的u1_printf("准备设置自动连接\r\n");                 //串口提示数据if(WiFi_SendCmd("AT+CWAUTOCONN=1",50)){            //设置自动连接,100ms超时单位,总计5s超时时间u1_printf("设置自动连接失败,准备重启\r\n");   //返回非0值,进入if,串口提示数据return 3;                                      //返回3}else u1_printf("设置自动连接成功\r\n");           //串口提示数据	u1_printf("准备开启Smartconfig\r\n");              //串口提示数据if(WiFi_SendCmd("AT+CWSTARTSMART",50)){            //开启Smartconfig,100ms超时单位,总计5s超时时间u1_printf("开启Smartconfig失败,准备重启\r\n");//返回非0值,进入if,串口提示数据return 4;                                      //返回4}else u1_printf("开启Smartconfig成功\r\n");        //串口提示数据u1_printf("请使用APP软件传输密码\r\n");            //串口提示数据if(WiFi_Smartconfig(60)){                          //APP软件传输密码,1s超时单位,总计60s超时时间u1_printf("传输密码失败,准备重启\r\n");       //返回非0值,进入if,串口提示数据return 5;                                      //返回5}else u1_printf("传输密码成功\r\n");               //串口提示数据u1_printf("准备关闭Smartconfig\r\n");              //串口提示数据if(WiFi_SendCmd("AT+CWSTOPSMART",50)){             //关闭Smartconfig,100ms超时单位,总计5s超时时间u1_printf("关闭Smartconfig失败,准备重启\r\n");//返回非0值,进入if,串口提示数据return 6;                                      //返回6}else u1_printf("关闭Smartconfig成功\r\n");        //串口提示数据}else{                                                 //反之,此时K2是没有按下u1_printf("等待连接路由器\r\n");                   //串口提示数据	if(WiFi_WaitAP(30)){                               //等待连接路由器,1s超时单位,总计30s超时时间u1_printf("连接路由器失败,准备重启\r\n");     //返回非0值,进入if,串口提示数据return 7;                                      //返回7	}else u1_printf("连接路由器成功\r\n");             //串口提示数据					}}
#endifu1_printf("准备设置透传\r\n");                     //串口提示数据if(WiFi_SendCmd("AT+CIPMODE=1",50)){               //设置透传,100ms超时单位,总计5s超时时间u1_printf("设置透传失败,准备重启\r\n");       //返回非0值,进入if,串口提示数据return 8;                                      //返回8}else u1_printf("设置透传成功\r\n");               //串口提示数据u1_printf("准备关闭多路连接\r\n");                 //串口提示数据if(WiFi_SendCmd("AT+CIPMUX=0",50)){                //关闭多路连接,100ms超时单位,总计5s超时时间u1_printf("关闭多路连接失败,准备重启\r\n");   //返回非0值,进入if,串口提示数据return 9;                                      //返回9}else u1_printf("关闭多路连接成功\r\n");           //串口提示数据u1_printf("准备连接服务器\r\n");                   //串口提示数据if(WiFi_Connect_Server(100)){                      //连接服务器,100ms超时单位,总计10s超时时间u1_printf("连接服务器失败,准备重启\r\n");     //返回非0值,进入if,串口提示数据return 10;                                     //返回10}else u1_printf("连接服务器成功\r\n");             //串口提示数据	return 0;                                          //正确返回0}
/*-------------------------------------------------*/
/*函数名:连接TCP服务器,并进入透传模式            */
/*参  数:timeout: 超时时间(100ms的倍数)        */
/*返回值:0:正确  其他:错误                      */
/*-------------------------------------------------*/
char WiFi_Connect_Server(int timeout)
{	WiFi_RxCounter=0;                               //WiFi接收数据量变量清零                        memset(WiFi_RX_BUF,0,WiFi_RXBUFF_SIZE);         //清空WiFi接收缓冲区   WiFi_printf("AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",ServerIP,ServerPort);//发送连接服务器指令while(timeout--){                               //等待超时与否Delay_Ms(100);                              //延时100ms	if(strstr(WiFi_RX_BUF ,"CONNECT"))          //如果接受到CONNECT表示连接成功break;                                  //跳出while循环if(strstr(WiFi_RX_BUF ,"CLOSED"))           //如果接受到CLOSED表示服务器未开启return 1;                               //服务器未开启返回1if(strstr(WiFi_RX_BUF ,"ALREADY CONNECTED"))//如果接受到ALREADY CONNECTED已经建立连接return 2;                               //已经建立连接返回2u1_printf("%d ",timeout);                   //串口输出现在的超时时间  }u1_printf("\r\n");                        //串口输出信息if(timeout<=0)return 3;                   //超时错误,返回3else                                      //连接成功,准备进入透传{u1_printf("连接服务器成功,准备进入透传\r\n");  //串口显示信息WiFi_RxCounter=0;                               //WiFi接收数据量变量清零                        memset(WiFi_RX_BUF,0,WiFi_RXBUFF_SIZE);         //清空WiFi接收缓冲区     WiFi_printf("AT+CIPSEND\r\n");                  //发送进入透传指令while(timeout--){                               //等待超时与否Delay_Ms(100);                              //延时100ms	if(strstr(WiFi_RX_BUF,"\r\nOK\r\n\r\n>"))   //如果成立表示进入透传成功break;                          //跳出while循环u1_printf("%d ",timeout);           //串口输出现在的超时时间  }if(timeout<=0)return 4;                 //透传超时错误,返回4	}return 0;	                                //成功返回0	
}

上面的代码就实现了esp8266连接上了阿里云TCP服务器,并且进入透传模式。

接着我们开始发送连接服务器报文CONNECT了,

CONNECT格式为:固定报头+可变报头+有效载荷
固定报头:0x10+剩余长度(可变报头+有效载荷的长度),如果剩余长度大于128,那么要用两个字节表示(剩余%128 | 0x80 , 以及剩余长度 / 128)。如果剩余长度小于128,那么用一个字节表示(剩余长度)
可变报头:一共10个字节,前7个固定为字节(00 04 4D 51 54 54 04),第8、第9第10都有各自的意义,不做详细讲述
有效载荷:2个字节的ClientID长度+ClientID+两个字节的Username长度+Username+两个字节的Passward长度+Passward

代码如下

/*----------------------------------------------------------*/
/*函数名:连接服务器报文                                    */
/*参  数:无                                                */
/*返回值:无                                                */
/*----------------------------------------------------------*/
void MQTT_ConectPack(void)
{	int temp,Remaining_len;Fixed_len = 1;                                                        //连接报文中,固定报头长度暂时先=1Variable_len = 10;                                                    //连接报文中,可变报头长度=10Payload_len = 2 + ClientID_len + 2 + Username_len + 2 + Passward_len; //连接报文中,负载长度      Remaining_len = Variable_len + Payload_len;                           //剩余长度=可变报头长度+负载长度temp_buff[0]=0x10;                       //固定报头第1个字节 :固定0x01		do{                                      //循环处理固定报头中的剩余长度字节,字节量根据剩余字节的真实长度变化temp = Remaining_len%128;            //剩余长度取余128Remaining_len = Remaining_len/128;   //剩余长度取整128if(Remaining_len>0)               	temp |= 0x80;                    //按协议要求位7置位          temp_buff[Fixed_len] = temp;         //剩余长度字节记录一个数据Fixed_len++;	                     //固定报头总长度+1    }while(Remaining_len>0);                 //如果Remaining_len>0的话,再次进入循环temp_buff[Fixed_len+0]=0x00;    //可变报头第1个字节 :固定0x00	            temp_buff[Fixed_len+1]=0x04;    //可变报头第2个字节 :固定0x04temp_buff[Fixed_len+2]=0x4D;	//可变报头第3个字节 :固定0x4Dtemp_buff[Fixed_len+3]=0x51;	//可变报头第4个字节 :固定0x51temp_buff[Fixed_len+4]=0x54;	//可变报头第5个字节 :固定0x54temp_buff[Fixed_len+5]=0x54;	//可变报头第6个字节 :固定0x54temp_buff[Fixed_len+6]=0x04;	//可变报头第7个字节 :固定0x04temp_buff[Fixed_len+7]=0xC2;	//可变报头第8个字节 :使能用户名和密码校验,不使用遗嘱,不保留会话temp_buff[Fixed_len+8]=0x00; 	//可变报头第9个字节 :保活时间高字节 0x00temp_buff[Fixed_len+9]=0x64;	//可变报头第10个字节:保活时间高字节 0x64   100s/*     CLIENT_ID      */temp_buff[Fixed_len+10] = ClientID_len/256;                			  			    //客户端ID长度高字节temp_buff[Fixed_len+11] = ClientID_len%256;               			  			    //客户端ID长度低字节memcpy(&temp_buff[Fixed_len+12],ClientID,ClientID_len);                 			//复制过来客户端ID字串	/*     用户名        */temp_buff[Fixed_len+12+ClientID_len] = Username_len/256; 				  		    //用户名长度高字节temp_buff[Fixed_len+13+ClientID_len] = Username_len%256; 				 		    //用户名长度低字节memcpy(&temp_buff[Fixed_len+14+ClientID_len],Username,Username_len);                //复制过来用户名字串	/*      密码        */temp_buff[Fixed_len+14+ClientID_len+Username_len] = Passward_len/256;			    //密码长度高字节temp_buff[Fixed_len+15+ClientID_len+Username_len] = Passward_len%256;			    //密码长度低字节memcpy(&temp_buff[Fixed_len+16+ClientID_len+Username_len],Passward,Passward_len);   //复制过来密码字串TxDataBuf_Deal(temp_buff, Fixed_len + Variable_len + Payload_len);                  //加入发送数据缓冲区
}

可以看到这个函数将CONNECT报文按照规则填充好,然后发送到数据缓冲区内,等待发送CONNECT报文。

订阅主题

订阅报文SUBSCRIBE
SUBSCRIBE:固定报头 +可变报头+主题长度+主题+服务质量等级

固定报头:0x82+剩余长度(可变报头+有效载荷的长度),如果剩余长度大于128,那么要用两个字节表示(剩余%128 | 0x80 , 以及剩余长度 / 128)。如果剩余长度小于128,那么用一个字节表示(剩余长度)

可变报头:两个字节,用来表示几号报文。
主题长度:两个字节
主题:要订阅的主题
服务质量等级:1个字节。

/*----------------------------------------------------------*/
/*函数名:SUBSCRIBE订阅topic报文                            */
/*参  数:QoS:订阅等级                                     */
/*参  数:topic_name:订阅topic报文名称                     */
/*返回值:无                                                */
/*----------------------------------------------------------*/
void MQTT_Subscribe(char *topic_name, int QoS)
{	Fixed_len = 2;                              //SUBSCRIBE报文中,固定报头长度=2Variable_len = 2;                           //SUBSCRIBE报文中,可变报头长度=2	Payload_len = 2 + strlen(topic_name) + 1;   //计算有效负荷长度 = 2字节(topic_name长度)+ topic_name字符串的长度 + 1字节服务等级temp_buff[0]=0x82;                                    //第1个字节 :固定0x82                      temp_buff[1]=Variable_len + Payload_len;              //第2个字节 :可变报头+有效负荷的长度	temp_buff[2]=0x00;                                    //第3个字节 :报文标识符高字节,固定使用0x00temp_buff[3]=0x01;		                              //第4个字节 :报文标识符低字节,固定使用0x01temp_buff[4]=strlen(topic_name)/256;                  //第5个字节 :topic_name长度高字节temp_buff[5]=strlen(topic_name)%256;		          //第6个字节 :topic_name长度低字节memcpy(&temp_buff[6],topic_name,strlen(topic_name));  //第7个字节开始 :复制过来topic_name字串		temp_buff[6+strlen(topic_name)]=QoS;                  //最后1个字节:订阅等级TxDataBuf_Deal(temp_buff, Fixed_len + Variable_len + Payload_len);  //加入发送数据缓冲区
}

可以看到这个函数将SUBSCRIBE报文按照规则填充好,然后发送到数据缓冲区内,等待发送SUBSCRIBE报文。

向阿里云平台发送数据

/*-------------------------------------------------*/
/*函数名:采集温湿度,并发布给服务器               */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void TempHumi_State(void)
{u8 tempdata,humidata;	char temp[256];  DHT11_Read_Data(&tempdata,&humidata);	//读取温湿度值	
//	AHT10_Data(&tempdata,&humidata);u1_printf("温度:%d  湿度:%d\r\n",tempdata,humidata);tempdata = 30;sprintf(temp,"{\"method\":\"thing.event.property.post\",\"id\":\"000000001\",\"params\":{\"CurrentTemperature\":%2d},\"version\":\"1.0.0\"}",tempdata);  //构建回复湿度温度数据MQTT_PublishQs0(P_TOPIC_NAME,temp,strlen(temp));   //添加数据,发布给服务器	
}/*----------------------------------------------------------*/
/*函数名:等级0 发布消息报文                                */
/*参  数:topic_name:topic名称                             */
/*参  数:data:数据                                        */
/*参  数:data_len:数据长度                                */
/*返回值:无                                                */
/*----------------------------------------------------------*/
void MQTT_PublishQs0(char *topic, char *data, int data_len)
{	int temp,Remaining_len;Fixed_len = 1;                              //固定报头长度暂时先等于:1字节Variable_len = 2 + strlen(topic);           //可变报头长度:2字节(topic长度)+ topic字符串的长度Payload_len = data_len;                     //有效负荷长度:就是data_lenRemaining_len = Variable_len + Payload_len; //剩余长度=可变报头长度+负载长度temp_buff[0]=0x30;                       //固定报头第1个字节 :固定0x30   	do{                                      //循环处理固定报头中的剩余长度字节,字节量根据剩余字节的真实长度变化temp = Remaining_len%128;            //剩余长度取余128Remaining_len = Remaining_len/128;   //剩余长度取整128if(Remaining_len>0)               	temp |= 0x80;                    //按协议要求位7置位          temp_buff[Fixed_len] = temp;         //剩余长度字节记录一个数据Fixed_len++;	                     //固定报头总长度+1    }while(Remaining_len>0);                 //如果Remaining_len>0的话,再次进入循环temp_buff[Fixed_len+0]=strlen(topic)/256;                      //可变报头第1个字节     :topic长度高字节temp_buff[Fixed_len+1]=strlen(topic)%256;		               //可变报头第2个字节     :topic长度低字节memcpy(&temp_buff[Fixed_len+2],topic,strlen(topic));           //可变报头第3个字节开始 :拷贝topic字符串	memcpy(&temp_buff[Fixed_len+2+strlen(topic)],data,data_len);   //有效负荷:拷贝data数据TxDataBuf_Deal(temp_buff, Fixed_len + Variable_len + Payload_len);  //加入发送数据缓冲区
}

解析阿里云平台的p

ublish数据
服务器发送数据给客户端的数据格式
固定报头(0x30+剩余长度)+可变报头(主题长度+主题)+有效载荷(数据内容)

在main函数里循环的检测云平台发送的数据里,首字符是否是0x30,如果是说明它是云平台推送的publish数据。

//if判断,如果第一个字节是0x30,表示收到的是服务器发来的推送数据//我们要提取控制命令else if((MQTT_RxDataOutPtr[2]==0x30)){ u1_printf("服务器等级0推送\r\n"); 		   //串口输出信息 MQTT_DealPushdata_Qs0(MQTT_RxDataOutPtr);  //处理等级0推送数据}				MQTT_RxDataOutPtr += BUFF_UNIT;                     //指针下移if(MQTT_RxDataOutPtr==MQTT_RxDataEndPtr)            //如果指针到缓冲区尾部了MQTT_RxDataOutPtr = MQTT_RxDataBuf[0];          //指针归位到缓冲区开头                        }//处理接收缓冲区数据的else if分支结尾

看到如下代码,它将解析出来的有效载荷(数据内容)通过CMDBuf_Deal()函数加入命令到缓冲区。

/*----------------------------------------------------------*/
/*函数名:处理服务器发来的等级0的推送                       */
/*参  数:redata:接收的数据                                */
/*返回值:无                                                */
/*----------------------------------------------------------*/
void MQTT_DealPushdata_Qs0(unsigned char *redata)
{int  re_len;               	           //定义一个变量,存放接收的数据总长度int  pack_num;                         //定义一个变量,当多个推送一起过来时,保存推送的个数int  temp,temp_len;                    //定义一个变量,暂存数据int  totle_len;                        //定义一个变量,存放已经统计的推送的总数据量int  topic_len;              	       //定义一个变量,存放推送中主题的长度int  cmd_len;                          //定义一个变量,存放推送中包含的命令数据的长度int  cmd_loca;                         //定义一个变量,存放推送中包含的命令的起始位置int  i;                                //定义一个变量,用于for循环int  local,multiplier;unsigned char tempbuff[BUFF_UNIT];	   //临时缓冲区unsigned char *data;                   //redata过来的时候,第一个字节是数据总量,data用于指向redata的第2个字节,真正的数据开始的地方re_len = redata[0]*256+redata[1];                               //获取接收的数据总长度		data = &redata[2];                                              //data指向redata的第2个字节,真正的数据开始的 pack_num = temp_len = totle_len = temp = 0;                	    //各个变量清零local = 1;multiplier = 1;do{pack_num++;                                     			//开始循环统计推送的个数,每次循环推送的个数+1	do{temp = data[totle_len + local];   temp_len += (temp & 127) * multiplier;multiplier *= 128;local++;}while ((temp & 128) != 0);totle_len += (temp_len + local);                          	//累计统计的总的推送的数据长度re_len -= (temp_len + local) ;                              //接收的数据总长度 减去 本次统计的推送的总长度      local = 1;multiplier = 1;temp_len = 0;}while(re_len!=0);                                  			//如果接收的数据总长度等于0了,说明统计完毕了u1_printf("本次接收了%d个推送数据\r\n",pack_num);//串口输出信息temp_len = totle_len = 0;                		            	//各个变量清零local = 1;multiplier = 1;for(i=0;i<pack_num;i++){                                        //已经统计到了接收的推送个数,开始for循环,取出每个推送的数据 		do{temp = data[totle_len + local];   temp_len += (temp & 127) * multiplier;multiplier *= 128;local++;}while ((temp & 128) != 0);				topic_len = data[local+totle_len]*256+data[local+1+totle_len] + 2;    //计算本次推送数据中主题占用的数据量cmd_len = temp_len-topic_len;                               //计算本次推送数据中命令数据占用的数据量cmd_loca = totle_len + local +  topic_len;                  //计算本次推送数据中命令数据开始的位置memcpy(tempbuff,&data[cmd_loca],cmd_len);                   //命令数据拷贝出来		                 CMDBuf_Deal(tempbuff, cmd_len);                             //加入命令到缓冲区totle_len += (temp_len+local);                              //累计已经统计的推送的数据长度local = 1;multiplier = 1;temp_len = 0;}	
}/*----------------------------------------------------------*/
/*函数名:处理命令缓冲区                                    */
/*参  数:data:数据                                        */
/*参  数:size:数据长度                                    */
/*返回值:无                                                */
/*----------------------------------------------------------*/
void CMDBuf_Deal(unsigned char *data, int size)
{memcpy(&MQTT_CMDInPtr[2],data,size);      //拷贝数据到命令缓冲区MQTT_CMDInPtr[0] = size/256;              //记录数据长度MQTT_CMDInPtr[1] = size%256;              //记录数据长度MQTT_CMDInPtr[size+2] = '\0';             //加入字符串结束符MQTT_CMDInPtr+=BUFF_UNIT;                 //指针下移if(MQTT_CMDInPtr==MQTT_CMDEndPtr)         //如果指针到缓冲区尾部了MQTT_CMDInPtr = MQTT_CMDBuf[0];       //指针归位到缓冲区开头
}

再在main函数,循环检测命令缓冲区是否有数据

if(MQTT_CMDOutPtr != MQTT_CMDInPtr){                             //if成立的话,说明命令缓冲区有数据了			       u1_printf("命令:%s\r\n",&MQTT_CMDOutPtr[2]);                 //串口输出信息receivedata_chuli(&MQTT_CMDOutPtr[2]);MQTT_CMDOutPtr += BUFF_UNIT;                             	 //指针下移if(MQTT_CMDOutPtr==MQTT_CMDEndPtr)           	             //如果指针到缓冲区尾部了MQTT_CMDOutPtr = MQTT_CMDBuf[0];          	             //指针归位到缓冲区开头				}//处理命令缓冲区数据的else if分支结尾	}//Connect_flag=1的if分支的结尾

因为接受到有效载荷(数据内容)是json格式的,我们可以用cJSON库,来处理数据。
cJSON的使用可以参考这篇文章:cJSON使用
处理过程过如下:

/*----------------------------------------------------------*/
/*函数名:解析JSON格式函数                                    */
/*参  message  :  待解析的JSON格式数据                        */              
/*返回值:无                                                */
/*----------------------------------------------------------*/
void receivedata_chuli(unsigned char * message) //阿里云推送数据json格式数据获取出来
{cJSON* cjson_test = NULL; //创建链表头指针:cJSON* cjson_params = NULL;cJSON* cjson_params_CurrentTemperature = NULL;cjson_test = cJSON_Parse((char *)message);// 解析整段JSON数据,并将链表头结点地址返回,赋值给头指针:cjson_params = cJSON_GetObjectItem(cjson_test, "params"); //根据键值对的名称从链表中取出对应的值,返回该键值对(链表节点)的地址cjson_params_CurrentTemperature = cJSON_GetObjectItem(cjson_params, "LightSwitch");//根据键值对的名称从链表中取出对应的值,返回该键值对(链表节点)的地址led_state = cjson_params_CurrentTemperature->valueint;if(led_state == 1) //接收到"LightSwitch"对应的键值为1{led_on();}else if(led_state == 0)//接收到"LightSwitch"对应的键值为0{led_off();}u1_printf("led_state :%d \r\n",led_state);cJSON_Delete(cjson_test);}

最终我们获取了云平台设置的标识符的对应键值。根据这个键值来确认是否开关灯。

实操效果

1.登陆云平台
2.进入对应设备的在线调试,可以看到,我这里建了两个物理模型,当前温度和主灯开关,它们的标识符分别为CurrentTemperature和LightSwitch。
在这里插入图片描述
3.设置对应的参数,然后点击设置按键,云平台即可发送数据给esp8266,esp8266再通过串口发送数据给stm32
stm32来解析这串字符串,并将里面的有效载荷(数据内容)获取出来,有效载荷(数据内容)里的内容是JSON格式的,所以用cJSON库做一个数据解析,根据标识符获取对应的键值,然后根据键值,判断是否开灯关灯。

相关文章:

stm32通过esp8266连接阿里云平台代码讲解

连接服务器 首先&#xff0c;按照一定的规则&#xff0c;获取连接阿里服务器所需要的ClientID&#xff08;客户端D&#xff09;、Username&#xff08;用户名&#xff09;、Passward(密码)&#xff0c;ServerIP&#xff08;域名&#xff09;&#xff0c;ServerPort&#xff08…...

突发!某大厂机房掉电,MySQL数据库无法启动,紧急恢复过程...

作者&#xff1a;IT邦德 中国DBA联盟(ACDU)成员&#xff0c;10余年DBA工作经验&#xff0c; Oracle、PostgreSQL ACE CSDN博客专家及B站知名UP主&#xff0c;全网粉丝10万 擅长主流Oracle、MySQL、PG、高斯及Greenplum备份恢复&#xff0c; 安装迁移&#xff0c;性能优化、故障…...

SpringCloudAlibaba:6.2RocketMQ的普通消息的使用

简介 普通消息也叫并发消息&#xff0c;是发送效率最高&#xff0c;使用最多的一种 依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSch…...

vue+echart :点击趋势图中的某一点或是柱状图,出现弹窗,并传输数据

样式 在趋势图中点击某一个柱状图&#xff0c;出现下面的弹窗 代码实现 主要是在趋势图页面代码中&#xff0c;在初始化趋势图的设置中&#xff0c;添加对趋势图监听的点击方法 drawChart() {const chartData this.chartData;let option {};if (!chartData.xData?.len…...

2024年上半年软考什么时候查成绩?附查询流程

考试一旦结束&#xff0c;并不意味着与考试相关的事情也就结束了。2024年上半年信息系统项目管理师等软考考试结束后&#xff0c;我们还需要关注考后和证书相关的事情&#xff0c;比如成绩查询、证书领取等等。 2024年上半年软考成绩查询 查询时间&#xff1a;预计在2024年7月…...

css3实现0.5px边框

效果图 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>css3实现0.5px边框</title><s…...

U-Net网络

U-Net网络 一、基本架构 各个箭头的解释&#xff1a; conv 3 * 3, ReLU&#xff1a;表示通过一个3 * 3的卷积层&#xff0c;并且该层自动附带一个非线性激活层&#xff08;ReLu&#xff09;copy and crop&#xff1a;表示进行裁剪然后再进行拼接&#xff08;在channel的维度上…...

不拍视频,不直播怎么在视频号卖货赚钱?开一个它就好了!

大家好&#xff0c;我是电商糖果 视频号这两年看着抖音卖货的热度越来越高&#xff0c;也想挤进电商圈。 于是它模仿抖音推出了自己的电商平台——视频号小店。 只要商家入驻视频号小店&#xff0c;就可以在视频号售卖商品。 具体怎么操作呢&#xff0c;需要拍视频&#xf…...

【vue-5】双向数据绑定v-model及修饰符

单向数据绑定&#xff1a;当数据发生改变时&#xff0c;视图会自动更新&#xff0c;但当用户手动更改input的值&#xff0c;数据不会自动更新&#xff1b; 双向数据绑定&#xff1a;当数据发生改变时&#xff0c;视图会自动更新&#xff0c;但当用户手动更改input的值&#xf…...

[STM32-HAL库]AS608-指纹识别模块-STM32CUBEMX开发-HAL库开发系列-主控STM32F103C8T6

目录 一、前言 二、详细步骤 1.光学指纹模块 2.配置STM32CUBEMX 3.程序设计 3.1 输出重定向 3.2 导入AS608库 3.3 更改端口宏定义 3.4 添加中断处理部分 3.5 初始化AS608 3.6 函数总览 3.7 录入指纹 3.8 验证指纹 3.9 删除指纹 3.10 清空指纹库 三、总结及资源 一、前言 …...

【java程序设计期末复习】chapter4 类和对象

类和对象 编程语言的几个发展阶段 &#xff08;1&#xff09;面向机器语言 计算机处理信息的早期语言是所谓的机器语言&#xff0c;使用机器语言进行程序设计需要面向机器来编写代码&#xff0c;即需要针对不同的机器编写诸如0101 1100这样的指令序列。 &#xff08;2&#x…...

ios:Command PhaseScriptExecution failed with a nonzero exit code

问题 使用 xcode 跑项目真机调试的时候&#xff0c;一直报错 Command PhaseScriptExecution failed with a nonzero exit code。 解决 最终靠以下方法解决 删除Podfile.lock文件删除Pods文件删除.xcworkspace文件Pod installCommandShiftK 清理一下缓存 亲测有效...

《拯救大学生课设不挂科第四期之蓝桥杯是什么?我是否要参加蓝桥杯?选择何种语言?如何科学备赛?方法思维教程》【官方笔记】

背景&#xff1a; 有些同学在大一或者大二可能会被老师建议参加蓝桥杯&#xff0c;本视频和文章主要是以一个过来人的身份来给与大家一些思路。 比如蓝桥杯是什么&#xff1f;我是否要参加蓝桥杯&#xff1f;参加蓝桥杯该选择何种语言&#xff1f;如何科学备赛&#xff1f;等…...

数据挖掘案例-航空公司客户价值分析

文章目录 1. 案例背景2. 分析方法与过程2.1 分析流程步骤2.2 分析过程1. 数据探索分析2. 描述性统计分析3. 分布分析1.客户基本信息分布分析2. 客户乘机信息分布分析3. 客户积分信息分布分析 4. 相关性分析 3. 数据预处理3.1 数据清洗3.2 属性约束3. 3 数据转换 4. 模型构建4. …...

决策树与机器学习实战【代码为主】

文章目录 &#x1f6f4;&#x1f6f4;引言&#x1f6f4;&#x1f6f4;决策树使用案例&#x1f6f4;&#x1f6f4;numpy库生成模拟数据案例&#x1f6f4;&#x1f6f4;决策树回归问题&#x1f6f4;&#x1f6f4;决策树多分类问题 &#x1f6f4;&#x1f6f4;引言 决策树是一种经…...

从感知机到神经网络

感知机 一、感知机是什么二、用感知机搭建简单逻辑电路2.1 与门2.2 与非门2.3 或门 三、感知机的局限性3.1 异或门3.2 线性和非线性 四、多层感知机4.1 已有门电路的组合4.2 Python异或门的实现 五、感知机模型5.1 感知机模型5.2 感知机损失函数5.3 感知机学习算法 六、感知机原…...

【HMGD】STM32/GD32 I2C DMA 主从通信

STM32 I2C配置 主机配置 主机只要配置速度就行 从机配置 从机配置相同速度&#xff0c;可以设置第二地址 因为我的板子上面已经有了上拉电阻&#xff0c;所以可以直接通信 STM32 I2C DMA 定长主从通信代码示例 int state 0; static uint8_t I2C_recvBuf[10] {0}; stat…...

leecode 226 翻转二叉树、101 对称二叉树、104 二叉树的最大深度

leecode 226 翻转二叉树、101 对称二叉树、104 二叉树的最大深度 leecode 226 翻转二叉树 题目链接 &#xff1a;https://leetcode.cn/problems/invert-binary-tree/description/ 题目 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。…...

Redux基础

简介 状态管理工具&#xff0c;集中式管理react、vue、angular等应用中多个组件的状态&#xff0c;是一个库,使用之后可以清晰的知道应用里发生了什么以及数据是如何修改&#xff0c;如何更新的 在项目中添加 Redux 并不是必须的,根据项目需求选择是否引入 Redux 三个原则 …...

国外目标公司的任何一个联系人也许都有意义

我们说跟进一个项目&#xff0c;最好能够联系上拥有决策权的人&#xff0c;不然中间隔着几重关系&#xff0c;所有的更新都需要层层审批申报&#xff0c;特别麻烦&#xff0c;总是要等&#xff0c;也许等到最后就是一场空。如果能够直接和老板或者是拍板的人沟通&#xff0c;则…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年&#xff0c;作为行业领先的3D工业相机及视觉系统供应商&#xff0c;累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成&#xff0c;通过稳定、易用、高回报的AI3D视觉系统&#xff0c;为汽车、新能源、金属制造等行…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

tomcat入门

1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效&#xff0c;稳定&#xff0c;易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...

SpringAI实战:ChatModel智能对话全解

一、引言&#xff1a;Spring AI 与 Chat Model 的核心价值 &#x1f680; 在 Java 生态中集成大模型能力&#xff0c;Spring AI 提供了高效的解决方案 &#x1f916;。其中 Chat Model 作为核心交互组件&#xff0c;通过标准化接口简化了与大语言模型&#xff08;LLM&#xff0…...

保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!

目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...