C# 一个串口通信的案例实现

通信规格书:

指定页读取规范:

HOST:<LF>RPP1<CR>
Reader:<LF>R<FAIL> <CR><LF> // 读取失败
Reader:<LF>R12345678<CR><LF>// 读取成功

Example:
HOST:0A 52 50 50 31 0D
Reader:0A 52 30 31 32 33 34 35 59 54 0D 0A // 成功
Reader:0A 52 46 41 49 4C 0D 0A // 失败

  1. HOST发送指令

    • HOST通过串口向RFID读写器发送指定页读取的命令。
    • 命令格式为 <LF>RPP1<CR>,其中:
      • <LF> 表示换行符,ASCII码为 0x0A。
      • <CR> 表示回车符,ASCII码为 0x0D。
      • RPP1 表示指定读取第一页的数据。
  2. 读写器响应

    • 如果读写器成功读取了数据,会返回如下格式的响应:
      • <LF>R12345678<CR><LF>,其中:
        • R 是固定的标识符,表示读取操作。
        • 12345678 是具体的数据内容。
        • <LF> 表示换行符。
        • <CR> 表示回车符。
    • 如果读取失败,读写器返回如下格式的响应:
      • <LF>RFAIL<CR><LF>,其中:
        • RFAIL 表示读取失败。

指定页写入规范:

HOST:<LF>WPP1,12345678<CR>
Reader:<LF>W<FAIL> <CR><LF> //写入失败
Reader:<LF>W<OK> <CR><LF> // 写入成功

Example:
HOST:0A 57 50 50 31 2C 31 32 33 34 35 36 37 38 0D
Reader:0A 57 4F 4B 0D 0A // 写入成功
Reader:0A 57 46 41 49 4C 0D 0A // 写入失败

  1. HOST发送指令

    • HOST通过串口向RFID读写器发送指定页写入的命令。
    • 命令格式为 <LF>WPP1,12345678<CR>,其中:
      • <LF> 表示换行符,ASCII码为 0x0A。
      • <CR> 表示回车符,ASCII码为 0x0D。
      • WPP1,12345678 表示写入数据到第一页,数据为 12345678
  2. 读写器响应

    • 如果写入操作成功,读写器会返回如下格式的响应:
      • <LF>W<OK><CR><LF>,其中:
        • W 是固定的标识符,表示写入操作。
        • <OK> 表示写入成功。
        • <LF> 表示换行符。
        • <CR> 表示回车符。
    • 如果写入操作失败,读写器会返回如下格式的响应:
      • <LF>W<FAIL><CR><LF>,其中:
        • W 是固定的标识符,表示写入操作。
        • <FAIL> 表示写入失败。

实现代码类:

    public class RfidCls : IDisposable
    {
        private SerialPort port;
        private Thread initThread;
        private readonly object mylock = new object();
        private string portName = "COM2";
        private int baudRate = 9600;
        public bool IsLink { get; private set; }

        public void Start(string portname, int baudrate)
        {
            portName = portname;
            baudRate = baudrate;
            initThread = new Thread(InitializePort);
            initThread.Start();
        }

        private void InitializePort()
        {
            try
            {
                if (string.IsNullOrEmpty(portName))
                    throw new ArgumentException("串口参数未设置,请检查!");

                port = new SerialPort(portName, baudRate)
                {
                    StopBits = StopBits.One,
                    DataBits = 8,
                    Parity = Parity.None
                };

                port.Open();
                if (port.IsOpen)
                {
                    IsLink = true;
                    LogInfo("RFID连接成功");
                }
                else
                {
                    throw new Exception("串口未能成功打开!");
                }
            }
            catch (Exception ex)
            {
                LogError($"串口连接失败:{ex.Message}");
            }
        }

        public void Close()
        {
            try
            {
                if (port != null && port.IsOpen)
                {
                    port.Close();
                    LogInfo("RFID连接已关闭");
                }
            }
            catch (Exception ex)
            {
                LogError($"关闭RFID连接失败:{ex.Message}");
            }
        }

        public bool ReadRFID(int pageIndex, out string pageInfo)
        {
            pageInfo = null;
            try
            {
                lock (mylock)
                {
                    if (port == null || !port.IsOpen)
                        throw new InvalidOperationException("RFID端口未打开或已关闭");

                    string command = $"RPP{pageIndex + 1}";
                    byte[] commandBytes = ConstructCommand(command, "");
                    port.Write(commandBytes, 0, commandBytes.Length);
                    byte[] responseBytes = ReadResponse();

                    if (responseBytes != null && responseBytes.Length >= 4)
                    {
                        string response = Encoding.Default.GetString(responseBytes);
                        if (response.StartsWith("R") && response.Length >= 6)
                        {
                            if (response.Substring(1, 4) == "FAIL")
                            {
                                LogError("读取RFID失败");
                                return false;
                            }
                            else if (response.Length > 6)
                            {
                                pageInfo = response.Substring(1);
                                LogInfo($"读取RFID成功:{pageInfo}");
                                return true;
                            }
                        }
                    }

                    LogError("读取RFID未知响应");
                    return false;
                }
            }
            catch (Exception ex)
            {
                LogError($"读取RFID出错:{ex.Message}");
                return false;
            }
        }

        public bool WriteRFID(int pageIndex, string hexValue)
        {
            try
            {
                lock (mylock)
                {
                    if (port == null || !port.IsOpen)
                        throw new InvalidOperationException("RFID端口未打开或已关闭");

                    string command = $"WPP{pageIndex + 1},{hexValue}";
                    byte[] commandBytes = ConstructCommand(command, "");
                    port.Write(commandBytes, 0, commandBytes.Length);
                    byte[] responseBytes = ReadResponse();

                    if (responseBytes != null && responseBytes.Length >= 4)
                    {
                        string response = Encoding.Default.GetString(responseBytes);
                        if (response.StartsWith("W"))
                        {
                            if (response.Length >= 6 && response.Substring(1, 2) == "OK")
                            {
                                LogInfo("写入RFID成功");
                                return true;
                            }
                            else if (response.Length >= 6 && response.Substring(1, 4) == "FAIL")
                            {
                                LogError("写入RFID失败");
                                return false;
                            }
                        }
                    }

                    LogError("写入RFID未知响应");
                    return false;
                }
            }
            catch (Exception ex)
            {
                LogError($"写入RFID出错:{ex.Message}");
                return false;
            }
        }

        private byte[] ConstructCommand(string command, string hexValue)
        {
            StringBuilder commandHex = new StringBuilder();
            foreach (char c in command)
            {
                commandHex.Append(Convert.ToString(c, 16));
            }

            string dataHex = hexValue;

            string fullHex = $"0A{commandHex}2C{dataHex}0D";

            byte[] commandBytes = new byte[fullHex.Length / 2];
            for (int i = 0; i < fullHex.Length; i += 2)
            {
                commandBytes[i / 2] = Convert.ToByte(fullHex.Substring(i, 2), 16);
            }

            return commandBytes;
        }

        private byte[] ReadResponse()
        {
            DateTime startTime = DateTime.Now;
            byte[] buffer = new byte[1024];
            int totalBytes = 0;

            while (DateTime.Now.Subtract(startTime).TotalSeconds < 3)
            {
                int bytesToRead = port.BytesToRead;
                if (bytesToRead > 0)
                {
                    if (totalBytes + bytesToRead > buffer.Length)
                        Array.Resize(ref buffer, totalBytes + bytesToRead);

                    totalBytes += port.Read(buffer, totalBytes, bytesToRead);

                    if (totalBytes >= 2 && (buffer[totalBytes - 2] == 0x0D || buffer[totalBytes - 1] == 0x0A))
                        break;
                }
                else
                {
                    Thread.Sleep(100);
                }
            }

            if (totalBytes > 0)
            {
                Array.Resize(ref buffer, totalBytes);
                return buffer;
            }

            return null;
        }

        private void LogInfo(string message)
        {
            // 实现信息日志记录,例如使用日志框架记录到文件或其他存储介质
            Console.WriteLine($"信息:{message}");
        }

        private void LogError(string message)
        {
            // 实现错误日志记录,例如使用日志框架记录到文件或其他存储介质
            Console.WriteLine($"错误:{message}");
        }

        public void Dispose()
        {
            Close();
            if (initThread != null)
            {
                initThread.Join(); // 确保线程已终止
                initThread = null;
            }
        }
    }
相关推荐
向宇it3 小时前
【从零开始入门unity游戏开发之——C#篇25】C#面向对象动态多态——virtual、override 和 base 关键字、抽象类和抽象方法
java·开发语言·unity·c#·游戏引擎
向宇it4 小时前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
坐井观老天9 小时前
在C#中使用资源保存图像和文本和其他数据并在运行时加载
开发语言·c#
pchmi11 小时前
C# OpenCV机器视觉:模板匹配
opencv·c#·机器视觉
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭13 小时前
C#都可以找哪些工作?
开发语言·c#
boligongzhu14 小时前
Dalsa线阵CCD相机使用开发手册
c#
向宇it1 天前
【从零开始入门unity游戏开发之——C#篇23】C#面向对象继承——`as`类型转化和`is`类型检查、向上转型和向下转型、里氏替换原则(LSP)
java·开发语言·unity·c#·游戏引擎·里氏替换原则
sukalot1 天前
windows C#-命名实参和可选实参(下)
windows·c#
小码编匠1 天前
.NET 下 RabbitMQ 队列、死信队列、延时队列及小应用
后端·c#·.net