从零开始开发物联网项目(6)——Arduino和ESP8266自动数据上传终端

2023-05-16

前面几节介绍了Mqtt协议以及用ESP8266模块作为客户端连接Mqtt服务器并实现数据的发布和订阅。这一节我们就正式的开始制作第一个物联网终端,基于Arduino和ESP8266模块。之所以选择了Arduino是因为它的开发比较方便,并且后期直接可以自己用Atmega芯片搭建最小系统来实现终端的产品化。

以下就是基于Arudino和ESP8266的自动数据采集和上传终端,前期为了调试数据的需要,我直接使用了Arduino mega2560,因为它有多个串口可以使用,当然Arduino UNO也完全没问题,但是由于只有一个硬串口,而软串口支持不了115200波特率,所以ESP模块只能接在硬串口上了,这就导致前期用UNO来开发就会很麻烦,每次改程序就要拔掉ESP模块。所以直接用了2560开发就方便多了。

硬件的连接非常的简单,我这里将ESP模块接到了串口1上,所以接线为:

Esp8266 Arduino Mega2560

Vcc ------------- 3V3

CH_PD ------------ 3V3

GND ------------- GND

URXD ------------- TXD1

UTXD ------------- RXD1

我上传的数据为模拟口A0采集到的模拟电压值,你可以接一个Lm35温度传感器上去,不过我这里仅仅为了测试Mqtt数据传输,就不接了,所以每次测量出来的数据都是随机的。

下面主要就是程序了,思路也很简单,就是完全模拟上一节时手动输入AT指令和Mqtt指令,只不过交由程序来自动实现罢了,好了,直接看程序吧,具体细节我也直接写在程序的注释里了。

//注意,本程序需要Arduino mega2560
//下面填入你自己的IP地址
String tcplinkstr = "AT+CIPSTART=\"TCP\",\"10.0.0.252\",1883";
//你的wifi名称
String wifiname = "******";
//wifi密码
String wifipsd = "******";
String wifilinkstr, tempstr,constr = "";
//mqttlink为mqtt连接指令,参考之前的内容
unsigned char mqttlink[27] = {0x10, 0x19, 0x00, 0x06, 0x4d, 0x51, 0x49, 0x73, 0x64, 0x70, 0x03, 0xc2, 0x01, 0x2c, 0x00, 0x05, 0x4d, 0x61, 0x6b, 0x65, 0x72, 0x00, 0x01, 0x72, 0x00, 0x01, 0x72};
//mqttsubscribe为mqtt数据发布指令,同样参考之前的,这里发送的数据为"t:****",采集到数据后替换掉*
unsigned char mqttpublish[13] = {0x32, 0x0b, 0x00, 0x01, 0x72, 0x00, 0x01, 0x74, 0x3a, 0x2a, 0x2a, 0x2a, 0x2a};
unsigned char mqttheart[2] = {0xc0, 0x00};
unsigned char mqttdata[4];
int mi = 0, sndi = 0, mode = 0, at = 0, espok = 0, temp,rtn;
long timenow, timebefor = 0, tm;


void setup() {
 //连接电脑串口,用于程序编写时观察程序的运行
  Serial.begin(9600);         
  //用于连接esp8266      
  Serial1.begin(115200);            
 //用于连接wifi的AT指令
  wifilinkstr = "AT+CWJAP=\"";        
  wifilinkstr += wifiname;
  wifilinkstr += "\",\"";
  wifilinkstr += wifipsd;
  wifilinkstr += "\"";
   //通电后等待一段时间让esp8266启动完毕      
  delay(5000);                       
 //一通电就发送网络状态查询,因为esp8266会自动记录wifi,所以可能一开机就连接上了wifi
  Serial1.println("AT+CIPSTATUS");  
}
//*******以下为loop主程序,主要用mode来判断程序此刻的功能*********
void loop() {
 //mode=0时为连接tcp服务器状态,此时为AT指令阶段,esp8266返回的都是字符串
  if (mode == 0) {      
//读取来自串口1的数据,来自esp8266,最后存在constr字符串中             
    while (Serial1.available())      
    {
      constr += char(Serial1.read());
      delay(2);
    }
 //如果constr字符串有数据了,则运行tcplink程序
    if (constr.length() > 0)         
    {
      tcplink();             
    }
  }
   //已经进入透传模式可以发送数据
  else if (mode == 1) {     
  //当接收mqtt服务器返回的数据时是16进制      
    while (Serial1.available())    
    {
//将读取的16进制数据保存到mqttdata数组中
      mqttdata[mi] = byte(Serial1.read());        
      mi++;
      delay(2);
    }
    mqttsend();
  }
}
//************tcplink程序,主要用于esp8266AT模式时与模块的互动******
void tcplink() {
  if (espok == 0)
  {
//用于相应网络连接信息返回值,2、4说明wifi已经连上
    if (constr.indexOf("STATUS:2") || constr.indexOf("STATUS:4"))       
    {
      Serial.println("STATUS:2、4");
      delay(500);
  //直接让at=4,跳过连接wifi的AT指令
      at = 4;                
 //有返回说明esp8266模块没问题                   
      espok = 1;           
  //进入AT发送指令程序,由at值来决定发哪句                    
      esp8266at(at);                           
    }
 //5说明WiFi还没有连上,需要从头开始AT指令
    else if (constr.indexOf("STATUS:5"))       
    {
      Serial.println("STATUS:5");
      delay(500);
      at = 1;
      espok = 1;
      esp8266at(at);
    }
//3说明TCP已经连上,直接进入透传模式即可
    else if (constr.indexOf("STATUS:3"))       
    {
      Serial.println("STATUS:3");
      delay(500);
      at = 7;
      espok = 1;
      esp8266at(at);
    }
  }
  else
  {
//如果模块返回OK,则继续下一条AT指令
    if (at < 6 && constr.indexOf("OK"))            
    {
      Serial.println("OK");
       //收到返回后到下一条需要延时一段时间,不然esp模块会反应不过来  
      delay(500); 
      at++;
//执行AT指令
      esp8266at(at);
      }
//当AT指令到第6条也就是连接TCP服务器后,返回CONNECT说明连接成功
    else if (at == 6 && constr.indexOf("CONNECT"))     
    {
      Serial.println("CONNECT");
      delay(500);
      at++;
      esp8266at(at);
    }
//当AT指令到第6条也就是连接TCP服务器后,返回CLOSED说明连接不成功,at不增加,会再次连接
    else if (at == 6 && constr.indexOf("CLOSED")) 
    {
      Serial.println("CLOSED");
      delay(500);
      esp8266at(at);
    }
//连接成功后收到">"说明进入了透传模式
    else if (at == 7 && constr.indexOf(">"))     
    {
      Serial.println("TCPlinked!");
      delay(1000);
 //模式mode=1,进入了mqtt数据发送模式
      mode = 1;                                
    }
  }
  constr="";//每次处理完数据都要清空
}
//***********************mqtt数据发送**********
void mqttsend() {
//用于计时,从而实现每隔一定时间发送一个数据
  timenow = millis();                     
  tm = timenow - timebefor;    
  temp = analogRead(A0);                   //采集模拟口A0的数据
  tempstr = String(temp);                //将采集到的数据变成字符串
  int mqtti = tempstr.length();          //读取字符串长度
  String mqttch; 
  //下面的程序用来将采集到的数据添加到mqtt发送的16进制数组中
  for (int j = 0; j < mqtti; j++)             
  {
    mqttch = tempstr.substring(j, j + 1);
//将字符转变为ascii码的16进制
    mqttpublish[j + 9] = chartobyte(mqttch);    
  }
  for (int j = mqtti; j < 4; j++)
  {
 //为了mqtt数据发送方便,这里控制发送的字符数每次都相同,后面非数字部分用“*”来填充
    mqttpublish[j + 9] = 0x2a;                   
  }
 //如果是刚进入透传模式
  if (sndi == 0)                              
  {
    Serial.print("send mqttlink");
//发送mqtt的连接指令,由于是16进制发送,这里需要用到write
    Serial1.write(mqttlink, 27);               
    sndi = 1;
  }
  if (tm > 10000)                            //每次计时到10秒时
  { 
    Serial1.write(mqttheart, 2);             //发送心跳指令
    timebefor = millis();
  }
  if (mi > 0)                             //如果收到了mqtt服务器返回的数据
  {
    mi = 0;
//方便起见,只判断返回数据的第一位
    if (mqttdata[0] == 0x20 || mqttdata[0] == 0xd0)     
    {
      Serial1.write(mqttpublish, 13);         //发布数据
    }
 //由于用了QoS=01,所以mqtt服务器会返回数据
    else if (mqttdata[0] == 0x40)               
    {
      timebefor = millis();                     //收到数据后重新计时
    }
  }
}
//*****************esp8266AT指令**********************
void esp8266at(int eat)
{
  switch (eat) {
    case 0: {
        Serial1.println("AT");            //测试模块是否正常
      } break;
    case 1: {
        Serial1.println("AT+CWMODE=1");    //设置模块模式
      } break;
    case 2: {
        Serial1.println(wifilinkstr);             //连接WIFI路由器
      } break;
    case 3: {
        Serial1.println("AT");     //查询
      } break;
    case 4: {
        Serial1.println("AT+CIPMUX=0");   //设置单连接
      } break;
    case 5: {
        Serial1.println("AT+CIPMODE=1");   //设置传输模式为透传
      } break;
    case 6: {
        Serial1.println(tcplinkstr);         //连接tcp服务器
      } break;
    case 7: {
        Serial1.println("AT+CIPSEND");         //进入tcp透传模式
      } break;
  }
}
//*******************字符转换为asscii码,用于mqtt数据发送*****
unsigned char chartobyte(String chr) {
  if (chr == "#")
    return 0x23;
  else if (chr == ":")
    return 0x3a;
  else if (chr == "$")
    return 0x24;
  else if (chr == "0")
    return 0x30;
  else if (chr == "1")
    return 0x31;
  else if (chr == "2")
    return 0x32;
  else if (chr == "3")
    return 0x33;
  else if (chr == "4")
    return 0x34;
  else if (chr == "5")
    return 0x35;
  else if (chr == "6")
    return 0x36;
  else if (chr == "7")
    return 0x37;
  else if (chr == "8")
    return 0x38;
  else if (chr == "9")
    return 0x39;
  else if (chr == "@")
    return 0x40;
}

将程序写入Arduino,然后打开emqx的websocket页面,连接上后订阅一个主题为“r“的消息,然后将Arduino断电再通电,就可以在页面上观察来自Arduino的消息了,当然你也可以在手机端订阅,同样可以收到消息。

由于没有使用任何的库函数,所以程序看起来有点长,不过各位同学正好可以了解清楚程序运行的全部过程。如果你使用了Arduino UNO模块的话,可以将程序中的Serial1全部改成Serial就可以了,当然还得把原来的Serial全部删除。

好了,这就是Arduino和ESP8266通过Mqtt服务器自动上传数据的终端示例,你可以接入自己的传感器,上传自己的数据。

现在虽然有了上传数据的终端,可是数据并没有保存起来。并且需要开启一台电脑来作为Mqtt服务器,也有点浪费,下一节我会来介绍如何使用一台树莓派来作为Mqtt服务器,再之后我们用Python编写一个小程序来将Arduino上传的数据存储到Mysql数据库里面,这样一个自动采集数据的物联网项目才能算完整!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从零开始开发物联网项目(6)——Arduino和ESP8266自动数据上传终端 的相关文章

  • Arduino Python3 脚本

    我正在尝试使用 Python3 脚本来控制 Arduino Mega 这是一个简单的脚本 用于从键盘获取一行并通过 Arduino 回显它 我从一个可用的 Python 2 脚本开始http petrimaki wordpress com
  • 蓝牙 HC-05 发送错误 1F 仅适用于 INQ 命令

    我的新蓝牙 HC 05 模块有问题 在 AT 模式下 它可以与我需要的所有命令完美配合 除了 INQ 我已经尝试事先发送一大堆其他命令 AT INIT OK AT ORGL OK AT ROLE 1 OK AT CLASS 0 OK 他们都
  • 经典蓝牙 (2.1) 设备可实现的最小数据包延迟是多少?

    我正在使用 RN42 http www microchip com wwwproducts en RN42 http www microchip com wwwproducts en RN42 蓝牙模块以 115200 波特率 UART S
  • Python自动选择串口(适用于Arduino)

    目前 Python 程序必须知道设备 Arduino 位于哪个端口 然后 Python 才能与设备进行通信 Problem 每当设备拔出并重新插入时 其 COM 端口都会发生变化 因此必须再次向 Python 提供正确的串行端口 以便它找到
  • 同时使用 GPRS 和 GSM

    我正在尝试使用 GSM GPRS 调制解调器的 GPRS 功能将数据发送到远程服务器 但我无法这样做 我在 Arduino 论坛上发布了一个问题 但没有得到任何回复 这是问题的链接 https robotics stackexchange
  • 静态 uint8_t 数组的输入过程和类型

    我目前正在尝试将 Arduino IDE 中的整数变量转换为静态 uint8 t 数组的值 我在用 include
  • ESP32 Arduino-ide如何获取唯一id

    我试图自动为每个 esp32 设置一个唯一的 id 在我使用提供该方法的 ESP IDF 框架对设备进行编程之前esp efuse mac get default 这将返回一个 8 字节值 该值在我手上的所有设备上都是唯一的 在arduin
  • 使用串口通过 Arduino 将多个值发送到 Raspberry

    我有一个关于 Arduino 和 Raspberry Pi 之间串行通信的问题 事实上 我想使用 Arduino 将 2 个变量发送到 Raspberry Pi 并以不同的方式使用它们 这是我的 Arduino 草图 int one 1 i
  • Arduino:连接字符串时崩溃和错误

    我尝试将 AES 256 加密的输出连接到一个字符串 将此字符串与从 Android 手机发送的加密字符串进行比较 基本上 连接似乎有效 但在几次运行后会出现错误 不可读的字符 字符串变得更短而不是更长 或崩溃 它是可重现的 重启后在同一点
  • 使用 Java 控制 Arduino

    我正在寻找一个LED http en wikipedia org wiki Light emitting diode用Java程序打开和关闭 我用 C 完成了这个项目大约 5 分钟 但用 Java 似乎更具挑战性 我让 Arduino 等待
  • 使用 Ardulink 命令 Arduino Uno

    我试图在我的 JAVA 应用程序中使用 Ardulink 库来命令我的 Arduino Uno 但没有成功 我不知道我错过了什么 这是我的代码 Link link Link getDefaultInstance boolean connec
  • 编译器:如果条件始终为真/假怎么办

    我想到了条件和编译器 我正在为 Arduino 编写一个应用程序 因此我需要该应用程序尽可能快 在我的代码中我有这个 define DEBUG false if DEBUG String pinName pinName Pin pinNam
  • Arduino C++ 代码:可以使用虚函数和异常吗?

    跟进这条评论 https stackoverflow com questions 452139 writing firmware assembly or high level 452401从问题中编写固件 汇编还是高级 https stac
  • 在链接时合并全局数组/从多个编译单元填充全局数组

    我想定义一系列的东西 比如事件处理程序 的内容 该数组在编译时是完全已知的 但定义在 多个编译单元 分布在多个库中 至少在最终 静态 链接之前是相当解耦的 我想要 也保持这种方式 因此添加或删除编译单元将 还可以自动管理事件处理程序 而无需
  • Arduino Nano 33 IoT 的软件序列号

    我计划从旧的 5V Arduino Nano 迁移到新的 Arduino Nano 33 IoT 我已经使用软件串行 SoftwareSerial h 为旧的 5V Arduino Nano 编写了一个功能代码 以便与 Sim800L 模块
  • 无法将 minicom 的输出保存到文件中

    当我使用Minicom从串口捕获数据时 我需要将大数据保存到一个文件中 名为minicom cap 但是 如果我按 Ctrl A 和 L 来捕获文件 则失败 没有创建文件 minicom cap之前并不存在 我的下载目录已正确创建 我的操作
  • 云到设备 Azure IoT REST API

    我探索了如何使用 Azure REST API 将数据从设备发送到云 它运行无缝 没有任何问题 我没有找到有关使用 Azure IoT Hub REST API 向 Arduino 板发送云到设备消息的好文章 有人可以就此提供建议吗 您还可
  • Arduino CLI 编译器“ino”和一些基本草图导致编译错误

    我正在尝试使用 cli 编译器 ino 编译基本的以太网 UDP Sketch 我从他们的 github 存储库下载了最新版本 ino init然后是 src sketch ino 的内容 include
  • 无法访问超过 255 个的 Modbus 寄存器 SimpleModbus

    我是法国学生 我已经使用 SimpleModbus 1 周了 它工作得很好 直到我尝试实现一个具有大量寄存器 1000needed 使用从站 1 无法访问超过 255 个的寄存器 无论我做什么 一旦寄存器读数超过 255 我就会收到超时错误
  • Arduino 引导加载程序

    有人可以解释一下如何Arduino引导加载程序 http code google com p arduino source browse tags 0019 hardware arduino bootloaders atmega ATmeg

随机推荐

  • Matlab转C++代码入门————附带详细代码和示例

    文章目录 1 转换1 1 转换例子1 2 详细转换过程 2 注意事项3 实例 1 转换 一般Matlab中的代码 xff0c 有一部分方法是无法转换成C 43 43 的 xff0c 例如图像化UI 文件写出等接口 一般做转换的话 xff0c
  • ‘CMRESHandler‘ object has no attribute ‘_timer‘,socket.gaierror: [Errno 8] nodename nor servname pro

    文章目录 1 错误重现2 解决3 调用方法写入es4 扩展 1 错误重现 在Mac上调用Python的CMRESHandler进行elasticsearch的日志写入时 xff0c 遇到如下错误 一开始还以为是自己的语法出现了错误 xff0
  • Python写入日志到Elasticsearch(logging/loguru,可个性化定制写入信息)————附带详细代码和示例

    文章目录 0 结果1 准备2 调用2 1 调用方法1 xff08 使用logging xff09 2 2 调用方法2 xff08 使用logging xff0c 并使用配置 xff09 2 3 调用方法3 xff08 使用loguru xf
  • C++改写Matlab源码实践一之【显示图片】——————附带详细讲解和示例

    文章目录 0 背景1 Matlab有用代码提取2 转换为C 43 43 3 使用纯C 43 43 实现mat数据中的图片显示4 代码封装5 福利其他 0 背景 这里以显示Matlab变量struct中的图片程序代码为例 xff0c 示范如何
  • C++/Java调用C++动态链接库————附带示例和详细讲解

    文章目录 0 准备1 C 43 43 调用动态链接库2 Java调用C 43 43 动态链接库3 运行 0 准备 在CMake中 xff0c 使用如下的方法把代码编译成动态 静态链接库 xff1a span class token comm
  • 什么变量存放在栈和堆

    内容会持续更新 xff0c 有错误的地方欢迎指正 xff0c 谢谢 什么是栈区 xff0c 什么是堆区 栈区 xff08 stack xff09 xff1a 由编译器自动分配释放 xff0c 存放函数的参数值 局部变量的值等 xff0c 内
  • C++改写Matlab源码实践二之【传递表格数据】————附带详细讲解和示例

    文章目录 0 背景1 Matlab有用代码提取2 转换为C 43 43 2 1 设定变量类型2 2 预先和定义声明变量 3 改写转换后的C 43 43 代码3 1 指定输入的文件3 2 改写处理 96 Data 96 和 96 Data1
  • Kylin4.0下载安装指南———附带详细安装过程

    文章目录 0 结果1 下载1 1 下载kylin1 2 下载spark1 3 jdk hadoop hive zookeeper安装1 4 Mysql安装 2 配置Mysql数据存储2 1 配置mysql2 2 配置Zookeeper2 3
  • 2023年的专业408算法题

    文章目录 0 结果1 题目2 思路3 实现附录 0 结果 1 题目 对于一个有向图 xff0c 如果一个顶点的出度大于入度 xff0c 则这个顶点称为K顶点 有向图用邻接矩阵存储 xff0c 数据结构定义如下 xff1a span clas
  • 专业408历年算题大全(2009~2023年)——附带详细代码和多种思路

    文章目录 1 题型总结1 1 线性表 xff08 6年 xff09 1 1 1 常用思想 1 2 链表 xff08 4年 xff09 1 2 1 常用思想 1 3 树 xff08 3年 xff09 1 3 1 常用思想 1 4 图 xff0
  • 2022年专业408算法题

    文章目录 0 结果1 题目2 思路3 实现3 1 思路一 xff08 中序遍历搜查搜索数 xff09 3 2 思路二 xff08 二叉搜索树的定义 xff09 附录 0 结果 1 题目 2 思路 1 xff0c 首先明确二叉搜索树的定义 x
  • 2021年专业408算法题

    文章目录 0 结果1 题目2 思路3 实现附录 0 结果 1 题目 2 思路 遍历邻接矩阵的每一行和列的非零元素的个数 xff0c 来统计每个顶点的度 xff08 出度和入度和 xff09 xff0c 并记录度为奇数的顶点个数 xff0c
  • jetbrains软件打开后突然闪退

    文章目录 0 背景1 错误重现2 错误原因3 解决方法 0 背景 在使用jetbrains编程软件时 xff0c 突然出现打开就闪退的情况 一开始还以为是系统升级到macOS13 1的原因 xff0c 经过查阅网上资料 xff0c 发现ma
  • 2011年专业408算法题

    文章目录 0 结果1 题目2 思路2 1 思路1 xff08 暴力解 xff1a 排序 xff09 2 2 思路2 xff08 较优解 xff1a 归并合并数组 xff09 2 3 思路3 xff08 较优解 xff1a 数组指针后移 xf
  • 2014年408专业算法题

    文章目录 0 结果1 题目2 思路附录 0 结果 1 题目 2 思路 二叉树的带权路径长度 xff08 WPL xff09 的计算方法有两种 xff1a 1 xff0c 定义 xff1a W P L 61
  • 2016年专业408算法题

    文章目录 0 结果1 题目2 思路2 1 思路1 xff08 较优解 xff1a 排序 xff09 2 2 思路2 xff08 最优解 xff1a 类快排思想排序 xff09 附录 0 结果 较优解 xff1a 最优解 xff1a 1 题目
  • 2017年408专业算法题

    文章目录 0 结果1 题目2 思路附录 0 结果 1 题目 2 思路 因为要转换为中序表达式 xff0c 因此使用中序遍历 在中序遍历的过程中 xff0c 对于当前访问的非空结点p xff0c 则先输出 34 xff0c 然后递归调用左子树
  • Python面向对象编程

    文章目录 1 作用域1 1 局部作用域 2 类成员权限3 是否继承新式类4 多重继承5 虚拟子类6 内省 在运行时确定对象类型的能力 7 函数参数8 生成器 1 作用域 1 1 局部作用域 1 xff0c 当局部变量遮盖全局变量 xff0c
  • 增大整数———晴问算法

    文章目录 1 题目2 思路3 代码 1 题目 2 思路 首先把数字n转化为字符串s xff0c 然后把第一个字符转换为数字得到正整数的首位 如果输入的数位a大于首位 xff0c 则把字符串s拼接在字符串化的数位后面形成新字符串ans xff
  • 从零开始开发物联网项目(6)——Arduino和ESP8266自动数据上传终端

    前面几节介绍了Mqtt协议以及用ESP8266模块作为客户端连接Mqtt服务器并实现数据的发布和订阅 这一节我们就正式的开始制作第一个物联网终端 xff0c 基于Arduino和ESP8266模块 之所以选择了Arduino是因为它的开发比