首先呢,这个代码我工作中也在用,而且一般公司代码不能外发,只不过呢,这个是在我入职之前就写着玩的,应该无所谓咯。
上位机和PLC使用modbus协议交互,参考我的文章:modbus协议讲解,上位机与PLC交互_花开莫与流年错_的博客-CSDN博客
1、首先呢,运行起来是这样的,一直在收取单片机的数据
2、对应单片机呢,是这样发的(大学的时候买的STM32F1的卡,很久没接触单片机了),里面的printf函数输出,通过USB线返回给电脑。
3、对应C#里面的几个关键点
(1)使用Serialport对象,结合微软官方实例程序使用:SerialPort serialPort = new SerialPort();
(2)读取当前有哪些接线的端口号(还有设定通讯速度,校验位什么的):
// 查询更新已有端口
IList list = new List();
// 读取当前有哪些COM口
foreach (string s in SerialPort.GetPortNames())
{
list.Add(s);
}
port_m.DataSource = list;
(3)接收到数据后的事件触发
serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
(4)事件触发中,中英文都传送,需要如下格式转换:
通讯时,string转换成byte,用于发送(包含中文)
Byte[] data = System.Text.Encoding.Default.GetBytes(textBox1.Text);
serialPort.Write(data, 0, data.Length);
通讯时,byte转换成string,用于接收(包含中文)
int dataLength = serialPort.BytesToRead;
byte[] buffer = new byte[1024];
sp.Read(buffer, 0, dataLength);
string indata = System.Text.Encoding.Default.GetString(buffer, 0, dataLength);
(5)事件触发呢是这样的
void DataReceivedHandler(
object sender,
SerialDataReceivedEventArgs e)
{
if (waitTimes == 0)
{
SerialPort sp = (SerialPort)sender;
Thread.Sleep(10); // 计算需要多长时间延时后再发送
int dataLength = serialPort.BytesToRead;
byte[] buffer = new byte[1024];
sp.Read(buffer, 0, dataLength);
string indata = System.Text.Encoding.Default.GetString(buffer, 0, dataLength);
//indata += sp.ReadExisting(); // 读取缓冲区全部内容
// String to store the response ASCII representation.
//ASCIIEncoding ASCll = new ASCIIEncoding();
//indata += ASCll.GetString(bt) + "\r\n";
//indata += Convert.ToString(sp.BytesToRead) + "\r\n";
haveRead = true;
// 需要触发更新界面
this.BeginInvoke(new ReadDelegate(Read), new object[] { indata });
}
}
private delegate void ReadDelegate(string str);
private void Read(string str)
{
this.textBox2.Text += str;
this.textBox2.SelectionStart = this.textBox2.Text.Length;
this.textBox2.ScrollToCaret(); // 滚动到当前选中位置
}
4、好啦,差不多了,于是看下我整体代码有些什么
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Timers; // 用于系统定时刷新
using System.IO.Ports;
using System.Threading;
using System.Runtime.CompilerServices;
namespace Com
{
public partial class Form1 : Form
{
//系统定时器
System.Timers.Timer timer;
public static int waitTimes = 0; // 端口发送后等待回收时间
static bool haveRead = false; // 已经读取到数据
static bool timerOut = false; // 读取等待超时
static SerialPort serialPort = new SerialPort();
StringComparer stringComparer = StringComparer.OrdinalIgnoreCase;
//Thread readThread = new Thread(Read);
public Form1()
{
InitializeComponent();
InitParameter();
serialPort.ReadTimeout = 500;
serialPort.WriteTimeout = 500;
}
private void send_Click(object sender, EventArgs e)
{
Byte[] data = System.Text.Encoding.Default.GetBytes(textBox1.Text);
if (receive_mode.Text == "发送后延时") {
if (serialPort.IsOpen)
serialPort.Write(data, 0, data.Length);
Thread.Sleep(waitTimes);
string indata;
int dataLength = serialPort.BytesToRead;
if (dataLength > 0)
{
byte[] buffer = new byte[1024];
serialPort.Read(buffer, 0, dataLength);
indata = System.Text.Encoding.Default.GetString(buffer, 0, dataLength);
}
else
indata = "超时未收到\r\n";
// 需要触发更新界面
this.BeginInvoke(new ReadDelegate(Read), new object[] { indata });
}
else
{
if (serialPort.IsOpen)
serialPort.Write(data, 0, data.Length);
TimerInit(250);
while (!timerOut && !haveRead) ;
if (timerOut == true) // 需要触发更新界面
this.BeginInvoke(new ReadDelegate(Read), new object[] { "超时未收到\r\n" });
timerOut = false;
haveRead = false;
timer.Stop();
}
}
void DataReceivedHandler(
object sender,
SerialDataReceivedEventArgs e)
{
if (waitTimes == 0)
{
SerialPort sp = (SerialPort)sender;
Thread.Sleep(10); // 计算需要多长时间延时后再发送
int dataLength = serialPort.BytesToRead;
byte[] buffer = new byte[1024];
sp.Read(buffer, 0, dataLength);
string indata = System.Text.Encoding.Default.GetString(buffer, 0, dataLength);
//indata += sp.ReadExisting(); // 读取缓冲区全部内容
// String to store the response ASCII representation.
//ASCIIEncoding ASCll = new ASCIIEncoding();
//indata += ASCll.GetString(bt) + "\r\n";
//indata += Convert.ToString(sp.BytesToRead) + "\r\n";
haveRead = true;
// 需要触发更新界面
this.BeginInvoke(new ReadDelegate(Read), new object[] { indata });
}
}
private delegate void ReadDelegate(string str);
private void Read(string str)
{
this.textBox2.Text += str;
this.textBox2.SelectionStart = this.textBox2.Text.Length;
this.textBox2.ScrollToCaret(); // 滚动到当前选中位置
}
private void port_m_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void receive_Click(object sender, EventArgs e)
{
if(!serialPort.IsOpen)
{
connect.Text = "关闭";
try
{
object myPort;
myPort = port_m.SelectedItem;
serialPort.PortName = Convert.ToString(myPort);
object mySpeed;
mySpeed = speed.SelectedItem;
serialPort.BaudRate = Convert.ToInt32(mySpeed);
object myParity;
myParity = odd_even.SelectedItem;
serialPort.Parity = (Parity)Enum.Parse(typeof(Parity), Convert.ToString(myParity), true);
serialPort.DataBits = 8;
object myStop;
myStop = receive_mode.SelectedItem;
serialPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), Convert.ToString(myStop), true);
}
catch (Exception ex) { }
serialPort.Open();
// 连接后开始执行读取线程
Task.Run(() => {
while (false)
{
if (haveRead)
{
TimerInit(100);
while (haveRead) ;
}
}
});
}
else
{
connect.Text = "连接";
serialPort.Close();
}
}
void TimerInit(int time)
{
//高刷新定时器初始化
timer = new System.Timers.Timer();
timer.Interval = time; // 单位:毫秒
timer.Elapsed += OnTimedEvent;
timer.AutoReset = true;
timer.Enabled = true;
timer.Start();
//timer.Stop();
}
/* 定时器Timer触发事件
*/
public void OnTimedEvent(object source, ElapsedEventArgs e)
{
timerOut = true;
}
private void InitParameter()
{
serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
//comboBox1.Items.Add(textBox1.Text);
// 查询更新已有端口
IList list = new List();
// 读取当前有哪些COM口
foreach (string s in SerialPort.GetPortNames())
{
list.Add(s);
}
port_m.DataSource = list;
// 传输速度
int[] speed_data = new int[] { 9600, 19200, 38400, 115200 };
speed.DataSource = speed_data;
// 奇偶校验
IList list1 = new List();
list1.Clear();
list1.Add("None");
list1.Add("奇校验");
list1.Add("偶校验");
odd_even.DataSource = list1;
// 停止位
string[] stop = { "1", "2" };
stop_num.DataSource = stop;
//list.Clear();
string[] str = { "事件", "发送后延时" };
receive_mode.DataSource = str; // StopBits
// 触发事件
this.port_m.SelectedValueChanged += new System.EventHandler(this.port_m_SelectedIndexChanged);
}
// 接收方式发生改变时
void receive_mode_changed(object ob, EventArgs e)
{
if(receive_mode.Text == "发送后延时")
{
DelayTime delayTime = new DelayTime();
delayTime.Show();
}
else
{
waitTimes = 0;
}
}
}
}