300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > esp32+stm32+onenet+arduino 智能家居系统

esp32+stm32+onenet+arduino 智能家居系统

时间:2023-07-05 16:34:40

相关推荐

esp32+stm32+onenet+arduino 智能家居系统

第一次发帖,有什么不对的,麻烦指正一下。

以下是我最近完成的一个小项目,不过还有很大的改动优化空间,本篇只是带来一个大体的框架,以及我个人在这个项目所遇到的一些问题,以及我个人对这些问题的解决以及看法,(一定有错的地方,发出来也是希望大家帮忙看看 嘿嘿)

首先,介绍一下本项目,本项目所需的有3块esp32_wroom_32模块,以及温湿度传感器DHT11,继电器开关,光敏电阻,stm32f407,以及一个串口屏(淘晶驰TJC4832T135_001),不过这个串口屏也可以不要,看你自己吧。首先需要解决的是esp32间的数据传输问题,这个我使用的是arduino开发,然后用的是esp_now传输,这个有不了解的我建议去下面的链接了解一下

/video/BV1g3411y7ro/?spm_id_from=333.788&vd_source=de8713d22d3d70995910b8e33ffe061b

这是可以无基础的学习的一个视频资源,网上也有很多关于now的介绍,可以到乐鑫的官网去深入了解。

然后第一个肯定是arduino的配置 ,首先去arduino的官网下载那个安装

文件——首选项——附加开发板管理器网址 :添加 /dl/package_esp32_index.json

——管理库:然后输入ESP32 (选那个带esp32的)然后进行下载就可以了

工具——开发板:选择ESP32 Dev Module;然后选择对应的端口;

然后首先要实现的是三个esp32之间的通信,我选择的是esp32独有esp-now协议

ESP-NOW 是由乐鑫开发的另一款协议,可以使多个设备在没有或不使用 Wi-Fi 的情况下进行通信。这种协议类似常见于无线鼠标中的低功耗 2.4GHz 无线连接——设备在进行通信之前要进行配对。配对之后,设备之间的连接是持续的、点对点的,并且不需要握手协议。

ESP-NOW 广泛应用于智能照明、远程控制、传感器等领域。

对于这个协议想了解更深入的话,可以去以下链接

ESP-NOW - ESP32 - — ESP-IDF 编程指南 latest 文档 ()

首先要获取各个esp32的mac地址,因为now协议是通过其mac地址进行数据传输的

#include <WiFi.h>void setup() {// put your setup code here, to run once:Serial.begin(115200);WiFi.mode(WIFI_MODE_STA);Serial.println(WiFi.macAddress()); //串口输出mac地址 }void loop() {// put your main code here, to run repeatedly:}

将以上代码 编译上传至esp32,即可得到其mac地址

然后以下是now的基本创建过程

#include <WiFi.h>#include <esp_now.h>uint8_t MACA[] = {0xC0,0x49,0xEF,0xD3,0x5F,0x28};//a uint8_t MACB[] = {0xC0,0x49,0xEF,0xD0,0xE2,0xC4};//buint8_t MACC[] = {0x40,0x22,0xD8,0x60,0xDD,0xB8};//c String success; //发送数据成功则存储变量//接收数据结构体 接受 温湿度以及哪个地方typedef struct Rdata{int id;float humidity;//湿度float temperature; //温度bool relay_status; //继电器状态 true为开 false为关}Rdata;Rdata myData; Rdata board1; //用于存储b板的数据Rdata board2; //用于存储c板的数据//创建一个包含结构体的数组方便调用读写数据//发送 结构体,可更改为打开或关闭继电器的信息,以及等等的控制信息typedef struct Tdata{int id;bool relay; //控制继电器状态int x; //暂留开关}Tdata;//创建一个发送的结构体Tdata IDdata;//发送数据时的回调函数void OnDataSend(const uint8_t *mac_addr, esp_now_send_status_t status) //发送数据时的回调函数{Serial.print("\r\n status:\t");Serial.println(status == ESP_NOW_SEND_SUCCESS ? "tran succes~!" : "tran failed!");}//接受到数据时的回调函数 可在这个函数里选择接收到何种数据 作何等操作void OnDataRecv(const uint8_t *mac_addr, const uint8_t *incomingData, int len){char macStr[18]; //定义一个字符串数组 用来存储是哪个发来的数据,其mac地址Serial.print("recv:");snprintf(macStr,sizeof(macStr),"%02x:%02x:%02x:%02x:%02x:%02x:",mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3],mac_addr[4],mac_addr[5]);Serial.println(macStr);//拼接到macStr 而后打印出来memcpy(&myData, incomingData, sizeof(myData)); //将接收到的数据存储到mydata中 Serial.printf("id: %u size: %u \n",myData.id,len); //打印出是哪个id发力的信息if(myData.id == 23)//如果是id为23的发来 后面可以改成字符串 是哪个地方发来的{board1.humidity = myData.humidity;board1.temperature = myData.temperature;board1.relay_status = myData.relay_status;Serial.printf("1humidity :%0.2f\n",board1.humidity);Serial.printf("1temperature:%0.2f\n",board1.temperature);if(board1.relay_status == true)Serial.println("1relay_status: Open");elseSerial.println("1relay_status: Close");}else if (myData.id == 26){board2.humidity = myData.humidity;board2.temperature = myData.temperature; Serial.printf("2humidity :%0.2f\n",board2.humidity);Serial.printf("2temperature:%0.2f\n",board2.temperature);if(board2.relay_status == true)Serial.println("2relay_status: Open");elseSerial.println("2relay_status: Close");}}void setup() {// put your setup code here, to run once:Serial.begin(115200);WiFi.mode(WIFI_STA);if(esp_now_init() != ESP_OK){Serial.printf("init esp_now error\n");return;}esp_now_register_send_cb(OnDataSend); //ESPNow初始化成功,注册发送包,获取已发送数据包的状态// 获取状态是上面那个回调函数所做的是esp_now_peer_info_t peerInfo; //注册对等点peerInfo.channel = 0; //对端点用于发送/接受数据的WiFi通道设置为0peerInfo.encrypt = false; //表示对端点发送/接受的数据是否加密对于本例,设置为false(不加密)memcpy(peerInfo.peer_addr,MACB,6); //对端点设备地址,将其设置为广播地址if(esp_now_add_peer(&peerInfo) != ESP_OK) //将“对等点”添加到列表中{Serial.println("add erreo");return;}memcpy(peerInfo.peer_addr,MACC,6); //对端点设备地址,将其设置为广播地址if(esp_now_add_peer(&peerInfo) != ESP_OK) //将“对等点”添加到列表中{Serial.println("add erreo");return;} esp_now_register_recv_cb(OnDataRecv);}void loop() {// put your main code here, to run repeatedly:int i=0;while(1){i++;if(i%2 == 0)IDdata.relay = true;elseIDdata.relay = false;//发送的数据 本板id为1 后面可更改为字符串主板---x,y可为控制IDdata.id = 1;IDdata.x = 66;esp_err_t result = esp_now_send(MACC,(uint8_t *)&IDdata,sizeof(IDdata));if(result == ESP_OK)Serial.println("发送成功");else Serial.println("发送失败");delay(10000);}}

另外两块esp32的代码写法也是大同小异,我最后面都包含有的压缩包

esp间的通信完成后,该考虑的就是主esp32与onenet间的数据传输以及esp32与stm32的串口传输,然后onenet平台的搭建,推荐以下这篇博客

/d1ERj

连接完onenet后,可以先尝试一下esp32与其的连接,看看数据是否互通,以下代码也是在csdn上参考一位大哥的,但是现在找不到,挂不了其链接

#include <Arduino.h>#include "WiFi.h"#include "PubSubClient.h"#include "Ticker.h"const char *ssid = "ylmting_PC";//wifi名const char *password = "18811111"; //wifi密码const char *mqtt_server = ""; //onenet 的 IP地址const int port = 1883; //端口号#define mqtt_devid "homedev" //设备ID#define mqtt_pubid "551578" //产品ID//鉴权信息#define mqtt_password "version=-10-31&res=products%2F551578%2Fdevices%2Fhomedev&et=4096342304&method=md5&sign=CCdJNa17tk%2B88nKW0QWHIw%3D%3D" //鉴权信息WiFiClient espClient; //创建一个WIFI连接客户端PubSubClient client(espClient); // 创建一个PubSub客户端, 传入创建的WIFI客户端char msgJson[75]; //发送信息缓冲区//信息模板char dataTemplate[] = "{\"id\":123,\"dp\":{\"Temperature\":[{\"v\":%.2f}],\"Humidity\":[{\"v\":%.2f}]}}"; //Ticker tim1; //定时器,用来循环上传数据//连接WIFI相关函数void setupWifi(){delay(10);Serial.println("连接WIFI");WiFi.begin(ssid, password);while (!WiFi.isConnected()){Serial.print(".");delay(500);}Serial.println("OK");Serial.println("Wifi连接成功");}//收到主题下发的回调, 注意这个回调要实现三个形参 1:topic 主题, 2: payload: 传递过来的信息 3: length: 长度void callback(char *topic, byte *payload, unsigned int length){Serial.println("message rev:");Serial.println(topic);for (size_t i = 0; i < length; i++){Serial.print((char)payload[i]);}Serial.println();}//向主题发送模拟的温湿度数据void sendTempAndHumi(){if (client.connected()){snprintf(msgJson, 75, dataTemplate, 26.0, 50.0); //将模拟温湿度数据套入dataTemplate模板中, 生成的字符串传给msgJson 75为字节数Serial.print("public the data:");Serial.println(msgJson);client.publish("$sys/551578/homedev/dp/post/json", (uint8_t *)msgJson, strlen(msgJson));//发送数据到主题}}//重连函数, 如果客户端断线,可以通过此函数重连void clientReconnect(){while (!client.connected()) //再重连客户端{Serial.println("reconnect MQTT...");if (client.connect(mqtt_devid, mqtt_pubid, mqtt_password)){Serial.println("connected");client.subscribe("$sys/551578/homedev/cmd/request/+"); //订阅命令下发主题}else{Serial.println("failed");Serial.println(client.state());Serial.println("try again in 5 sec");delay(5000);}}}void setup(){Serial.begin(115200); //初始化串口delay(3000); //这个延时是为了让我打开串口助手setupWifi(); //调用函数连接WIFIclient.setServer(mqtt_server, port); //设置客户端连接的服务器,连接Onenet服务器, 使用6002端口client.connect(mqtt_devid, mqtt_pubid, mqtt_password); //客户端连接到指定的产品的指定设备.同时输入鉴权信息if (client.connected()){Serial.println("OneNet is connected!");//判断以下是不是连好了.}client.setCallback(callback); //设置好客户端收到信息是的回调client.subscribe("$sys/551578/homedev/cmd/request/+"); //订阅命令下发主题tim1.attach(10, sendTempAndHumi); //定时每10秒调用一次发送数据函数sendTempAndHumi}void loop(){if (!WiFi.isConnected()) //先看WIFI是否还在连接{setupWifi();}if (!client.connected()) //如果客户端没连接ONENET, 重新连接{clientReconnect();delay(100);}client.loop(); //客户端循环检测 用于检测服务器是否有下发信息}

注意上面那些设备id那些要用自己的哦

连接后,以上esp32-now连接的那仨可以取其中一个,来当作为主esp32用来连接onenet与stm32,将这个连接onenet的代码移植到now连接的代码即可,不过在这里我遇到了第1-2345第5个问题,就是将主esp32 连接wifi后 与另外两个esp32通信的时候,数据就会不稳定,传输时而成功时而失败,最后也只解决了一个次esp32发送数据到主esp32变得稳定.就是将esp32都连接上一个wifi,或者也可以将主esp32设置为ap+sta模式,然后次esp32直接连接主esp32的热点,也就是将那些处于一个wifi组网下。具体的代码资料等我会放在下面。

esp32间的联系完成以及连上onenet平台后实现数据传输后,就可以实现esp32与stm32的串口数据传输了在arduino上可以很方便的实现,

//初始串口Serial2.begin(115200); //于stm32进行串口连接--使用串口2//然后在回调函数处,将数据传输过去即可,不过应当注意你数据传输的协议的//usart2传输协议Temperature:00.00!// Humidity:00.00!(sprintf(usart2send,"Temperature:%0.2f!",board1.Temperature))

而在stm32端,我在这里就讲解普通的版本,在我的代码压缩包里面有一个freeRTOS版,以下是串口中断的处理函数,可以取得上面的Temperature:00.00 字符串

然后在下面调用哪个sscanf就可以得到温湿度的数据啦

void USART3_IRQHandler(void){//判断接收中断标志是否为1if(USART_GetITStatus(USART3, USART_IT_RXNE) == SET){//清空标志位USART_ClearITPendingBit(USART3, USART_IT_RXNE);//接受数据 先赋值再加buffer[count++] = USART_ReceiveData(USART3);//判断接受的字符是否为 '!'if(buffer[count-1] == '!'){//buffer循环赋值给rx_buffer, 但不需要赋值':' 过滤结束标志for(rx_i=0; rx_i<(count-1); rx_i++){rx_buffer[rx_i] = buffer[rx_i];}memset(buffer, 0, sizeof(buffer));//确保下一帧存放位置从buffer[0]开始count = 0;rx_flag = 1;}}}

if(rx_flag == 1){printf("rx_buffer:%s\r\n", rx_buffer);if(strstr(rx_buffer, "Temperature1")){sscanf(rx_buffer,"Temperature1:%f,Humidity1:%f",&Temperature1,&Humidity1);//拼接传输至串口屏的数据sprintf((char *)send_screen_buff,"DHT11.t0.txt=\"%.2f\"\xFF\xFF\xFF",Temperature1);//往串口屏传输数据 USART_SendString(USART2, send_screen_buff);//延时2ms,确保数据已到位delay_ms(2);//清空字符串memset(send_screen_buff, 0, sizeof(send_screen_buff));//拼接湿度数据sprintf((char *)send_screen_buff,"DHT11.t1.txt=\"%.2f\"\xFF\xFF\xFF",Humidity1);USART_SendString(USART2, send_screen_buff);memset(send_screen_buff, 0, sizeof(send_screen_buff));}if(strstr(rx_buffer, "Temperature2")){sscanf(rx_buffer,"Temperature2:%f,Humidity2:%f",&Temperature2,&Humidity2);//拼接传输至串口屏的数据sprintf((char *)send_screen_buff,"DHT11.t2.txt=\"%.2f\"\xFF\xFF\xFF",Temperature2);//往串口屏传输数据 USART_SendString(USART2, send_screen_buff);//延时2ms,确保数据已到位delay_ms(2);//清空字符串memset(send_screen_buff, 0, sizeof(send_screen_buff));//拼接湿度数据sprintf((char *)send_screen_buff,"DHT11.t3.txt=\"%.2f\"\xFF\xFF\xFF",Humidity2);USART_SendString(USART2, send_screen_buff);memset(send_screen_buff, 0, sizeof(send_screen_buff));}printf("Temperature1:%.2f,Humidity1:%.2f",Temperature1,Humidity1);//清空数组memset(rx_buffer, 0, sizeof(rx_buffer));rx_flag = 0;}

上面就是串口的处理函数,串口2是我连接的一个串口屏。

然后还有一个通过感受光照强度来控制led开关的,因为光敏电阻遇到光得话,阻值会降低,所有我们可以通过ADC来获取其变化,得到那个值,然后根据哪个值来控制灯得开关,这个比较简单。

然后还有一个串口屏传输数据过来时吗,用的中断大同小异,可以根据上面那个串口中断函数自行修改。

if(rx_flag_screen == 1){printf("rx_buffer_screen:%s\r\n", rx_buffer_screen);USART_SendString(USART3, rx_buffer_screen);//清空数组memset(rx_buffer_screen, 0, sizeof(rx_buffer_screen));rx_flag_screen = 0;}

上面用到得一个串口传输字符串得函数是

void USART_SendString(USART_TypeDef * pUSARTx, char *str){unsigned int k=0;while(*(str+k)!='\0'){// 发送一个字节数据到USART USART_SendData(pUSARTx, *(str+k));// 等待发送数据寄存器为空while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);k++;}while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET); /* TC:传输完成标志 */}

这个比较通用,可以用在所有串口传输的地方上,建议背诵全文哈哈。

以上还有很多没有讲到的地方。但是暂时没想起来 有什么不了解得欢迎过来一起交流

这个是云平台得最终效果

知识无价,欢迎分享。

链接: /s/1-veegbGcjwog4RjVP3MMGQ?pwd=2326 提取码: 2326 复制这段内容后打开百度网盘手机App,操作更方便哦

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。