Как сделать фоновый результат согласованным - PullRequest
0 голосов
/ 28 января 2020

Я использую фоновый рабочий для опроса цифрового состояния ввода-вывода с моего PL C через MODBUS через последовательный COM-порт. Фоновый рабочий используется только для операции READ со скоростью опроса 200 мс между каждым циклом. Количество операций ввода-вывода для чтения в одном цикле составляет около 50 бит (1 состояние = 1 логическое значение). Затем я имитирую команду WRITE для PL C, переключая все входы / выходы в противоположное состояние (ON -> OFF / OFF -> ON) из потока пользовательского интерфейса. Я помещаю подпрограмму Toggle () в таймер с интервалом 100 мс и выполняю в течение 3000 мс. В результате некоторые порты не соответствуют друг другу. Начальное состояние - либо все включено, либо все выключено. Ожидаемый результат после переключения также либо полностью включен, либо полностью выключен. Иногда конечный результат равен 45 и включается и 5 - выключается. Иногда он выключен на 40 и 10 вкл. Результат всегда является случайным, но никогда не является правильным результатом, когда все включено или выключено.

Интересно, что если я использую Таймер вместо фонового работника для опроса, результат переключения всегда будет согласованным (все 50 IO либо ВКЛ или ВЫКЛ). Я предпочитаю использовать фоновый рабочий для опроса, потому что пользовательский интерфейс намного плавнее. Когда я использую таймер, пользовательский интерфейс чувствует себя немного "лагом". Однако фоновый работник вызывает противоречивый результат.

Ниже приведена упрощенная версия моих кодов для иллюстрации моей ситуации. Я надеюсь, что кто-то может указать мне правильное направление. Фоновый рабочий работает нормально, опрашивая состояние io. Но как только я манипулирую портом из потока пользовательского интерфейса, команда не гарантируется на 100% выполнение в любое время, что является серьезной проблемой для меня!

Я поместил операцию чтения MODBUS в подпрограмму DoWork. подпрограммы и передать результат чтения в поток пользовательского интерфейса, используя Backgroundworker.ReportProgress (0, objResult). Следовательно, операции чтения и записи объекта происходят в одном и том же потоке пользовательского интерфейса. Почему результат все еще противоречив?

Public Class Bit

Private _LastValue As Boolean
Private _Label As Control
Private DictControl As New Dictionary(Of String, Control)

Sub SetCoil(val As Boolean)
    'Do work here

    'Update last value
    SetLastValue(val)
End Sub

Function GetCoil() As Boolean
    Dim result As Boolean = True
    'Do work here

    'Update last value
    SetLastValue(result)

    Return result
End Function

Sub Toggle()
    Dim result As Boolean = Not _LastValue
    'invert current value
    'set current value = not current value

    'Update last value
    SetLastValue(result)
End Sub

Sub SetLastValue(val As Boolean)
    _LastValue = val

    Dim ctlText As String = ""

    If _LastValue = True Then
        ctlText = "ON"
    Else
        ctlText = "OFF"
    End If

    'Update label
    For Each c As KeyValuePair(Of String, Control) In DictControl
        c.Value.Text = ctlText
    Next

End Sub

Sub AddControl(key As String, c As Control)
    DictControl.Add(key, c)
End Sub

End Class

Public Class Main

Const BIT_COUNT = 50
Dim bgw As New System.ComponentModel.BackgroundWorker
Dim dictBit As New Dictionary(Of Integer, Bit)

Sub New()
    'Create a bunch of label and bit instances
    'Add label control to Bit
    'Add Bit to dictBit dictionary
    'Add Handler to Background Worker
    'Run Background Worker
    'Run Timer
End Sub

Sub bgw_DoWorkHandler(sender As Object, e As System.ComponentModel.DoWorkEventArgs)
    Dim Coils(49) As Boolean
    Dim result() As Boolean
    Dim run As Boolean = True

    Do
        'Do some processing & assign Coils value

        result = Coils.Clone 'Duplicate the variable
        bgw.ReportProgress(0, result)
        Sleep(300)
    Loop While run = True

End Sub

Sub bgw_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs)
    Dim results() As Boolean = DirectCast(e.UserState, Boolean())

    Dim i As Integer

    For i = 0 To UBound(results)
        If dictBit.ContainsKey(i) Then
            dictBit(i).SetLastValue(results(i)) 'Set last value and update Label
        End If
    Next
End Sub

Sub TimerTickHandler(ByVal sender As Object, ByVal e As EventArgs)
    'Background worker alternative.
    Dim Coils(49) As Boolean
    Dim result() As Boolean
    Dim run As Boolean = True

    'Do some work & assign Coils value
    result = Coils.Clone
    bgw.ReportProgress(0, result)

End Sub

Sub ToggleBits()
    Dim i As Integer

    For i = 0 To BIT_COUNT - 1
        dictBit(i).Toggle()
    Next
End Sub

Sub TimerToggleHandler(ByVal sender As Object, ByVal e As EventArgs)
    'Interval = 100 ms. Run for 3000 ms before stop.
    ToggleBits()
End Sub

End Class

1 Ответ

0 голосов
/ 05 февраля 2020

Фоновый рабочий читает IO во время переключения. Вот почему все 50 баллов не имеют одинаковое значение.

Фактические аппаратные входы могут измениться в любое время. Даже доли секунды до или после вашего чтения. Если эта процедура переключения предназначена только для тестирования, игнорируйте расхождения. В противном случае обновите флаг или запустите событие в конце переключателя. Что-нибудь, чтобы заставить BW ждать, пока переключение не будет завершено, перед чтением

...