【C#】串口数据传输

发布于:2024-11-28 ⋅ 阅读:(36) ⋅ 点赞:(0)

日志类 

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyEntity
{

    public static class LogHelper
    {
        private static readonly string logDirectory = AppDomain.CurrentDomain.BaseDirectory + "Logs\\";

        public static void WriteLog(string message)
        {
            try
            {
                if (!Directory.Exists(logDirectory))
                {
                    Directory.CreateDirectory(logDirectory);
                }

                string logFilePath = logDirectory + "Log_" + DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
                using (StreamWriter writer = new StreamWriter(logFilePath, true))
                {
                    writer.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} - {message}");
                }
            }
            catch (Exception ex)
            {
                // 如果写入日志失败,可以考虑将异常信息输出到控制台或者存储到备用的位置
                Console.WriteLine($"Error writing to log: {ex.Message}");
            }
        }
    }
}

 串口类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using System.ComponentModel;
using Newtonsoft.Json;
using Microsoft.Extensions.Logging;

namespace MyEntity
{
    public class SerialPortClass
    {

        public SerialPort serialPort = new System.IO.Ports.SerialPort();
        /// <summary>
        /// 无参构造函数
        /// 初始化串口参数
        /// </summary>
        public SerialPortClass()
        {
            serialPort.PortName = SerialPortConfig.PortName; // 设置串口名称
            serialPort.BaudRate = SerialPortConfig.BaudRate; // 设置波特率
            serialPort.Parity = Parity.None; // 设置奇偶校验
            serialPort.DataBits = SerialPortConfig.DataBits; // 设置数据位数
            serialPort.StopBits = StopBits.One; // 设置停止位
            serialPort.Handshake = Handshake.None; // 设置握手协议
            serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);//绑定接收数据时的调用方法
        }
        /// <summary>
        /// 串口接收到数据时的触发事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
        {
            Thread.Sleep(100);//增加延时控制,确保数据可以一次全部接收
            SerialPort sp = (SerialPort)sender;
            Thread.Sleep(100);//增加延时控制,确保数据可以一次全部接收
            byte[] tempbuffer = new byte[sp.BytesToRead]; // 设置缓冲区大小为接收字节数
            sp.Read(tempbuffer, 0, tempbuffer.Length);
            Thread.Sleep(100);//增加延时控制,确保数据可以一次全部接收
            Console.WriteLine("串口接收:");
            Console.WriteLine($@"串口数据:{BitConverter.ToString(buffer).Replace("-", " ")}");
            Console.WriteLine($@"json字符串:{jsonStr}");
            //SendByteData(buffer);
            }
        /// <summary>
        /// 打开串口
        /// </summary>
        public void OpenPort()
        {
            try
            {
                serialPort.Open();
                Console.WriteLine("串口打开");
                LogHelper.WriteLog("串口打开");
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog("串口打开失败,失败原因" + ex.Message);
                Console.WriteLine("串口打开失败,失败原因" + ex.Message);
            }
        }
        /// <summary>
        /// 关闭串口
        /// </summary>
        public void ClosePort()
        {
            if (serialPort.IsOpen)
            {
                serialPort.Close();
            }
        }
        /// <summary>
        /// 发送字符串数据
        /// </summary>
        /// <param name="data"></param>
        public void SendStringData(string data)
        {
            if (serialPort.IsOpen)
            {
                LogHelper.WriteLog("串口发送:" + JsonConvert.SerializeObject(data));
                Console.WriteLine("串口发送:" + data);
                serialPort.WriteLine(data);
            }
            else
            {
                LogHelper.WriteLog("串口关闭");
                Console.WriteLine("串口关闭");
            }
        }
        /// <summary>
        /// 发送字节数据
        /// </summary>
        /// <param name="data"></param>
        public void SendByteData(byte[] data)
        {
            if (serialPort.IsOpen)
            {
                Console.WriteLine("串口发送:" + JsonConvert.SerializeObject(data));
                //Console.WriteLine($@"串口发送:{BitConverter.ToString(data).Replace("-", " ")}");

                LogHelper.WriteLog($@"串口发送:{BitConverter.ToString(data).Replace("-", " ")}");
                serialPort.Write(data, 0, data.Length);
            }
            else
            {
                LogHelper.WriteLog("串口关闭");
                Console.WriteLine("串口关闭");
            }

        }
        /// <summary>
        /// 获取字节数据字符串
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private string GetByteString(byte data)
        {
            string result = "";
            byte[] bytes = new byte[1] { data };

            return BitConverter.ToString(bytes);
        }
    }
    /// <summary>
    /// 串口调用静态类
    /// </summary>
    public static class UseSerial
    {
        public static SerialPortClass serialPort { get; set; }
    }
    
    public static class SerialPortConfig
    {
        /// <summary>
        /// 串口名称(与电脑设备管理器中串口名称对应)
        /// </summary>
        public static string PortName { get; set; } = "COM1";
        /// <summary>
        /// 波特率
        /// </summary>
        public static int BaudRate { get; set; } = 9600;
        /// <summary>
        /// 数据位数
        /// </summary>
        public static int DataBits { get; set; } = 8;
        
        /// <summary>
        /// 数据包序号
        /// </summary>
        public static short PacketSerialNumber { get; set; } = 0;
        /// <summary>
        /// LRC校验
        /// SerialPortConfig.Lrc(byteArr) byteArr为需要校验的字节数组
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="start"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public static byte[] Lrc(byte[] buffer, int start = 0, int len = 0)
        {
            if (buffer == null || buffer.Length == 0) return null;
            if (start < 0) return null;
            if (len == 0) len = buffer.Length - start;
            int length = start + len;
            if (length > buffer.Length) return null;
            byte lrc = 0;// Initial value
            for (int i = start; i < len; i++)
            {
                lrc ^= buffer[i];
            }
            //lrc = (byte)((lrc ^ 0xFF) + 1);
            return new byte[] { lrc };
        }

    }
}

注意事项及优化

        1.系统延时(Thread.Sleep()):暂时在创建串口类之前,读取数据之前和之后都增加了系统延时,没有具体验证是在哪个位置增加系统延时能解决接收设备数据时分包的情况,猜测是在创建串口类后并在串口读取数据之前延时可解决该类问题

        2.数据校验:可在每次接收数据后,对数据进行完整性校验,直到数据完整性验证通过后再进行数据处理。如假设数据存在LRC校验位,可在每次接收数据后验证LRC校验位是否正确,如果正确则数据校验通过,进行之后的数据处理逻辑,如果不通过,则继续等待串口数据,直到LRC校验通过后在进行数据处理逻辑。