gayansudara Ответов: 1

Как запустить 5 или более таймеров или потоков для чтения значений внешних устройств (шкал) одновременно, не застревая, в VB или c#.net


I tried to read a value with one timer. It worked well. But I used 4 timers to read 4 scale values, it was not working well, it was delayed to display values, numbering series is wrong highly. 
Eg: Want to show increasing or decreasing values such as : 1-2-3-4-5-6
But it show as : 1--- delayed few second---  50 --- delayed few second---  120


Что я уже пробовал:

С одним таймером и считыванием только одного значения
------------------------------------------------------
Public Class Form4
    Dim intR() As Short, blnX() As Boolean
    Delegate Sub SetTextCallback2()
    Dim f_err As Fatek_Error_Code = New Fatek_Error_Code

    Private Sub Form4_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        f_Plc = New FatekNet.FatekPLCNet("192.168.1.3", 500)
        f_Plc.Connect() : Timer1.Enabled = True 
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Timer1.Stop()
        CountNo()
        Timer1.Start()
    End Sub

    Private Sub CountNo() 'ByVal intValue As Integer
        If Label1.InvokeRequired Then
            Dim d As New SetTextCallback2(AddressOf CountNo)
            Label1.Invoke(d) ', New Object() {intValue}) '
        Else
            Label1.Text = 1 : Call ReadServices()
        End If
    End Sub

    Private Sub ReadServices()
        Try
            intR = f_Plc.Read_Continuous(Fatek_Register_Area.HR, 1, 52, Fatek_Data_Type.Short, f_err)
            TextBox1.Text = intR(0)
        Catch ex As Exception
        End Try
    End Sub
End Class


----------------------------------------------------
Код проблемы таков
--------------------------------------------------
Public Class Form5
    Dim shtR1(), shtR2(), shtR3(), shtR4() As Short
    Delegate Sub SetTextCallback2()
    Dim f_err As Fatek_Error_Code = New Fatek_Error_Code

    Private Sub Form5_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        f_Plc = New FatekNet.FatekPLCNet("192.168.1.3", 500)
        f_Plc.Connect()
        Timer1.Enabled = True : Timer2.Enabled = True : Timer3.Enabled = True : Timer4.Enabled = True
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Timer1.Stop()
        CountNo1()
        Timer1.Start()
    End Sub

    Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer2.Tick
        Timer2.Stop()
        CountNo2()
        Timer2.Start()
    End Sub

    Private Sub Timer3_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer3.Tick
        Timer3.Stop()
        CountNo3()
        Timer3.Start()
    End Sub

    Private Sub Timer4_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer4.Tick
        Timer4.Stop()
        CountNo4()
        Timer4.Start()
    End Sub

    Private Sub CountNo1() 'ByVal intValue As Integer
        If Label1.InvokeRequired Then
            Dim d As New SetTextCallback2(AddressOf CountNo1)
            Label1.Invoke(d) ', New Object() {intValue}) '
        Else
            Label1.Text = 1 : Call ReadServices1()
        End If
    End Sub

    Private Sub CountNo2() 'ByVal intValue As Integer
        If Label1.InvokeRequired Then
            Dim d As New SetTextCallback2(AddressOf CountNo2)
            Label1.Invoke(d) ', New Object() {intValue}) '
        Else
            Label1.Text = 1 : Call ReadServices2()
        End If
    End Sub

    Private Sub CountNo3() 'ByVal intValue As Integer
        If Label1.InvokeRequired Then
            Dim d As New SetTextCallback2(AddressOf CountNo3)
            Label1.Invoke(d) ', New Object() {intValue}) '
        Else
            Label1.Text = 1 : Call ReadServices3()
        End If
    End Sub

    Private Sub CountNo4() 'ByVal intValue As Integer
        If Label1.InvokeRequired Then
            Dim d As New SetTextCallback2(AddressOf CountNo4)
            Label1.Invoke(d) ', New Object() {intValue}) '
        Else
            Label1.Text = 1 : Call ReadServices4()
        End If
    End Sub

    Private Sub ReadServices1()
        Try
            shtR1 = f_Plc.Read_Continuous(Fatek_Register_Area.HR, 1, 52, Fatek_Data_Type.Short, f_err)
            TextBox1.Text = shtR1(0)
        Catch ex As Exception
        End Try
    End Sub
    Private Sub ReadServices2()
        Try
            shtR2 = f_Plc.Read_Continuous(Fatek_Register_Area.HR, 1, 60, Fatek_Data_Type.Short, f_err)
            TextBox2.Text = shtR2(0)
        Catch ex As Exception
        End Try
    End Sub
    Private Sub ReadServices3()
        Try
            shtR3 = f_Plc.Read_Continuous(Fatek_Register_Area.HR, 1, 56, Fatek_Data_Type.Short, f_err)
            TextBox3.Text = shtR3(0)
        Catch ex As Exception
        End Try
    End Sub
    Private Sub ReadServices4()
        Try
            shtR4 = f_Plc.Read_Continuous(Fatek_Register_Area.HR, 1, 42, Fatek_Data_Type.Short, f_err)
            TextBox4.Text = shtR4(0)
        Catch ex As Exception
        End Try
    End Sub
End Class

1 Ответов

Рейтинг:
1

OriginalGriff

Не используйте несколько таймеров: установите один таймер на минимальный интервал (поэтому, если вы хотите обновления один раз в секунду, установите таймер на полсекунды) и внутри одного обработчика тиков проверьте текущее время против времени "следующего обновления" для каждого ПЛК.

Другая проблема заключается в том, что мы понятия не имеем, что делает ваш метод "Read_Continuous" или как он это делает. Если это блокирующий вызов, то он не возвращается до тех пор, пока полностью не прочитает сообщение / значение, а это может занять некоторое время в компьютерных терминах - и пока блокируется пользовательский интерфейс, он не обновляется, и больше ничего не происходит.

Что может быть лучшим решением, так это запустить каждый из ваших масштабных считывателей в отдельном потоке - BackgroundWorker имеет встроенный отчет о прогрессе, который позволит вам легко обновить ваш дисплей без необходимости что - либо вызывать-и использовать Sleep внутри каждого потока вместе со значением "время следующего обновления", чтобы ваши чтения выполнялись через соответствующие интервалы времени.


gayansudara

Функция Read_Continuous такова...
------------------------------------------

Общественные Read_Continuous функции(f_area бывал как Fatek_Register_Area, Граф бывал как целое, start_add бывал как целое, return_type бывал как Fatek_Data_Type, как byref err_code как Fatek_Error_Code) как массив
'Если ссылка ничего не значит, то бросьте новое исключение FatekException("объект еще не инициализирован!")
-Тусклый сетевой поток как сеть.Разъемы.NetworkStream = носок.Метод getstream()
Тусклый сетевой поток как сеть.Разъемы.Объекте networkstream
Попробуй
networkStream = носок.Метод getstream()
Поймать ex как исключение
Ничего Не Возвращайте
Конец Попытки
Если нет ISConnect, то бросьте новое исключение FatekException("сетевой порт не открыт")
Если UnitAddress < 1 или UnitAddress > &HFE затем выбрасывают новое исключение FatekException("Unit Address is invalid")
Если f_area < Fatek_Register_Area.Ч тогда
Если start_add < 0 или start_add > 255, то бросьте новое исключение FatekException("недопустимый диапазон регистров")
Еще
Если start_add < 0 или start_add > 99999, то бросьте новое исключение FatekException("недопустимый диапазон регистров")
Конец, Если
Если Count < 1 или Count > 64, то бросьте новое исключение FatekException("счетчик не находится в диапазоне!")
Если (start_add < 200) и ((start_add + Count) > 199) Затем бросьте новое исключение FatekException("диапазон счетчиков не соответствует!")

Dim lng_length As Integer = 0, str_in As String = ""
Dim length_predicted As Integer = 9 + (Count * IIf(f_area = Fatek_Register_Area.CTR, IIf(start_add < 200, 4, 8), 4)), tmr_indicator As Long = 0
Если Count = 256, То Count = 0

Dim str_out As String = STX & _
Mid$(Hex(UnitAddress).PadLeft(2, "0"c), Hex(UnitAddress).PadLeft(2, "0"c).длина - 1, 2) & _
Середина$(В Шестнадцатеричном Виде(Fateck_Command_Header.Read_Continuous_Register), Шестигранные(Fateck_Command_Header.Read_Continuous_Register).Длина - 1, 2) & _
Гекс(Граф).PadLeft(2, "0"c) & _
(f_area) &ампер str_Register_Area; _
start_add.Метод toString.PadLeft(IIf(f_area < Fatek_Register_Area.HR, 4, 5), "0"c)
str_out = str_out &амп; GetChecksum_Str(str_out) &ампер; ЕТХ
'С помощью MsgBox(str_out)
lng_length = ((length_predicted * ByteTime) * 1000 + delay_ms) * TimeSpan.Тикспермиллисекунда
- Сделай простую запись.
Dim sendBytes As [Byte]() = кодировка.ASCII.Метод getbytes(str_out)
сетевой поток.Write(sendBytes, 0, sendBytes.Длина)
- Считайте сетевой поток в байтовый буфер.
Дим байт(носок.ReceiveBufferSize) В Виде Байта
Попробуй
объекте networkstream.ReadTimeout = 1
networkStream.Read(bytes, 0, CInt(sock.ReceiveBufferSize))
Поймать ex как исключение
Ничего Не Возвращайте
Конец Попытки

- Выведите данные, полученные от хоста, на консоль.
str_in = кодировка.ASCII.GetString(байты)

'MsgBox(str_in)
Если (str_in.Длина < length_predicted) Затем бросьте новое исключение FatekException("ошибка в строке данных, данные повреждены!")
Если GetChecksum_Str(Mid$(str_in, 1, 10)) <> Mid$(str_in, 11, 2), то бросьте новое исключение FatekException("ошибка контрольной суммы, пожалуйста, проверьте строку!")
err_code = Val(Mid$(str_in, 6, 1))
Dim str_in_final As String = Mid$(str_in, 7, 4)
Dim arr_out As Array = Nothing
Если return_type = Fatek_Data_Type.Затем байт возвращается (Hex2ByteArr(str_in_final))
Если return_type = Fatek_Data_Type.Затем Char возвращает (str_in_final.ToCharArray)
Если return_type = Fatek_Data_Type.Двухместный потом вернуться (Hex2DoubleArr(str_in_final))
Если return_type = Fatek_Data_Type.Целое Число T

gayansudara

Если return_type = Fatek_Data_Type.Число тогда возврат (Hex2IntArr(str_in_final))
Если return_type = Fatek_Data_Type.Короче потом вернуться (Hex2ShortArr(str_in_final))
Если return_type = Fatek_Data_Type.Один потом вернуть (Hex2SingleArr(str_in_final))
Если return_type = Fatek_Data_Type.UShort затем возвращает (Hex2WordArr(str_in_final))
Вернуться arr_out
Конечная Функция

------------------------------------------------------

Можете ли вы показать мне пример кода, который работает с отдельным потоком - BackgroundWorker?
Большое вам спасибо за Вашу поддержку.

OriginalGriff

Посмотрите на документацию MSDN для BackgroundWorker: она включает в себя базовый пример.
https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=против 110).aspx

gayansudara

Компонент BackgroundWorker будет застрять или замерзнуть, когда я сверну или разверну форму

OriginalGriff

Нет, это не так - это отдельный поток, который не связан с потоком пользовательского интерфейса, вот и вся идея...