上一期我们使用MQTT协议连接到百度云并且向C#的客户端上传了我们的数据。
我之后也成功使用ESP32上传数据到MQTT服务器,在C#中显现折线图,但是随之而来的我们发现了新的问题:这消息量好像有点庞大了
短短的测试环节我就发送了将近20w条消息(幸亏我关的早),于是当机立断选择放弃使用MQTT协议,改用其他协议来传输数据。
MQTT协议适合小型数据量的传输,那么对于我们这么庞大的数据量来说确实不太适合,于是我们选择常用的超文本传输协议:HTTP来传输我们的数据。
** HTTP简单介绍 ** HTTP由三个部分组成:
** 起始行(start line) ** :描述请求或响应的基本信息;
** 头部字段集合(header) ** :使用 key-value 形式更详细地说明报文;
** 消息正文(entity) ** :实际传输的数据,它不一定是纯文本,可以是图片、视频等二进制数据。
起始行中我们需要确定我们的HTTP是进行请求还是发送。
这里不细细赘述如何具体使用HTTP报文的详细,我们简单的介绍一下在ESP32中如何使用HTTP。
** HTTP发送 **
首先,我们在Arduino IDE中安装我们的HTTP相关的库,我们在库管理中搜索HttpClient安装相关库。
其次按win+R调出命令窗口,输入cmd并运行调出终端面板,之后输入ipconfig查询我们的电脑IP
在IPv4的地址中(任意一个)查看我们的局域网IP地址
我们在ESP32中保存我们的Wifi用户名,Wifi密码还有我们刚才的IP地址,注意加上https://pic.qr2c.cn/strong>
void WIFIConnect(){ WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } Serial.print("IP Address: "); Serial.println(WiFi.localIP()); Serial.println("Connected to WiFi");}
我们定义一个函数来连接我们的Wifi,因为我们使用的ESP32的定时器2,使用Wifi的时候不能
使用ESP32的ADC2,因此我们使用ADC2的时候我们需要关闭我们的Wifi。
String postData = ""; for (int i = 0; i < 1000; i++) { dataArray[i] = analogRead(13); postData += String(dataArray[i]); if (i < 1000-1) { postData += ","; } delay(5); }
我们定义一个数组dataArray,用这个数组存放我们的ADC采集数据,接着我们将数据存到postData变量中,并且加上分隔符号方便我们在C#中分离数据。
WIFIConnect();//连接Wifi
HTTPClient http;//创建HTTP句柄 http.begin(serverUrl);//启动HTTP,参数为IP地址 http.addHeader("Content-Type", "text/plain");//设置我们的请求头 int httpResponseCode = http.POST(postData);//发送我们的数据
我们利用上述代码利用HTTP传输我们的数据,最后利用httpResponseCode变量接收HTTP的返回(响应)
http.end();
WiFi.disconnect(true);
最后关闭HTTP连接和WiFi,保证我们下一次循环的ADC采集可以正常进行。 C#上位机代码编写
我们修改之前的代码,利用httpListener方法创建一个我们的Http句柄,并且输入我们的监听端口。
之后用异步的方式开启我们的监听函数,这个函数是我们自己定义的ListenForHttpRequests()
private void InitializeHTTPClient() { // 请确保端口未被占用,如果被占用,请更改端口 string url = "https://pic.qr2c.cn/"; httpListener = new HttpListener(); httpListener.Prefixes.Add(url); httpListener.Start();
// 异步处理请求 Task.Run(() => ListenForHttpRequests()); }
接着我们定义我们的监听函数,我们在监听函数中解析我们的数据。
private void HandleHttpRequest(HttpListenerContext context) { try { // 从请求中获取数据 Stream body = context.Request.InputStream; Encoding encoding = context.Request.ContentEncoding; StreamReader reader = new StreamReader(body, encoding);
if (context.Request.HasEntityBody) { string postData = reader.ReadToEnd(); Console.WriteLine($"Received data from ESP32: {postData}");
// 将以逗号分隔的多个数值解析为数组 string[] values = postData.Split(',');
Invoke((MethodInvoker)delegate { for (int i = 0; i < values.Length; i++) { if (double.TryParse(values[i], out double value)) { chart1.Series[0].Points.AddXY(chart1.Series[0].Points.Count + 1, value*3.3/4096); } } chart1.Refresh(); }); }
// 发送响应 string responseString = "Data received successfully"; byte[] buffer = Encoding.UTF8.GetBytes(responseString); context.Response.ContentLength64 = buffer.Length; Stream output = context.Response.OutputStream; output.Write(buffer, 0, buffer.Length);
// 关闭连接 output.Close(); } catch (Exception ex) { Console.WriteLine($"Error handling request: {ex.Message}"); } }
这里需要注意的是我们在非UI线程中修改我们的chart对象是需要加上 Invoke((MethodInvoker)delegate
进行的,并且我们成功收到消息后我们也应该向发送者回复对应的回复。 接着运行我们的程序我们可以看到我们的波形成功的显示在我们的示波器上。
这个本地/云端的启动没加上去,主要展示一下主界面。 问题阐述
我 们的代码有一个很大的问 题就是采样不能实时性,我们在采集的 过程中不能发送我们的数据,并且 我们的
需要关闭一段时间的ADC来发送我们的数据,这就必然会导致我们的采样出现数据欠缺。
并且现在我们的数据传输是在局域网中进行的,我们后期可能要进行内网穿透以及域名注册,将我们的端口连接到公网上。
下期我们探讨,使用FreeRTOS在ESP32的部署是否能够解决这个问题。