You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何读取RS232端口两引脚接触?开发程序实现记录与MSSQL同步

针对RS232引脚接触检测与数据同步的C#实现方案

听起来你需要构建一个集RS232引脚状态检测本地日志记录定时数据库同步于一体的小型桌面程序,用C#完全可以搞定这个需求。我把整个方案拆成三个核心模块,每个模块给你具体的实现思路和代码示例:

一、RS232引脚接触状态检测

首先得明确:RS232的引脚分为输入型(如CTS、DSR、CD、RI)和输出型(如DTR、RTS)。要检测任意两个引脚的接触(短路),通常需要将其中一个引脚设为固定电平输出,另一个作为输入,通过监听输入引脚的电平变化来判断是否短路。

实现步骤:

  1. 选一对适配的引脚:比如把DTR(输出)设为高电平,CTS(输入)作为检测端。当两个引脚接触时,CTS的电平会被拉到DTR的电平,触发状态变化。
  2. 用C#的SerialPort类监听引脚状态:
using System.IO.Ports;

SerialPort serialPort = new SerialPort("COM3"); // 替换成你的实际串口名
serialPort.DtrEnable = true; // 开启DTR输出高电平
serialPort.PinChanged += SerialPort_PinChanged;
serialPort.Open();

private void SerialPort_PinChanged(object sender, SerialPinChangedEventArgs e)
{
    if (e.EventType == SerialPinChange.CtsChanged)
    {
        bool isCtsHigh = serialPort.CtsHolding;
        // 这里根据CTS电平变化判断接触:比如从低变高时,说明DTR和CTS短路
        if (isCtsHigh)
        {
            // 触发时间戳记录逻辑
            LogContactEvent(DateTime.Now);
        }
    }
}

注意:如果要支持任意引脚组合,可能需要额外硬件电路辅助(比如电平转换模块),RS232引脚是±12V电平,直接短路有风险,建议先确认传感器的电气特性。

二、本地文件记录时间戳

为了保证数据不丢失,每次检测到接触事件时,先写入本地文件做缓存。建议用追加模式写入,并且加锁避免并发冲突:

private readonly object _fileLock = new object();
private string logFilePath = @"C:\RS232_Contact_Logs.txt"; // 自定义日志存储路径

private void LogContactEvent(DateTime timestamp)
{
    lock (_fileLock)
    {
        using (StreamWriter writer = File.AppendText(logFilePath))
        {
            writer.WriteLine($"{timestamp:yyyy-MM-dd HH:mm:ss.fff}");
        }
    }
}

三、每5分钟同步至MSSQL数据库

System.Timers.Timer实现定时任务,每次触发时读取本地日志文件,批量插入数据库,之后可以清空文件(或者标记已同步的行,避免重复插入)。

1. 数据库表设计示例

先在MSSQL中创建日志表:

CREATE TABLE RS232_Contact_Logs (
    Id INT IDENTITY(1,1) PRIMARY KEY,
    ContactTime DATETIME NOT NULL,
    SyncTime DATETIME DEFAULT GETDATE()
)

2. C#定时同步代码

using System.Data.SqlClient;
using System.Timers;

private Timer _syncTimer;
// 替换成你的数据库连接字符串
private string connectionString = "Server=你的服务器IP;Database=你的数据库名;User Id=用户名;Password=密码;";

// 初始化定时器
private void InitSyncTimer()
{
    _syncTimer = new Timer(5 * 60 * 1000); // 5分钟间隔
    _syncTimer.Elapsed += SyncToDatabase;
    _syncTimer.AutoReset = true;
    _syncTimer.Start();
}

private void SyncToDatabase(object sender, ElapsedEventArgs e)
{
    lock (_fileLock)
    {
        if (!File.Exists(logFilePath)) return;

        // 读取日志内容
        string[] lines = File.ReadAllLines(logFilePath);
        if (lines.Length == 0) return;

        // 批量插入数据库
        using (SqlConnection conn = new SqlConnection(connectionString))
        {
            conn.Open();
            using (SqlTransaction tran = conn.BeginTransaction())
            {
                try
                {
                    string insertSql = "INSERT INTO RS232_Contact_Logs (ContactTime) VALUES (@ContactTime)";
                    foreach (string line in lines)
                    {
                        if (DateTime.TryParse(line, out DateTime contactTime))
                        {
                            using (SqlCommand cmd = new SqlCommand(insertSql, conn, tran))
                            {
                                cmd.Parameters.AddWithValue("@ContactTime", contactTime);
                                cmd.ExecuteNonQuery();
                            }
                        }
                    }
                    tran.Commit();
                    // 清空日志文件
                    File.WriteAllText(logFilePath, string.Empty);
                }
                catch (Exception ex)
                {
                    tran.Rollback();
                    // 记录同步失败日志
                    File.AppendText(@"C:\RS232_Sync_Errors.txt").WriteLine($"{DateTime.Now}: {ex.Message}");
                }
            }
        }
    }
}

额外注意事项

  • 权限问题:确保程序有串口访问权限、文件写入权限,以及MSSQL的连接权限。
  • 异常处理:在串口打开、文件操作、数据库连接等环节添加try-catch块,避免程序崩溃。
  • 性能优化:如果接触事件频率很高,建议用内存队列缓存事件,定时批量写入文件,减少IO次数;数据库插入可以用SqlBulkCopy提升批量插入效率。
  • 串口参数:不需要设置波特率、数据位等通信参数,我们只关心引脚状态,保持默认即可。

内容的提问来源于stack exchange,提问作者Kantin Charignon

火山引擎 最新活动