Modbus读写值冲突

我和我的同事在做一个项目,其中一些物理设备连接到 Modbus 接口(例如 Lamp),以及一个桌面应用程序,我们使用 nmodbus 包向 modbus 发送请求,并且不时(例如每 1第二)从 Modbus 读取数据。我们有一个经典的读/写冲突。读取没有问题,但有时当我们向 modbus 写入新值时,物理灯会发疯并每 1 秒改变一次状态。

从 modbus 读取数据是不同的任务,因此向 modbus 写入新值也是如此。

我们尝试过的:

  • 锁定临界区(仅写入),并在新值到来时忽略读取数据。之后,我们遇到了队列问题并且工作非常缓慢
  • CancellationToken - 没有效果,或者我写的不好

目前我们有一个类收集上次状态变化的属性日期(在 IoC 中注册),当新的写入值到来时,我们更新这个属性,并阻止从 Modbus 读取数据。不幸的是,这段代码有时有效,有时无效。

请帮忙。我们对这个问题很着迷,不知道如何解决。

编辑:我发布当前代码。

这是我们执行 getcurrentState 处理程序的任务

    public void Start()
{
    var cancellationToken = _cancellationTokenSource.Token;

    Task.Run(async () =>
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            await Task.Delay(ReadStateDelayInmiliseconds).ConfigureAwait(false);

            if ((DateTime.Now - _lastCommandExecutionTimeContainer.LastCommandExecutionTime).TotalMilliseconds < _userCommandThresholdInmiliseconds)
                continue;

            try
            {
                await _service.getcurrentState().ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                Logger.Error($"Error while checking current state. Message '{ex.Message}',Stack trace: '{ex.StackTrace}'.");
            }

        }
    },cancellationToken);
}

这是 getcurrentState 处理程序,我们从 Modbus 读取数据

    protected override IgnisLightState Handle(GetState request)
{
    if ((DateTime.Now - _lastCommandExecutionTimeContainer.LastCommandExecutionTime).TotalMilliseconds <= _configuration.UserCommandThresholdInmiliseconds)
    {
        Logger.Debug($"Ignore before read state from lights,time after last execution: '{(DateTime.Now - _lastCommandExecutionTimeContainer.LastCommandExecutionTime).TotalMilliseconds}'.");
        return _state;
    }

    var currentLightState = _state.DeepClone();

    foreach (var head in currentLightState.Heads)
    {
        try
        {
            ushort startAddress = 0x0000;
            ushort numberOfPointsToRead = 0x0006;

            var values = _modbusMaster.ReadHoldingRegisters((byte)head.UniqueId,startAddress,numberOfPointsToRead);

            var isOn = values[IgnisRegistry.On.Value];
            var isEndo = values[IgnisRegistry.Endo.Value];
            var isCentrum = values[IgnisRegistry.Centrum.Value];
            var tempValue = values[IgnisRegistry.Temp.Value];
            var illuminanceValue = values[IgnisRegistry.Vol.Value];

            head.ColorValue = Convert.ToInt32(tempValue);
            head.IlluminanceValue = Convert.ToInt32(illuminanceValue);
            head.IsCentrumOn = Convert.ToBoolean(isCentrum);
            head.IsEndoOn = Convert.ToBoolean(isEndo);
            head.IsTurnedOn = Convert.ToBoolean(isOn);

            if (currentLightState.CameraState != null &&
                _configuration.CameraHeadId.HasValue &&
                _configuration.CameraHeadId.Value == head.UniqueId)
            {
                var camMode = values[IgnisRegistry.Cam.Value];

                currentLightState.CameraState.IsTurnedOn = Convert.ToBoolean(isOn);
                currentLightState.CameraState.CurrentMode = (IgnisCameraMode)Convert.ToInt32(camMode);
            }
        }
        catch (Exception ex)
        {
            Logger.ErrorFixed(ex,$"Error while getting data from headId {head.UniqueId}.");
        }
    }

    if (_state.Equals(currentLightState)
        || (DateTime.Now - _lastCommandExecutionTimeContainer.LastCommandExecutionTime).TotalMilliseconds < _configuration.UserCommandThresholdInmiliseconds)
    {
        Logger.Debug($"Ignore after read state from lights,time after last execution: '{(DateTime.Now - _lastCommandExecutionTimeContainer.LastCommandExecutionTime).TotalMilliseconds}'.");
        return _state;
    }

    foreach (var currentHeadState in currentLightState.Heads)
    {
        _lightHeadStateUpdater.UpdateState(currentHeadState);
    }

    Logger.Debug($"Broadcast new state to clients '{JsonConvert.SerializeObject(currentLightState)}'.");
    _hubContext.Clients.All.StateChanged(currentLightState);

    return currentLightState;
}

这是一个打开灯处理程序,我们将新值写入 modbus:

    protected override Response Handle(TurnOn request)
{
    _lastCommandExecutionTimeContainer.SetLastCommandExecutionTime(DateTime.Now);

    if (request.HeadId <= 0
        || !_state.Heads.Any(x=>x.UniqueId == request.HeadId))
    {
        return ResponseFactory.FromError(Error.NotExist);
    }

    var headState = _state.Heads.Single(x=>x.UniqueId == request.HeadId);

    if (headState.IsTurnedOn)
        return ResponseFactory.FromError(Error.AlreadyAsRequested);

    _modbusMaster.WriteSingleRegister((byte)request.HeadId,IgnisRegistry.On.Value,0x0001);
    headState.IsTurnedOn = true;

    if (_state.CameraState != null &&
        _ignisLightConfiguration.CameraHeadId.HasValue &&
        _ignisLightConfiguration.CameraHeadId.Value == request.HeadId)
    {
        _state.CameraState.IsTurnedOn = true;
    }


    Logger.Trace($"Turn head lamp {request.HeadId} on.");
    _hubContext.Clients.All.HeadStateChanged(headState);

    return ResponseFactory.Success;
}
zxcvbnm__ 回答:Modbus读写值冲突

暂时没有好的解决方案,如果你有好的解决方案,请发邮件至:iooj@foxmail.com
本文链接:https://www.f2er.com/984044.html

大家都在问