一、声明
该项目只需要创建一个产品,然后这个产品里面包含几个设备,而不是直接创建几个产品
注意:传输数据使用到了不同的power,还有一定要手机先联网才能使用云平台
二、OneNet云平台创建
(1)创建一个产品
第一步:OneNet网站登录,然后进入开发者中心
第二步:在产品开发里面选择创建产品,注意联网方式是wifi,开发方案是自定义方案
这个里面的设备名称不一定要是英文,可以是中文,也就是这个项目的大标题
第三步:添加设备
在产品开发的设备管理里面添加设备
记得!!!这个里面的设备名称就是需要用英文的!!!也就是MQTT协议里面用到的设备ID!!!
第四步:在产品开发的产品开发里面设置物模型,也就是我们要传输的四个数据
到这里我们产品创建得差不多了,接下来就是需要获取信息,为后面写代码做准备
(2)获取信息
设备名称:zhinengjiaju
设备密钥:Q1g0ZU1ETnpsd21TR0IwaGVHbnlXMzF2RUwwVmRtSEo=
产品ID:zv9My9QY4s
(下面这两个是通用的,然后有一个工具需要在官网去下载,这个可以看之前的CSDN)
url:mqtts.heclouds.com
端口号:1883
时间戳:2052911776
res:products/zv9My9QY4s/devices/zhinengjiaju
et:2052911776
key:Q1g0ZU1ETnpsd21TR0IwaGVHbnlXMzF2RUwwVmRtSEo=
password:version=2018-10-31&res=products%2Fzv9My9QY4s%2Fdevices%2Fzhinengjiaju&et=2052911776&method=md5&sign=0%2Fh%2F1yGDE3aGxdo%2FcVZTyA%3D%3D
订阅:$sys/zv9My9QY4s/zhinengjiaju/thing/property/post/reply
发布:$sys/zv9My9QY4s/zhinengjiaju/thing/property/post
(3)串口调试(这一步可以判断设备有没有调试好)
首先如果发送出来的东西不正常看看是不是波特率有问题,波特率是115200
要是还有问题,就换几个端口重新试几次
如果还是有问题就重新刷一下固件库,刷固件库的之后记得用辰哥单片机的烧入软件,再用专门的烧录器,这样能够省很多没必要的麻烦。选好下载速度115200,选好串口的端口,其他的都不改变,直接烧录就行
如果固件库刷完了,还是在连上热点之后出问题的话,那么可能出现的问题就是串口发送的代码有问题,自己再好好检查一下ID,设备名称之类的信息有没有改正确
最后一行的power就是标识符,设置物模型时候写的什么标识符,在这里写什么标识符就可以了,后面的那个25就是发送的数据
AT
AT+RST
AT+CWMODE=1
AT+CWDHCP=1,1
AT+CWJAP="iPhone","123456789"
AT+MQTTUSERCFG=0,1,"zhinengjiaju","zv9My9QY4s","version=2018-10-31&res=products%2Fzv9My9QY4s%2Fdevices%2Fzhinengjiaju&et=2052911776&method=md5&sign=0%2Fh%2F1yGDE3aGxdo%2FcVZTyA%3D%3D",0,0,""
AT+MQTTCONN=0,"mqtts.heclouds.com",1883,1
AT+MQTTSUB=0,"$sys/zv9My9QY4s/zhinengjiaju/thing/property/post/reply",1
AT+MQTTPUB=0,"$sys/zv9My9QY4s/zhinengjiaju/thing/property/post","{\"id\":\"123\"\,\"params\":{\"power1\":{\"value\":25\}}}",0,0
如果以上的步骤都没有问题,说明云平台创建正确,esp01s工作正常。那么就可以在接下来进行单片机发数据了
(三)单片机发数据
esp01s.c
这个头文件有点问题,后续改改就行了
//单片机头文件
#include "main.h"
//网络设备驱动
#include "esp8266.h"
//硬件驱动
#include "usart.h"
//C库
#include <string.h>
#include <stdio.h>
#include <string.h>
#define ESP01S_WIFI_INFO "AT+CWJAP=\"iPhone\",\"123456789\"\r\n"
const char* ClintID="zhinengjiaju";
const char* username="zv9My9QY4s";
const char* passwd="version=2018-10-31&res=products%2Fzv9My9QY4s%2Fdevices%2Fzhinengjiaju&et=2052911776&method=md5&sign=0%2Fh%2F1yGDE3aGxdo%2FcVZTyA%3D%3D";
const char* Url="mqtts.heclouds.com";
const char* pubtopic="$sys/zv9My9QY4s/zhinengjiaju/thing/property/post";
const char* subtopic="$sys/zv9My9QY4s/zhinengjiaju/thing/property/post/reply";
const char* func1="temperature";
const char* func2="humidity";
const char* func3="light";
const char* func4="MQ135";
unsigned char ESP01S_buf[256];
unsigned short ESP01S_cnt = 0, ESP01S_cntPre = 0;
uint8_t aRxBuffer; //接收中断缓冲
//==========================================================
// 函数名称: ESP01S_Clear
//
// 函数功能: 清空缓存
//
// 入口参数: 无
//
// 返回参数: 无
//
// 说明:
//==========================================================
void ESP01S_Clear(void)
{
memset(ESP01S_buf, 0, sizeof(ESP01S_buf));
ESP01S_cnt = 0;
}
//==========================================================
// 函数名称: ESP01S_WaitRecive
//
// 函数功能: 等待接收完成
//
// 入口参数: 无
//
// 返回参数: REV_OK-接收完成 REV_WAIT-接收超时未完成
//
// 说明: 循环调用检测是否接收完成
//==========================================================
_Bool ESP01S_WaitRecive(void)
{
if(ESP01S_cnt == 0) //如果接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数
return REV_WAIT;
if(ESP01S_cnt == ESP01S_cntPre) //如果上一次的值和这次相同,则说明接收完毕
{
ESP01S_cnt = 0; //清0接收计数
return REV_OK; //返回接收完成标志
}
ESP01S_cntPre = ESP01S_cnt; //置为相同
return REV_WAIT; //返回接收未完成标志
}
//==========================================================
// 函数名称: ESP01S_SendCmd
//
// 函数功能: 发送命令
//
// 入口参数: cmd:命令
// res:需要检查的返回指令
//
// 返回参数: 0-成功 1-失败
//
// 说明:
//==========================================================
_Bool ESP01S_SendCmd(char *cmd, char *res)
{
unsigned char timeOut = 200;
Usart_SendString(huart2, (unsigned char *)cmd, strlen((const char *)cmd));
while(timeOut--)
{
if(ESP01S_WaitRecive() == REV_OK) //如果收到数据
{
if(strstr((const char *)ESP01S_buf, res) != NULL) //如果检索到关键词
{
ESP01S_Clear(); //清空缓存
return 0;
}
}
HAL_Delay(10);
}
return 1;
}
//==========================================================
// 函数名称: ESP01S_Init
//
// 函数功能: 初始化ESP01S
//
// 入口参数: 无
//
// 返回参数: 无
//
// 说明:
//==========================================================
void ESP01S_Init(void)
{
char cmdBuf[512];
ESP01S_Clear();
UsartPrintf(USART_DEBUG, "0. AT\r\n");
while(ESP01S_SendCmd("AT\r\n", "OK"))
HAL_Delay(500);
UsartPrintf(USART_DEBUG, "1. RST\r\n");
ESP01S_SendCmd("AT+RST\r\n", "");
HAL_Delay(500);
UsartPrintf(USART_DEBUG, "2. CWMODE\r\n");
while(ESP01S_SendCmd("AT+CWMODE=1\r\n", "OK")) //模式1(Station),默认保存Flash
HAL_Delay(500);
UsartPrintf(USART_DEBUG, "3. AT+CWDHCP\r\n"); //开启DHCP(获取分配IP),默认保存Flash
while(ESP01S_SendCmd("AT+CWDHCP=1,1\r\n", "OK"))
HAL_Delay(500);
UsartPrintf(USART_DEBUG, "4. CWJAP\r\n"); //链接WIFI
while(ESP01S_SendCmd(ESP01S_WIFI_INFO, "OK"))
HAL_Delay(500);
UsartPrintf(USART_DEBUG, "5.MQTTUSERCFG\r\n"); //用户信息配置
sprintf(cmdBuf,"AT+MQTTUSERCFG=0,1,\"%s\",\"%s\",\"%s\",0,0,\"\"\r\n", ClintID,username,passwd);
while(ESP01S_SendCmd(cmdBuf, "OK"))
HAL_Delay(500);
memset(cmdBuf,0,sizeof(cmdBuf));
UsartPrintf(USART_DEBUG, "6.MQTTCONN\r\n"); //连接服务器
sprintf(cmdBuf,"AT+MQTTCONN=0,\"%s\",1883,1\r\n",Url);
while(ESP01S_SendCmd(cmdBuf, "OK"))
HAL_Delay(500);
memset(cmdBuf,0,sizeof(cmdBuf));
UsartPrintf(USART_DEBUG, "7.MQTTSUB\r\n"); //订阅消息
sprintf(cmdBuf,"AT+MQTTSUB=0,\"%s\",1\r\n",subtopic);
while(ESP01S_SendCmd(cmdBuf, "OK"))
HAL_Delay(500);
memset(cmdBuf,0,sizeof(cmdBuf));
}
//功能:esp发送消息
//参数:无
//返回值:0:发送成功;1:发送失败
void Esp_PUB(int value1,int value2,int value3,int value4)
{
char cmdBuf[256];
UsartPrintf(USART_DEBUG, "Publish\r\n"); //订阅消息
// sprintf(cmdBuf,"AT+MQTTPUB=0,\"%s\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"%s\\\":{\\\"value\\\":%d\\}}}\",0,0\r\n",pubtopic,func1,value1);
sprintf(cmdBuf,"AT+MQTTPUB=0,\"%s\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"%s\\\":{\\\"value\\\":%d\\}\\,\\\"%s\\\":{\\\"value\\\":%d\\}\\,\\\"%s\\\":{\\\"value\\\":%d\\}\\,\\\"%s\\\":{\\\"value\\\":%d\\}}}\",0,0\r\n",pubtopic,func1,value1,func2,value2,func3,value3,func4,value4);
while(ESP01S_SendCmd(cmdBuf, "OK"))
HAL_Delay(500);
memset(cmdBuf,0,sizeof(cmdBuf));
HAL_Delay(100);
}
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
UNUSED(huart);
if(ESP01S_cnt >= sizeof(ESP01S_buf)) //溢出判断
{
ESP01S_cnt = 0;
memset(ESP01S_buf,0x00,sizeof(ESP01S_buf));
HAL_UART_Transmit(&huart1, (uint8_t *)"接收缓存溢出", 10,0xFFFF);
}
else
{
ESP01S_buf[ESP01S_cnt++] = aRxBuffer; //接收数据转存
// if(aRxBuffer=='1') HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET);
// if(aRxBuffer=='0') HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET);
}
HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1); //再开启接收中断
}
/* USER CODE END 4 */
这个里面最难写的就是发送数据,如果要分开写发送数据的话,那么要连四次热点才能把四个数据全都给发出去,所以只写一个发送数据,但是一次最多只能发五个数据。稍微根据这个代码改改就行了
参考发数据的模式可以参考姜帆的代码,我自己的代码,还有B站上给这个代码的博主
sprintf(cmdBuf,"AT+MQTTPUB=0,\"%s\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"%s\\\":{\\\"value\\\":%d\\}}}\",0,0\r\n",pubtopic,func1,power);
sprintf(cmdBuf,"AT+MQTTPUB=0,\"%s\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"%s\\\":{\\\"value\\\":%d\\}\\,\\\"%s\\\":{\\\"value\\\":%d\\}\\,\\\"%s\\\":{\\\"value\\\":%d\\}\\,\\\"%s\\\":{\\\"value\\\":%d\\}}}\",0,0\r\n",pubtopic,func1,value1,func2,value2,func3,value3,func4,value4);
sprintf(cmdBuf,"AT+MQTTPUB=0,\"%s\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"%s\\\":{\\\"value\\\":%d\\}\\,\\\"%s\\\":{\\\"value\\\":%d\\}\\,\\\"%s\\\":{\\\"value\\\":%d\\}\\,\\\"%s\\\":{\\\"value\\\":%d\\}\\,\\\"%s\\\":{\\\"value\\\":%d\\}}}\",0,0\r\n",pubtopic,func1,value1,func2,value2,func3,value3,func4,value4,func5,value5);
esp01s.h
#ifndef _ESP8266_H_
#define _ESP8266_H_
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#define REV_OK 0 //接收完成标志
#define REV_WAIT 1 //接收未完成标志
void ESP01S_Init(void);
void ESP01S_Clear(void);
//void ESP01S_SendData(unsigned char *data, unsigned short len);
//unsigned char *ESP01S_GetIPD(unsigned short timeOut);
void Esp_PUB(int value1,int value2,int value3,int value4);
#endif
(1)CubeMx的配置
串口1用来和电脑通信
最开始是用来判断串口是否正常工作,后面可以用来判断单片机和esp01s有没有正常通信成功
这个可以不用开串口接收中断
这就是串口助手发回来的数据,通过串口1发回来的,由此可以看到esp01s有没有成功连上手机,只有成功连上之后才能发数据给云平台
串口2是用来给onenet发数据
这个我具体不知道是怎样的一个工作原理,但是串口2就是单片机和esp01s进行通信,串口1 就是单片机和电脑进行通信
这个就要注意开一下中断了
(2)keil.5的配置
首先我前面已经把esp01s.c和esp01s.h的代码已经写上去了。但是这个代码直接写上去是会报错的,所以需要在usart.c和usart.h里面添加代码
void Usart_SendString(UART_HandleTypeDef USARTx, unsigned char *str, unsigned short len)
{
unsigned short count = 0;
for(; count < len; count++)
{
HAL_UART_Transmit (&USARTx ,(uint8_t *)str++,1,HAL_MAX_DELAY );
}
}
void UsartPrintf(UART_HandleTypeDef USARTx, char *fmt,...)
{
unsigned char UsartPrintfBuf[296];
va_list ap;
unsigned char *pStr = UsartPrintfBuf;
va_start(ap, fmt);
vsnprintf((char *)UsartPrintfBuf, sizeof(UsartPrintfBuf), fmt, ap);
va_end(ap);
while(*pStr != NULL)
{
HAL_UART_Transmit (&USARTx ,(uint8_t *)pStr++,1,HAL_MAX_DELAY );
}
}
#include <stdarg.h>
#include "stdio.h"
#define USART_DEBUG huart1
void Usart_SendString(UART_HandleTypeDef USARTx, unsigned char *str, unsigned short len);
void UsartPrintf(UART_HandleTypeDef USARTx, char *fmt,...);
上述代码添加完之后调用esp01s的文件就不会出错了
main.c文件
UsartPrintf(USART_DEBUG, "The USART1 is OK!\r\n");
HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1);
ESP01S_Init();
ESP01S_Clear();
UsartPrintf(USART_DEBUG, "Init is OK!\r\n");
Esp_PUB(temp,humi,Light_val,MQ135_val);
这一行代码里面的temp,humi这些数据要在main.c里面定义。因为onenet里面传输的数据是int32类型,所以这里定义的类型也是int32的数据
/* USER CODE BEGIN Includes */
#include "dht11.h"
#include "oled.h"
#include "mq135.h"
#include "gy302.h"
#include "esp8266.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
extern uint8_t aRxBuffer;
int32_t temp;
int32_t humi;
int32_t Light_val;
int32_t MQ135_val;
/* USER CODE END PTD */
在dht11等温湿度、光照、大气压的代码里面传输的数据就声明使用就可以
main.c的代码
这个里面是整个智能家居的所以外设的运行代码
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "dht11.h"
#include "oled.h"
#include "mq135.h"
#include "gy302.h"
#include "esp8266.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
extern uint8_t aRxBuffer;
int32_t temp;
int32_t humi;
int32_t Light_val;
int32_t MQ135_val;
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC1_Init();
MX_I2C1_Init();
MX_TIM4_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
OLED_Init();
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_3);
UsartPrintf(USART_DEBUG, "The USART1 is OK!\r\n");
HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1);
ESP01S_Init();
ESP01S_Clear();
UsartPrintf(USART_DEBUG, "Init is OK!\r\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
DHT11();
MQ135_Init();
MQ135_ReadData();
Value_GY30();
Esp_PUB(temp,humi,Light_val,MQ135_val);
}
/* USER CODE END 3 */
}
最后一个问题就是我没有学会如何加上freertos来让执行起来更快,我也不知道为什么加上esp01s发数据之后,oled就不显示了,要等到连上手机热点之后才会显示,而且比以前要卡一些