Я использую фоновый рабочий для опроса цифрового состояния ввода-вывода с моего 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