C#实现简单串口通信

Leona ·
更新时间:2024-11-10
· 1517 次阅读

串口通信(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)

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

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

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

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

数据封装方法:

//数据打包 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();                     }     }

3、调用(模拟测试读写硬件版本号)

//地址存储信息定义 private static int HARD_VERSION = 0;            //硬件版本号 //命令定义 private static byte RD_HV = 0;                //读硬件版本 private static byte WR_HV = 1;                //写硬件版本 private CommHelper comm = new CommHelper(); private bool GetCorrect = false; //用来标识是否已经接收到返回值 private List<byte> buffer = new List<byte>(1024);//默认分配1M内存,限制不能超过 private byte[] binary_data = new byte[10];//指定格式的某个完整数据 //串口初始化 private void InitComm()         {             comm.serialPort.PortName = "COM1";             comm.serialPort.BaudRate = 19200;             try             {                 comm.Open();             }             catch (Exception ex)             {                 MessageBox.Show(ex.Message);             }             if (comm.IsOpen)             {                 comm.DataReceived += new CommHelper.EventHandle(comm_DataReceived);             }         }         //数据接收后处理         private void comm_DataReceived(byte[] readBuffer)         {             try             {                 buffer.AddRange(readBuffer);//将数据放到缓存中                 //完整性判断                 while (buffer.Count >= 10)                 {                     //查找数据头                     if (buffer[0] == 0xAA && buffer[1] == 0x55)                     {                         //和校验                         byte checksum = 0;                         for (int i = 0; i < 7; i++)                         {                             checksum += buffer[i];                         }                         if (checksum != buffer[7])                         {                             buffer.RemoveRange(0, 10);//如果校验失败,从缓存中删除这一包数据                             continue;                         }                         buffer.CopyTo(0, binary_data, 0, 10);//复制一条完整的数据到具体的数据缓存                         //读取硬件版本号                         if (binary_data[2] == RD_HV && ByteArrayToInt(binary_data[3], binary_data[4]) == HARD_VERSION)//命令字为读RD_HV,地址HARD_VERSION                         {                             GetCorrect = true;                             string data = ByteArrayToString(binary_data[5], binary_data[6]);                             //这里可以处理数据更新界面展示                         }                         buffer.RemoveRange(0, 10);                     }                     else                     {                         GetCorrect = false;                         buffer.RemoveAt(0);//如果数据开始不是头,则删除数据                     }                 }             }             catch             {             }         }         //将2位数组转换成字符串         private static string ByteArrayToString(byte arr1, byte arr2)         {             int value = ByteArrayToInt(arr1, arr2);             string str = Convert.ToString(value, 10);             return str;         }         //将2位数组转换成10进制数         private static int ByteArrayToInt(byte arr1, byte arr2)         {             byte[] arr = new byte[] { arr1, arr2 };             int value = (int)((arr[0] & 0xFF) << 8)                       | (arr[1] & 0xFF);             return value;         }         //读取硬件版本号         private void ReadHV()         {             GetCorrect = false;             try             {                 comm.WritePort(DataPackage(RD_HV, HARD_VERSION, 0), 0, 10);//发送RD_E2P命令,地址HARD_VERSION                 Delay(100);                 if (GetCorrect == true)                 {                     MessageBox.Show("硬件版本号读取成功!");                 }                 else                 {                     MessageBox.Show("硬件版本号读取失败!");                 }             }             catch (Exception ex)             {                 MessageBox.Show(ex.Message);             }         }         //写入硬件版本号         private void WriteHV()         {             if (tbVersion.Text.Length == 4 && isLegal(tbVersion.Text))//限定只能写入4个字符且输入合法             {                 try                 {                     int buf = Convert.ToInt32(tbVersion.Text);                     GetCorrect = false;                     comm.WritePort(DataPackage(WR_HV, HARD_VERSION, buf), 0, 10);//发送WR_HV命令,地址HARD_VERSION                     Delay(100);                     if (GetCorrect == true)                     {                         MessageBox.Show("硬件版本号写入成功!");                     }                     else                     {                         MessageBox.Show("硬件版本号写入失败!");                     }                 }                 catch (Exception ex)                 {                     MessageBox.Show(ex.Message);                 }             }             else             {                 MessageBox.Show("硬件版本号数据格式错误!请重新写入!");             }         }         //判断输入是否合法,必须是数字         private const string PATTERN = @"^[0-9]*$";         private bool isLegal(string hex)         {             return System.Text.RegularExpressions.Regex.IsMatch(hex, PATTERN);         }         //延时函数         [DllImport("kernel32.dll")]         static extern uint GetTickCount();         static void Delay(uint ms)         {             uint start = GetTickCount();             while (GetTickCount() - start < ms)             {                 Application.DoEvents();             }         }



C# 串口 串口通信 通信

需要 登录 后方可回复, 如果你还没有账号请 注册新账号