C# 工业上位机实时信号边沿检测

171 阅读3分钟

前言

在工业自动化、设备监控等领域,实时信号的边沿检测(如上升沿、下降沿捕捉)是保障系统响应速度和精度的核心需求。传统硬件方案成本高昂,而软件实现常面临信号噪声干扰、动态阈值适配等挑战。

在上位机开发中,经常会涉及到沿信号检测的问题,本文跟大家分享一下如何实现沿信号检测。

沿信号

首先,我们需要了解什么是沿信号:

上升沿:指信号从低电平(False/0)到高电平(True/1)的变化瞬间。

下降沿:指信号从高电平(True/1)到低电平(False/0)的变化瞬间。

在PLC控制或上位机系统中,检测这些变化是非常常见的需求。

例如,在报警状态变化、逻辑信号交互等场景中,沿信号检测都起着关键作用。

代码实现

下面通过C#代码来实现沿信号的检测。

将创建一个类RisingEdgeDetector来模拟PLC中的指令,并通过实例化该类来检测上升沿信号。

1、创建上升沿检测器类

/// <summary>
/// 上升沿检测类(边缘触发检测)
/// </summary>
public class RisingEdgeDetector
{
    private bool _previousState;
    /// <summary>
    /// 初始化检测器
    /// </summary>
    /// <param name="initialState">初始输入状态(默认false)</param>
    public RisingEdgeDetector(bool initialState = false)
    {
        _previousState = initialState;
    }
    /// <summary>
    /// 检测输入信号的上升沿变化
    /// </summary>
    /// <param name="currentState">当前输入状态</param>
    /// <returns>是否检测到上升沿</returns>
    public bool CheckForRisingEdge(bool currentState)
    {
        bool edgeDetected = !_previousState && currentState;
        _previousState = currentState;
        return edgeDetected;
    }
    /// <summary>
    /// 重置检测器状态
    /// </summary>
    public void Reset(bool initialState = false)
    {
        _previousState = initialState;
    }
}

2、实际使用

使用这个类非常简单,只需创建一个RisingEdgeDetector对象,并调用其方法即可。

以下是一个简单的示例:

// 初始化检测器(可选设置初始状态)
var edgeDetector = new RisingEdgeDetector();

// 模拟输入序列
bool[] inputSequence = { falsefalsetruetruefalsetrue };

foreach (var input in inputSequence)
{
    bool detected = edgeDetector.CheckForRisingEdge(input);
    Console.WriteLine($"输入 {input} \t 检测到上升沿: {detected}");
}

输出结果:

输入 False     检测到上升沿: False
输入 False     检测到上升沿: False
输入 True      检测到上升沿: True
输入 True      检测到上升沿: False
输入 False     检测到上升沿: False
输入 True      检测到上升沿: True

3、增加防抖动和线程安全

为了应对实际应用中的信号抖动问题,我们可以在原有基础上增加防抖动功能。同时,为了确保多线程环境下的线程安全,我们在方法中使用了锁机制。

通过这种方式,我们可以有效地检测信号的变化并处理潜在的问题,如信号抖动和并发访问。希望这段代码能帮助大家更好地理解和实现沿信号检测的功能。

/// <summary>
/// 带消抖处理的上升沿检测器(精确到毫秒级)
/// </summary>
public class DebouncedRisingEdgeDetector
{
    private bool _previousState;
    private DateTime _lastTriggerTime = DateTime.MinValue;
    private readonly int _debounceMs;
    private readonly object _lock = new object();
    /// <summary>
    /// 初始化消抖检测器
    /// </summary>
    /// <param name="debounceMilliseconds">消抖时间(毫秒)</param>
    /// <param name="initialState">初始输入状态</param>
    public DebouncedRisingEdgeDetector(int debounceMilliseconds, bool initialState = false)
    {
        _debounceMs = debounceMilliseconds > 0 ? debounceMilliseconds : 10;
        _previousState = initialState;
    }
    /// <summary>
    /// 检测输入信号的有效上升沿
    /// </summary>
    public bool CheckForRisingEdge(bool currentState)
    {
        lock (_lock)
        {
            bool edgeDetected = false;
            bool potentialEdge = !_previousState && currentState;
            if (potentialEdge)
            {
                TimeSpan elapsed = DateTime.UtcNow - _lastTriggerTime;
                if (elapsed.TotalMilliseconds > _debounceMs)
                {
                    edgeDetected = true;
                    _lastTriggerTime = DateTime.UtcNow;
                }
            }
            _previousState = currentState;
            return edgeDetected;
        }
    }
    /// <summary>
    /// 重置检测器状态
    /// </summary>
    public void Reset(bool initialState = false)
    {
        lock (_lock)
        {
            _previousState = initialState;
            _lastTriggerTime = DateTime.MinValue;
        }
    }
}

4、测试结果

// 初始化50ms消抖的检测器
var debounceDetector = new DebouncedRisingEdgeDetector(50);
// 模拟带抖动的输入序列
bool[] noisyInputs = { falsetruefalsetruetruefalsetruetrue };
foreach (var input in noisyInputs)
{
    bool validEdge = 
    debounceDetector.CheckForRisingEdge(input);
    Console.WriteLine($"输入 
    {input,-5} 有效触发: {validEdge}");
    // 模拟实际应用中的时间间隔
    Thread.Sleep(30); 
}

输出结果

输入 False 有效触发: False
输入 True  有效触发: True  ← 首次触发
输入 False 有效触发: False
输入 True  有效触发: False ← 30ms后仍在消抖期
输入 True  有效触发: False
输入 False 有效触发: False
输入 True  有效触发: True  ← 超过50ms后再次触发
输入 True  有效触发: False

5、对于下降沿检测,原理是相通的

我们可以参考上述代码编写一个下降沿检测的类,也可以将上升沿和下降沿检测放到同一个类中,通过构造方法传值来判断为上升沿或下降沿。

总结

本文介绍了如何通过C#代码实现沿信号检测,包括上升沿和下降沿的概念及其应用场景。

通过创建一个RisingEdgeDetector类,我们能够方便地检测信号变化,并且增加了防抖动和线程安全的功能,以应对实际应用中的复杂情况。

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。

也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!

优秀是一种习惯,欢迎大家留言学习!

作者:上位机付工

出处:mp.weixin.qq.com/s/NSTpKN_WVM-X4cDUABfr1w

声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!