我有一个程序,用于从串口读取数据,将其显示在图表上并允许保存。这些数据只是逐个发送的uint64号码。数据发送速度非常快(每秒多次)。
目前,数据被读入数据表,此功能在datareceivedhandler事件方法中完成,该方法在接收数据时自动触发。
我希望得到以下内容:
任何不在所选时间/捕获范围内的数据都应该被丢弃(或者从不首先捕获)。应该有一个“停止捕获”按钮,可以停止连续或定时模式。
实施此方法的最佳方法是什么?我在下面附上了我的代码。
using System;
using System.ComponentModel;
using System.Data;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
using System.Text.RegularExpressions;
namespace FieldProbe
{
public partial class MainForm : Form
{
SerialPort _port = new SerialPort(); //set up port
DataTable dt = new DataTable(); //set up datatable to hold output
int numSamples = 0;
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
var ports = SerialPort.GetPortNames(); //get list of ports connected to PC
cmbSerialPorts.DataSource = ports; //use list of ports as combobox options
_port.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); //create pointer to datareceived event handler
dt.Clear(); //Clear datatable on start
dt.Columns.Add("index", typeof(int)); //index
dt.Columns.Add("dutyCycle", typeof(float)); //0.5 means equal on/off, 1.0 means permanently on
dt.Columns.Add("frequency", typeof(float)); //probe can go from 40MHz to 10GHz
dt.Columns.Add("distance", typeof(float)); //antenna to radiator distance in metres (usually 1m)
dt.Columns.Add("pulseWidth", typeof(float)); //calculated from duty cycle and frequency
dt.Columns.Add("level", typeof(int)); //output in V/m
chChart.Series["series1"].YValueMembers = "level";
chChart.Series["series1"].XValueMember = "index";
chChart.DataSource = dt;
chChart.DataBind();
}
private void btnConnect_Click(object sender, EventArgs e)
{
if (btnConnect.Text == "Connect") //if user clicks connect button
{
if (cmbSerialPorts.SelectedIndex > -1) //if port valid
{
//MessageBox.Show(String.Format("You selected port '{0}'", cmbSerialPorts.SelectedItem));
Connect(cmbSerialPorts.SelectedItem.ToString()); //go to connect function
}
else
{
MessageBox.Show("Please select a port first");
}
}
else //if user clicks disconnect button
{
btnConnect.Text = "Connect";
btnContinuous.Enabled = false;
btnSingle.Enabled = false;
btnTimed.Enabled = false;
nudTime.Enabled = false;
try
{
_port.Close();
}
catch
{
MessageBox.Show("Connection close failed- device may already be unplugged. Program will exit.");
Application.Exit();
}
}
}
private void btnSave_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "csv files (*.csv)|*.csv*";
saveFileDialog1.RestoreDirectory = true;
saveFileDialog1.DefaultExt = "csv";
saveFileDialog1.AddExtension = true;
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
File.WriteAllText(saveFileDialog1.FileName, dtToCSV());
}
}
private void btnSingle_Click(object sender, EventArgs e)
{
}
private void Connect(string portName)
{
if (!_port.IsOpen)
{
_port.BaudRate = 9600; //CHANGE ME AFTER ARDUINO TESTING!!!!!!!!!!!!!!
_port.DataBits = 8;
_port.StopBits = StopBits.One;
_port.Parity = Parity.None;
_port.Handshake = Handshake.None;
_port.RtsEnable = true; //CHANGE ME AFTER ARDUINO TESTING!!!!!!!!!!!!!!
_port.DtrEnable = true; //CHANGE ME AFTER ARDUINO TESTING!!!!!!!!!!!!!!
_port.PortName = portName;
try
{
_port.Open(); //connect to port
btnConnect.Text = "Disconnect";
btnContinuous.Enabled = true;
btnSingle.Enabled = true;
btnTimed.Enabled = true;
nudTime.Enabled = true;
}
catch
{
MessageBox.Show("ERROR: Port invalid or in use!");
btnConnect.Text = "Connect";
btnContinuous.Enabled = false;
btnSingle.Enabled = false;
btnTimed.Enabled = false;
nudTime.Enabled = false;
}
}
}
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender; //set up serial port
string indata = sp.ReadExisting(); //read data from port
string indataString = Regex.Match(indata, @"\d+").Value; //extract number (still a string)
numSamples++; //increment x axis
try
{
int indataInt = Int32.Parse(indataString); //convert string to int
var pulseWidth = nudDutyCycle.Value / (nudFrequency.Value * 100); //formula to find pulse width from duy cycle & frequency
object[] o = { numSamples, nudDutyCycle.Value, nudFrequency.Value, nudDistance.Value, pulseWidth, indataInt }; //collect data
dt.Rows.Add(o); //add data to datatable
teIncomingData.invokeIfRequired(() => //add text to textbox (different thread)
{
teIncomingData.AppendText(indataString + Environment.NewLine);
});
}
catch { }
chChart.invokeIfRequired(() => //update chart (different thread)
{
chChart.DataBind();
});
}
private string dtToCSV()
{
string file = "";
foreach (DataColumn col in dt.Columns)
file = string.Concat(file, col.ColumnName, ",");
file = file.Remove(file.LastIndexOf(','), 1);
file = string.Concat(file, "\r\n");
foreach (DataRow row in dt.Rows)
{
foreach (object item in row.ItemArray)
file = string.Concat(file, item.ToString(), ",");
file = file.Remove(file.LastIndexOf(','), 1);
file = string.Concat(file, "\r\n");
}
return file;
}
public void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
{ //do not delete me, this needs to exist for some reason for saving to work
}
}
public static class Invoker
{
public static void invokeIfRequired(this ISynchronizeInvoke obj, MethodInvoker action)
{
if(obj.InvokeRequired)
{
var args = new object[0];
obj.Invoke(action, args);
}
else
{
action();
}
}
}
}