C#串口通信(C#串口通信代码)

C#串口通信(C#串口通信代码)

编码文章call10242025-07-19 22:08:043A+A-

串口通信(Serial Communications)是指外设和计算机间通过数据信号线、地线等按位(bit)进行传输数据的一种通信方式,属于串行通信方式,能够实现远距离通信,长度可达1200米。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通信的端口,这些参数必须匹配。

串口通信的接口标准有很多,有 RS-232C、RS-232、RS-422A、RS-485 等。常用的就是 RS-232 和 RS-485。串口通信使用的大多都是 DB9 接口,如下图。

1 载波检测(DCD)

2 接受数据(RXD)

3 发出数据(TXD)

4 数据终端准备好(DTR)

5 信号地线(SG)

6 数据准备好(DSR)

7 请求发送(RTS)

8 清除发送(CTS)

9 振铃指示(RI)

DB9 Connector 信号定义。串口测试将2、3针脚短接即可。

这里我们以 RS-232 接口进行演示。

1、数据包格式定为(10bytes):

帧头(0xAA,0x55),命令字(1byte),地址位(2bytes),数据位(2bytes),校验位(1byte,和校验),帧尾(0xFE,0xFE)

地址位和数据位都是高位在前。

2、串口端口号搜索


string[] portList = System.IO.Ports.SerialPort.GetPortNames();

for (int i = 0; i < portList.Length; i++)

{

string name = portList[i];

comboBox.Items.Add(name);

}

还有一种通过调用API的方法来获取实现,可以获取详细的完整串口名称,对于USB-to-COM虚拟串口来说特别适用。

3、串口属性参数设置

SerialPort mySerialPort = new SerialPort("COM2");//端口

mySerialPort.BaudRate = 9600;//波特率

mySerialPort.Parity = Parity.None;//校验位

mySerialPort.StopBits = StopBits.One;//停止位

mySerialPort.DataBits = 8;//数据位

mySerialPort.Handshake = Handshake.Non;

mySerialPort.ReadTimeout = 1500;

mySerialPort.DtrEnable = true;//启用数据终端就绪信息

mySerialPort.Encoding = Encoding.UTF8;


mySerialPort.ReceivedBytesThreshold = 1;//DataReceived触发前内部输入缓冲器的字节数

mySerialPort.DataReceived += new SerialDataReceivedEvenHandler(DataReceive_Method);


mySerialPort.Open();

4、串口发送信息

Write(Byte[], Int32, Int32) :将指定数量的字节写入串行端口

Write(Char[], Int32, Int32) :将指定数量的字符写入串行端口

Write(String) :将指定的字符串写入串行端口

WriteLine(String) :将指定的字符串和NewLine值写入输出缓冲区


// Write a string

port.Write("Hello World");


// Write a set of bytes

port.Write(new byte[] { 0x0A, 0xE2, 0xFF }, 0, 3);


// Close the port

port.Close();

5. 串口接收信息

Read(Byte[], Int32, Int32):从SerialPort输入缓冲区读取一些字节,并将那些字节写入字节数组中指定的偏移量处

ReadByte():从SerialPort输入缓冲区中同步读取一个字节

ReadChar(): 从SerialPort输入缓冲区中同步读取一个字符

ReadExisting() :在编码的基础上,读取SerialPort对象的流和输入缓冲区中所有立即可用的字节

ReadLine() :一直读取到输入缓冲区中的NewLine值

ReadTo(String) :一直读取到输入缓冲区中的指定value的字符串


string serialReadString;

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)

{

serialReadString = port.ReadExisting());

this.txt1.Invoke( new MethodInvoker(delegate { this.txt1.AppendText(serialReadString); }));

}

6、循环接收数据


void com_DataReceived(object sender, SerialDataReceivedEventArgs e)

{

// Use either the binary OR the string technique (but not both)

// Buffer and process binary data

while (com.BytesToRead > 0)

bBuffer.Add((byte)com.ReadByte());

ProcessBuffer(bBuffer);


// Buffer string data

sBuffer += com.ReadExisting();

ProcessBuffer(sBuffer);

}


private void ProcessBuffer(string sBuffer)

{

// Look in the string for useful information

// then remove the useful data from the buffer

}


private void ProcessBuffer(List<byte> bBuffer)

{

// Look in the byte array for useful information

// then remove the useful data from the buffer

}

7、 C# 串口接收数据不完整解决办法

/针对数据协议:head + len + playload + check 类型

private List<byte> buffer = new List<byte>(4096);


private void sp_DataReceived(objectsender, EventArgs e) //sp是串口控件

{

int n = sp.BytesToRead;

byte[] buf = new byte[n];

sp.Read(buf, 0, n);


//1.缓存数据

buffer.AddRange(buf);


//2.完整性判断

while (buffer.Count >= 4) //至少包含帧头(2字节)、长度(1字节)、校验位(1字节);根据设计不同而不同

{

//2.1 查找数据头

if (buffer[0] == 0x01) //传输数据有帧头,用于判断

{

int len = buffer[2];


if (buffer.Count < len + 4) //数据区尚未接收完整

{

break;

}


//得到完整的数据,复制到ReceiveBytes中进行校验

byte[] ReceiveBytes = new byte[len + 4];

buffer.CopyTo(0, ReceiveBytes, 0, len + 4);


byte jiaoyan; //开始校验---自定义实现

jiaoyan = this.JY(ReceiveBytes);//

if (jiaoyan != ReceiveBytes[len+3]) //校验失败,最后一个字节是校验位

{

buffer.RemoveRange(0, len + 4);

MessageBox.Show("数据包不正确!");

continue;

}


buffer.RemoveRange(0, len + 4);


///执行对数据进行处理操作RunReceiveDataCallback(ReceiveBytes);

}

else //帧头不正确时,记得清除

{

buffer.RemoveAt(0);

}

}

}

//针对协议类型: head + len +cmd + seq+ playload +check + tail;


private List<byte> buffer = new List<byte>(4096);

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)

{

try

{

try

{

int nCount = serialPort1.BytesToRead;

if (nCount == 0)

{

return;

}


byte[] btAryBuffer = new byte[nCount];

serialPort1.Read(btAryBuffer, 0, nCount);


//缓存数据

buffer.AddRange(btAryBuffer);


int index = 1;

while (buffer.Count>0x07) //最短协议长度

{

if (buffer[0] == 0x01) //协议头

{


if (buffer[index] != 0x03) //查询协议尾

{


index++;


if (index > buffer.Count) //没有接受到帧尾 0x03

{

break; //退出继续接收


}


}

else // 接收到协议尾 得到完整一帧数据

{

byte[] ReceiveBytes = new byte[index+1];

buffer.CopyTo(0, ReceiveBytes, 0, index+1);


RunReceiveDataCallback(ReceiveBytes);


buffer.RemoveRange(0, index);

}


}

else

{

buffer.RemoveAt(0);


}

}

}

catch (System.Exception ex)

{


}


}

catch(Exception ex)

{

MessageBox.Show(ex.Message);

}

finally

{

handerListening = false;

}

}

8、封装

1、数据封装方法:

//数据打包

private byte[] DataPackage(byte cmd, int addr, int data)

{

byte[] package = new byte[10];

package[0] = 0xAA;//帧头

package[1] = 0x55;

package[2] = cmd;//命令字

byte[] dataaddr = IntToByteArray(addr);

package[3] = dataaddr[0];//地址高字节

package[4] = dataaddr[1];//地址低字节

byte[] value = IntToByteArray(data);

package[5] = value[0];//数据高字节

package[6] = value[1];//数据低字节

package[7] = CheckSum(package);//校验位

package[8] = 0xFE;//帧尾

package[9] = 0xFE;

return package;

}


//将int转换成2位数组

private static byte[] IntToByteArray(int value)

{

int hvalue = (value >> 8) & 0xFF;

int lValue = value & 0xFF;

byte[] arr = new byte[] { (byte)hvalue, (byte)lValue };

return arr;

}


//得到和校验码

private byte CheckSum(byte[] package)

{

byte checksum = 0;

for (int i = 0; i < package.Length; i++)

{

checksum += package[i];

}

return checksum;

}

2、串口调用封装类CommHelper.cs

internal class CommHelper

{

//委托

public delegate void EventHandle(byte[] readBuffer);

public event EventHandle DataReceived;


public SerialPort serialPort;

private Thread thread;

volatile bool _keepReading;


public CommHelper()

{

serialPort = new SerialPort();


thread = null;

_keepReading = false;


serialPort.ReadTimeout = -1;

serialPort.WriteTimeout = 1000;

}


//获取串口打开状态

public bool IsOpen

{

get

{

return serialPort.IsOpen;

}

}


//开始读取

private void StartReading()

{

if (!_keepReading)

{

_keepReading = true;

thread = new Thread(new ThreadStart(ReadPort));

thread.Start();

}

}


//停止读取

private void StopReading()

{

if (_keepReading)

{

_keepReading = false;

thread.Join();

thread = null;

}

}


//读数据

private void ReadPort()

{

while (_keepReading)

{

if (serialPort.IsOpen)

{

int count = serialPort.BytesToRead;

if (count > 0)

{

byte[] readBuffer = new byte[count];

try

{

Application.DoEvents();

serialPort.Read(readBuffer, 0, count);

DataReceived?.Invoke(readBuffer);

Thread.Sleep(100);

}

catch (TimeoutException)

{

}

}

}

}

}


//写数据

public void WritePort(byte[] send, int offSet, int count)

{

if (IsOpen)

{

serialPort.Write(send, offSet, count);

}

}


//打开

public void Open()

{

Close();

try

{

serialPort.Open();

serialPort.RtsEnable = true;

if (serialPort.IsOpen)

{

StartReading();

}

else

{

MessageBox.Show("串口打开失败!");

}

}

catch

{

}

}

//关闭

public void Close()

{

StopReading();

serialPort.Close();

}

}

点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4