使用配置环境
1.核心板:STM32F103C8T6
2.WIFI模块:ESP-01S
3.传感器:LED灯(引脚:PA0)
4.使用云平台:新大陆云平台
列出代码中用到的全局变量:
#define REV_OK 0 //接收完成标志
#define REV_WAIT 1 //接收未完成标志
unsigned char esp8266_buf[128];//WiFi数据接收缓存区
unsigned short esp8266_cnt = 0, esp8266_cntPre = 0;
一、上报数据
1.发送数据包长度AT指令(发数据前都要进行数据包长度声明发送,然后在发送数据包)
sprintf((char *)IPDATALEN,"AT+CIPSEND=%d\r\n",datalen);
2.发送数据包格式
datatype:数据上报格式类型
说明:具体为datas属性内的 传感数据格式类型,我用的代码示例数据类型为1:列如
"datas":
{
"temperature": 23.5,
"rgb-r": "#999",
…
}
datas:要上报的传感数据数组()
msgid:消息编号(由客户端生成的一个用于表示该条报文的编号,用于服务器下发“上报响应”时原样带回)
"{\"t\": 3,\"datatype\":1,\"datas\": {\"tmp\":%.1f,\"hum\":%.1f,\"speed\":%d,\"countnum\":%d } ,\"msgid\": 123}"
3.数据上报发送成功返回信息格式
"{\"msgid\":123,\"status\":0,\"t\":4}"
详情可参考官方文档:设备接入协议-MQTT.docx · newlandedu/资料下载 - Gitee.com
具体封装函数
void ESP8266_cloudSend(float tmp,float hum,int Distance_mm,uint16_t countnum)
{
u8 IPDATA[200];
u8 IPDATALEN[200];
memset(IPDATA,0x00,200);
sprintf((char *)IPDATA,"{\"t\": 3,\"datatype\":1,\"datas\": {\"tmp\":%.1f,\"hum\":%.1f,\"speed\":%d,\"countnum\":%d } ,\"msgid\": 123}"
,tmp,hum,Distance_mm,countnum);
int datalen=strlen(IPDATA);//计算数据包长度
memset(IPDATALEN,0x00,200);
sprintf((char *)IPDATALEN,"AT+CIPSEND=%d\r\n",datalen);
while(ESP8266_SendCmd(IPDATALEN, "OK"))//数据包长度声明发送
delay_ms(500);
UsartPrintf(USART_DEBUG, "数据上报发送中...\r\n");
while(ESP8266_SendCmd(IPDATA, "{\"msgid\":123,\"status\":0,\"t\":4}"))//数据上报发送
delay_ms(500);
UsartPrintf(USART_DEBUG, "数据上报发送成功\r\n");
}
二、云平台下发指令
1.云平台配置执行器
2.下层数据解析
数据返回:ESP8266的返回格式为 "+IPD,x:yyy" x代表数据长度,yyy是数据内容(说明: 不同网络设备返回的格式不同,需要去调试)
1、ESP8266串口来数据后触发中断进行数据接收,将数据保存esp8266_buf
//==========================================================
// 函数名称: USART2_IRQHandler
//
// 函数功能: 串口2收发中断
//
// 入口参数: 无
//
// 返回参数: 无
//
// 说明:
//==========================================================
void USART2_IRQHandler(void)
{
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收中断
{
if(esp8266_cnt >= sizeof(esp8266_buf)) esp8266_cnt = 0; //防止串口被刷爆
esp8266_buf[esp8266_cnt++] = USART2->DR;
USART_ClearFlag(USART2, USART_FLAG_RXNE);
}
}
2、将平台返回的数据解析,把数据内容返回
//==========================================================
// 函数名称: ESP8266_GetIPD
//
// 函数功能: 获取平台返回的数据
//
// 入口参数: 等待的时间(乘以10ms)
//
// 返回参数: 平台返回的原始数据
//
// 说明: 不同网络设备返回的格式不同,需要去调试
// 如ESP8266的返回格式为 "+IPD,x:yyy" x代表数据长度,yyy是数据内容
//==========================================================
unsigned char *ESP8266_GetIPD(unsigned short timeOut)
{
char *ptrIPD = NULL;
do
{
if(ESP8266_WaitRecive() == REV_OK) //如果接收完成
{
ptrIPD = strstr((char *)esp8266_buf, "IPD,"); //搜索“IPD”头
if(ptrIPD == NULL) //如果没找到,可能是IPD头的延迟,还是需要等待一会,但不会超过设定的时间
{
//UsartPrintf(USART_DEBUG, "\"IPD\" not found\r\n");
}
else
{
ptrIPD = strchr(ptrIPD, ':'); //找到':'
if(ptrIPD != NULL)
{
ptrIPD++;
return (unsigned char *)(ptrIPD);
}
else
return NULL;
}
}
delay_ms(5); //延时等待
} while(timeOut--);
return NULL; //超时还未找到,返回空指针
}
3、再次解析提取内容,然后底层进行对应操作
//平台下发数据格式
//{"apitag":"motor02","cmdid":"aa71fefe-f363-4461-a568-bdf51c8cea7c","data":"100","t":5}
void ESP8266_cloudCtr(unsigned char *dataPtr)
{
if(strstr((char *)dataPtr, "{\"apitag\":\"led001\",")) //搜索"led001"
{
if(strstr((char *)dataPtr, "\"data\":1,")) //控制数据如果为1,代表开
{
GPIO_ResetBits(GPIOA, GPIO_Pin_0);
delay_ms(500);
}
else if(strstr((char *)dataPtr, "\"data\":0,")) //控制数据如果为0,代表关
{
GPIO_SetBits(GPIOA, GPIO_Pin_0);
delay_ms(500);
}
ESP8266_Clear();
}
//{"apitag":"motor02","cmdid":"aa71fefe-f363-4461-a568-bdf51c8cea7c","data":"100","t":5}
if(strstr((char *)dataPtr, "{\"apitag\":\"motor01\",")) //搜索"motor01"
{
if(strstr((char *)dataPtr, "\"data\":1,")) //控制数据如果为1,代表开
{
Speed_cloud += 20;
if (Speed_cloud > 80)
{
Speed_cloud = -80;
}
Motor_SetSpeed(Speed_cloud);
}
else if(strstr((char *)dataPtr, "\"data\":0,")) //控制数据如果为0,代表关
{
Speed_cloud += 20;
if (Speed_cloud > 80)
{
Speed_cloud = -80;
}
Motor_SetSpeed(Speed_cloud);
}
OLED_ShowSignedNum(1, 7, Speed_cloud, 3);
ESP8266_Clear();
}
}
三、main函数的while循环中调用
unsigned char *dataPtr = NULL;
dataPtr = ESP8266_GetIPD(0);
if(dataPtr != NULL)
{
ESP8266_cloudCtr(dataPtr);
}
ESP8266_cloudSend(dht11_info.tempreture,dht11_info.humidity,Distance_mm,countnum);