【发布时间】:2019-08-08 05:54:33
【问题描述】:
我创建了一个 Windows 窗体,我打算使用它从数据记录 Arduino 中提取数据。目前,Arduino 上安装了一个 SD 卡,其中有一个包含我想要接收的数据的日志文件。使用 Arduino IDE 串行监视器,我能够测试发送和接收串行数据。 Ardunio 草图等待一个“r”字符,一旦接收到它,它将日志文件中的所有数据发送到串行监视器。这已经过测试,并且在 Arduino IDE 中 100% 的时间都可以工作。我现在有一个 Windows 窗体 GUI,允许将数据直接读取到 PC 上的日志文件中,而无需移除 SD 卡(这是有必要的原因)。我连接到串行端口没有问题,并且读取数据似乎没有问题,直到我进入文件的一些方法。
将读取的数据输出到列表框时,我注意到它会在文件结束之前停止。假设这可能是一个多线程问题,我决定尝试直接写入文件而不是更新 GUI。这也失败了,在检查创建的日志文件时,我注意到有时它会包含数据,有时它不会。然后,我没有尝试读取整个文件,而是开始尝试仅读取一定数量的数据。在程序无法持续读取数据之前,我最多可以读取大约 110 行数据。当程序失败,我关闭它时,查看日志文件显示我在文件中有 2048 个字符,这是串口的写缓冲区大小。更改此数字会导致字符数与缓冲区大小相匹配。在每次写入文件后尝试刷新数据会导致文件中剩余的字符数看起来是随机的,而不是与缓冲区大小匹配。
VB 代码:
Public Class mainForm
Public Shared logFile As System.IO.StreamWriter
Public Shadows num As Int16 = 0
'this is the sub that checks for serial data and is writing the read data to the previously created log file
Private Sub SerialPort_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles serialPort.DataReceived
Dim readData As String = serialPort.ReadLine()
num += 1
If readData = "EOF" Then
logFile.Close()
MsgBox("Done")
End If
logFile.Write(readData)
If num = 110 Then
MsgBox("Done")
serialPort.Close()
logFile.Close()
End If
End Sub
'this sub allows the user to connect to the correct serial port
'I'm almost positive the problem does not lie here
Private Sub BtnConnect_Click(sender As Object, e As EventArgs) Handles btnConnect.Click
serialPort.Close()
Dim comPortName As String = "COM" + txtComPort.Text
serialPort.PortName = comPortName
Try
serialPort.Open()
lstLog.Items.Add("Connected to serial port " + comPortName)
Catch
lstLog.Items.Add("Could not connect to serial port " + comPortName)
End Try
End Sub
'this sub creates the log file and sends the 'r' to the Arduino to begin reading the sd card
Private Sub BtnReadData_Click(sender As Object, e As EventArgs) Handles btnReadData.Click
logFile = My.Computer.FileSystem.OpenTextFileWriter("C:\Users\AHNEHR\Documents\Docs\test1.txt", True)
serialPort.WriteLine("r")
End Sub
End Class
Arduino 草图:
#include <SdFat.h>
#include <SPI.h>
const int relayPin = 9;
const int sdChip = 10;
SdFat sd;
SdFile dataLog;
void setup() {
Serial.begin(115200);
pinMode(relayPin,OUTPUT);
}
void loop() {
if (Serial.available()) {
char data = Serial.read();
if (data == 'r') {
if (!sd.begin(sdChip)) {
Serial.println("Failed to Initialize SD Card");
}
else Serial.println("SD Card Initialized");
if (!dataLog.open("log.txt", O_READ)) {
Serial.println("Failed to open file.");
}
else Serial.println("Opened Log");
while (dataLog.available()) {
Serial.write(dataLog.read());
}
Serial.println("EOF");
dataLog.close();
}
}
}
“如果 readData = EOF”应该检查文件的结尾,因为一旦整个日志文件输出到串行,Arduino 草图就会写这个,但我从来没有在那里,所以另一个 if 语句检查读取完成的次数,如果为 110,则停止。对于小于 100 的数字,我将所有数据写入日志文件没有问题,但是一旦达到 100-110 左右,程序就会开始出现故障.
SD卡上日志文件中的数据格式如下:
2019 年 8 月 4 日 06:57 T:ERRC P:ERRpsi
2019 年 8 月 4 日 06:58 T:ERRC P:ERRpsi
而且我希望创建的日志文件直接匹配 sd 卡上的日志文件,但是我得到大约 80/90 行匹配,并且程序停止工作并且不会继续写入日志文件。我相信 sd 卡上的日志文件总共有大约 900 行。我的vb技能不是很好,所以我希望我缺少一些明显的东西,但是我已经尝试了我所知道的一切,不知道为什么我只能读取一些串行数据。非常感谢任何帮助弄清楚为什么会发生这种情况以及如何解决它。
*编辑:我还确保 Arduino 草图和串口的波特率匹配为 115200。经过更多测试,这似乎是串口的问题,而不是文件的问题。
【问题讨论】:
-
你已经发现了问题。您希望 Arduino 和 Windows 完美同步,而在现实世界中,任何一方的轻微滞后或延迟可能会产生意想不到的结果,并且概率是累积的,这就是为什么它总是在一段时间后发生。您必须在每行或多行之后实现流控制,以确保 arduino 等待窗口完成并准备好接收。
-
是的,正如@AlessandroMandelli 指出的那样,这似乎是一个时间问题。从 Windows 窗体接收到“r”命令后,我只会发送一行。然后,当 Windows 窗体处理完这一行时,它会发送一个新命令“r”。
-
我认为在您的
SerialPort_DataReceived事件中,您会想要使用serialPort.ReadExisting()而不是serialPort.ReadLine()。可能有不止一行可供阅读。或者完整的行可能不可用,ReadLine调用将阻塞,直到收到完整的行。 docs.microsoft.com/en-us/dotnet/api/… -
@B.Letz 我现在已经编辑了 Windows 表单和 Arduino 草图,所以现在草图在接收到“r”命令时一次只发送一行,我发送“r” ' 每次在 Windows 端写入后的命令。这和以前有同样的问题。我可以反复单击读取按钮并最终到达文件末尾,但它只适用于不同大小的小块。我应该上传这个修改后的代码版本吗?对于什么可能会有所帮助,您还有其他想法吗?
-
你还是做错了。除非已经有一行可供读取,否则您无法读取一行。因为在 115200 一位是 1e-5 秒,1 个字节是 1e-4 秒,所以在尝试读取之前,您必须每 10 个字节至少等待 1ms。因此,作为第一次尝试,在 readline 之前放置一个 Thread.Sleep(10)。
标签: vb.net winforms logging arduino serial-port