【C#】串口数据传输

日志类

cs 复制代码
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}");
            }
        }
    }
}

串口类

cs 复制代码
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校验通过后在进行数据处理逻辑。

相关推荐
SRC_BLUE_172 分钟前
UPLOAD LABS | PASS 01 - 绕过前端 JS 限制
开发语言·前端·javascript
NetX行者3 分钟前
Vue3+Typescript+Axios+.NetCore实现导出Excel文件功能
前端·typescript·c#·excel·.netcore
小狮子安度因40 分钟前
Qt如何改变串口读取数据的频率
开发语言·数据库·qt
小爬虫程序猿1 小时前
如何利用Java爬虫获取店铺详情:一篇详尽指南
java·开发语言·爬虫
tian-ming1 小时前
Java八股(一)
java·开发语言
听潮阁1 小时前
【SpringCloud详细教程】-04-服务容错--Sentinel
java·开发语言·spring boot·spring cloud·eclipse·tomcat
海涛高软1 小时前
QT配置文件详解
开发语言·qt
Object~1 小时前
【第十二课】Rust并发编程(三)
开发语言·后端·rust
吾与谁归in2 小时前
【C#设计模式(15)——命令模式(Command Pattern)】
设计模式·c#·命令模式
cwtlw2 小时前
数据库学习记录02
开发语言·数据库·笔记·sql·学习