Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.88/25: Рейтинг темы: голосов - 25, средняя оценка - 4.88
 Аватар для USSR_Nic
0 / 0 / 0
Регистрация: 05.04.2017
Сообщений: 14

Чтение данных из COM порта без тормозов на форме

10.11.2017, 12:14. Показов 4932. Ответов 28
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте. Не пинайте сильно, я знаю, что таких тем много на форуме, я их все(по крайней мере, что нащел) перечитал и все равно туплю.
Есть код для обмена данными с COM портом. На форме есть TrackBar и TextBox. (Там еще много чего, но уже не суть).
При движении TrackBar медленно TextBox обновляется более менее прилично, но если TrackBar тащить быстро, то TextBox замирает и данные в нем не обновляются, пока бегунок TrackBar не останавливается. Собственно это единственное, что сильно раздражает и в общем и целом мешает настройке оборудования. Если закомментировать строчку "while ((COMport.BytesToRead < (Length_answer + 2)) && !timer_event) ; //*****СОБСТВЕННО ЭТА СТРОКА ТОРМОЗИТ ФОРМУ****", то данные на форме начинают летать, но связи нет.(хотя иногда почему-то срабатывает)
Если функцию SendCommand вызвать из другого потока, то форма не тормозит.
Теперь собственно вопрос, как переделать код, чтобы основной поток мог вызвать функцию SendCommand и дождаться ответа, но форма при этом не тормозила и связь работала.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
        private void Стандарт_trB_StepMotor_1_Scroll(object sender, EventArgs e)
        {
            //При движении скролла сначала меняем в TextBox положение бегунка
            Стандарт_mTB_Step_1.Text = Convert.ToString(Стандарт_trB_StepMotor_1.Value);
            //Затем отправляем команду в Com порт и ждем ответ.
            byte[] result = SendCommand(Convert.ToByte(Стандарт_cb_AddresController.Text), WriteRegistr, 6, Convert.ToInt16(Стандарт_mTB_Step_1.Text));
        }
 
 
        //Запись/чтение данных в контроллере
        public byte[] SendCommand(byte DeviceAddress, byte Command, short Addres, short Data)
        {
            byte[] Result;
            int CRC_Resive;
            int Счетчик_запросов;
            if (DeviceAddress == 0xFF) { Счетчик_запросов = Количество_запросов; } else { Счетчик_запросов = 0; }
                do
                {
            //Подготовка данных для отправки
                    Счетчик_запросов++;
                    string CommandFull = String.Format("{0:X2}", Math.Abs(DeviceAddress));
                    CommandFull += String.Format("{0:X2}", Math.Abs(Command));
                    CommandFull += String.Format("{0:X4}", Math.Abs(Addres));
                    CommandFull += String.Format("{0:X4}", Data);
                    int Length = 0;
                    // Вычисление длинны ответа от контроллера
                    switch (Command)
                    {
                        case 3:     Length = Data * 2 + 3; break;
                        case 6:     Length = 6; break;
                        case 33:    Length = 512; break;
                    }
                    //Вызов процедуры отправки/получения данных
                    Result = ModbusCommandExecute(CommandFull, Length);
            //Вычисление CRC полученного ответа
                    int CRC_Result = crc16(Result, Length);
                    try
                    {
                        CRC_Resive = Result[Length] * 0x100 + Result[Length + 1];
                    }
                    catch (Exception)
                    {
                        CRC_Resive = 0; Result[0] = 0;
                    }
                    if ((CRC_Result != CRC_Resive) || (Result[0] == 0))
                    {
                        //Если CRC неправильный, увеличиваем счетчик ошибок на линии на 1
                //Через Invoke, потому, что эта процедура вызывается из разных потоков
                        this.BeginInvoke(new WriteStringDelegate(WriteButtonCRC), Convert.ToString(1));
                        Result[0] = 0;
                    }
                    else
                    {
                        this.BeginInvoke(new WriteStringDelegate(WriteButtonCRC), Convert.ToString(0));
                    }
                } while ((Result[0] == 0) && (Счетчик_запросов < Количество_запросов));
            return Result;
        }
 
        //Таймер ожидания ответа от контроллера
        private void timer_Tick(object sender, EventArgs e)
        {
            timer_event = true;
        }
 
        //Процедура отправки/получения данных
        public byte[] ModbusCommandExecute(string command, int Length_answer)               
        {
            //Length_answer-длинна ОТВЕТА без 2х CRC байт
            byte[] result = new byte[512];
            try
            {
                if (COMport.IsOpen)
                {
                    byte[] modbus_bytes = new byte[command.Length / 2];
                    modbus_bytes = StringToByteArray(command);
                    int crc_result = crc16(modbus_bytes, modbus_bytes.Length);
                    byte[] crc_bytes = BitConverter.GetBytes(crc_result);
                    Array.Resize(ref modbus_bytes, modbus_bytes.Length + 2);
 
                    //Отпаравка пакета
                    COMport.Write(modbus_bytes, 0, modbus_bytes.Length);
                    //Получение ответа
                    timer_event = false;
                    tm.AutoReset = false;
                    tm.Interval = 60;
                    tm.Elapsed += timer_Tick;     //Подписываемся на обработчик превышения времени запроса
                    tm.Start();
                    //Ждем, пока нужное кол. байт не упадут в приемный буфер, но не дольше времени ожидания
                    while ((COMport.BytesToRead < (Length_answer + 2)) && !timer_event) ;  //*****СОБСТВЕННО ЭТА СТРОКА ТОРМОЗИТ ФОРМУ****
                    tm.Stop();
                    //Собственно чтение байтов их порта
                    COMport.Read(result, 0, COMport.BytesToRead);
                }
                else
                {
                    MessageBox.Show("Порт не доступен!!! Проверьте настройки соединения");
                }
                return result;
            }
            catch (Exception)
            {
                result[0] = 0;
                return result;
            }
        }
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
10.11.2017, 12:14
Ответы с готовыми решениями:

Чтение данных с COM-порта
Доброго времени суток. Уверен тема поднималась не раз, уже все прочитал разобраться не смог. В общем есть сканер который подключается по...

Чтение данных из COM порта
Добрый день. Требуется написать программу для чтения данных из ком порта на Visual c++ 6.0. Собственно говоря, у меня получилось объявить...

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

28
Эксперт .NET
 Аватар для Usaga
14086 / 9303 / 1348
Регистрация: 21.01.2016
Сообщений: 34,920
10.11.2017, 12:43
USSR_Nic, работайте с COM-портом в другом потоке.
0
 Аватар для USSR_Nic
0 / 0 / 0
Регистрация: 05.04.2017
Сообщений: 14
10.11.2017, 13:18  [ТС]
Идея классная, но как сделать, чтобы основной поток дождался ответа(или неответа) от порта. Например, я двигаю бегунок быстро, и события о его движении возникают чаще, чем успевают приходить ответы от порта. Но пока я не дождусь ответа от порта, нет смысла выполнять следующее событие. Вот тут форма и подвисает...
Я программист хреновый(Зато конструктор хороший). Если можете разжевать с примером буду очень благодарен.
Я например хоть убейте не понимаю, почему я пишу сначала обновить данные в TextBox, а затем делаю вызов функции обмена с портом. А в итоге функция обмена выполняется, а обновление TextBox нет. Вернее я понимаю почему, но где то глубоко внутри. И эта глубина не дает правильно код написать...

Добавлено через 12 минут
А, еще, если я выведу в другой поток получение данных, то как вернуть функции ответ, ведь нужно, чтобы она ответ подождала. А функция эта в основном потоке...
0
Эксперт .NET
 Аватар для insite2012
5548 / 4311 / 1218
Регистрация: 12.10.2013
Сообщений: 12,371
Записей в блоге: 2
10.11.2017, 13:21
Цитата Сообщение от USSR_Nic Посмотреть сообщение
я двигаю бегунок быстро, и события о его движении возникают чаще, чем успевают приходить ответы от порта.
USSR_Nic, прежде всего в таком вопросе (поскольку я сомневаюсь, что у всех на форуме есть такая железяка) расскажите подробно,
1. Что она из себя представляет и как работает
2. Примерная архитектура программы, как и что должно работать, что и с чем взаимодействовать и в какой последовательности.
Тогда шансы получить толковый ответ возрастут очень сильно.
0
Эксперт .NET
 Аватар для Usaga
14086 / 9303 / 1348
Регистрация: 21.01.2016
Сообщений: 34,920
10.11.2017, 13:29
Цитата Сообщение от USSR_Nic Посмотреть сообщение
Идея классная, но как сделать, чтобы основной поток дождался ответа(или неответа) от порта.
Использовать событийный подход. В "рабочем" потоке что-то произошло - извещаем GUI-поток.
0
 Аватар для USSR_Nic
0 / 0 / 0
Регистрация: 05.04.2017
Сообщений: 14
10.11.2017, 13:47  [ТС]
Железяка принимает команду(пересылка в железяку пакета) и отвечает на нее(прием пакета от железяка). Длинна ответа известна заранее.
Структура программы проста. Двигаем TrackBar - возникает событие "Стандарт_trB_StepMotor_1_Scroll" в этом событии я меняю данные в TextBox и вызываю функцию обмена с контроллером, которая собственно и обменивается данными с портом. И возвращает ответ в основной поток. Исходя из этих данных формируется следующая посылка. (В данном мною примере этого не видно) В результате, если события от бегунка сыпятся слишком часто, все работает отлично, но форма подвисает и не обновляет TextBox(и другие контролы). Происходит это потому, что цикл ожидания ответа порта находится в основном потоке и времени на обновление формы у него уже нет. А вот дальше я уже не понимаю. Если я вынесу ожидание ответа порта в другой поток, то мне в основном потоке придется ждать ответа от этого другого потока, и все равно форма будет висеть... Расписал как мог. Мозг уже в тубочке, понятнее я не смогу обьяснить суть проблемы

Добавлено через 3 минуты
Использовать событийный подход. В "рабочем" потоке что-то произошло - извещаем GUI-поток.
Так вроде бы так и написано. Нет?
0
Эксперт .NET
 Аватар для Usaga
14086 / 9303 / 1348
Регистрация: 21.01.2016
Сообщений: 34,920
10.11.2017, 13:49
Цитата Сообщение от USSR_Nic Посмотреть сообщение
Если я вынесу ожидание ответа порта в другой поток, то мне в основном потоке придется ждать ответа от этого другого потока, и все равно форма будет висеть...
Нет. Это вы выдумали только что сами. Когда вы что-то делаете в GUI, то посылаете команду рабочему потоку, а он уже пересылает в устройство. GUI-поток ничего ждать не должен. Когда в рабочем потоке появляются данные, он дёргает событие и GUI поток обновляет состояние окна новыми данными. Если данные не придут, то ничего страшного.

Добавлено через 26 секунд
Цитата Сообщение от USSR_Nic Посмотреть сообщение
Так вроде бы так и написано. Нет?
Нет, раз "зависает".
0
 Аватар для USSR_Nic
0 / 0 / 0
Регистрация: 05.04.2017
Сообщений: 14
10.11.2017, 13:51  [ТС]
Я на форуме много чего прочитал о задержках без подвисания формы и об асинхронном обмене данными с портом, но применить все это в моем случае МНЕ не удается. Наверно туповат. Поэтому и прошу помощи.
0
Эксперт .NET
 Аватар для Usaga
14086 / 9303 / 1348
Регистрация: 21.01.2016
Сообщений: 34,920
10.11.2017, 13:57
USSR_Nic, вы умеете запустить поток? Умеете вызвать событие (event)? Умеете отправить блок кода в Control.Invoke()?
0
 Аватар для USSR_Nic
0 / 0 / 0
Регистрация: 05.04.2017
Сообщений: 14
10.11.2017, 13:58  [ТС]
C#
1
2
3
4
5
 private void Стандарт_trB_StepMotor_1_Scroll(object sender, EventArgs e)
        {
            Стандарт_mTB_Step_1.Text = Convert.ToString(Стандарт_trB_StepMotor_1.Value);
            byte[] result = SendCommand(Convert.ToByte(Стандарт_cb_AddresController.Text), WriteRegistr, 6, Convert.ToInt16(Стандарт_mTB_Step_1.Text));
        }
СНАЧАЛА команда GUI обновить TextBox ЗАТЕМ вызов процедуры обмена. TextBox не обновляется.

Добавлено через 1 минуту
вы умеете запустить поток? Умеете вызвать событие (event)? Умеете отправить блок кода в Control.Invoke()?
В общем скорее да, чем нет.
0
Эксперт .NET
 Аватар для Usaga
14086 / 9303 / 1348
Регистрация: 21.01.2016
Сообщений: 34,920
10.11.2017, 14:03
Цитата Сообщение от USSR_Nic Посмотреть сообщение
В общем скорее да, чем нет.
Воот. Создаёте поток, в котором помещается ВЕСЬ код работы с COM-портом. "Вешаете" его на AutoResetEvent, придумываете способ передачи ему команды\задачи (чаще всего - просто публичное свойство). Когда возникает необходимость что-то передать, суёте ему в публичное свойство данные, "дёргаете" AutoResetEvent, чтобы поток проснулся и забываете. Когда поток закончит работу, то дёрнет какое-нибудь своё событие (на которое GUI-код заранее подпишется), и передаст результаты работы в виде аргумента. GUI поток это дело обработает в своём потоке, через Control.Invoke().
1
 Аватар для USSR_Nic
0 / 0 / 0
Регистрация: 05.04.2017
Сообщений: 14
10.11.2017, 14:15  [ТС]
Пойду думать...
0
[Bicycle Reinventor]
 Аватар для Exerion
332 / 270 / 109
Регистрация: 19.10.2011
Сообщений: 668
Записей в блоге: 2
10.11.2017, 14:27
Тут ещё и проблема в том, что ТС хранит данные в control-ах.

USSR_Nic, Вам текстбокс Стандарт_mTB_Step_1 нужен только для того, чтобы хранить значение трекбара и потом передавать его в команду? Потому что судя по коду, только для этого.
0
 Аватар для USSR_Nic
0 / 0 / 0
Регистрация: 05.04.2017
Сообщений: 14
10.11.2017, 15:14  [ТС]
Вам текстбокс Стандарт_mTB_Step_1 нужен только для того, чтобы хранить значение трекбара и потом передавать его в команду? Потому что судя по коду, только для этого.
Я его там не храню. Я его там показываю. Плюс на форме есть кнопка, по нажатию на которую TrackBar сдвигается на значение от текстбокс.

Добавлено через 58 секунд
Далее происходит событие по передвижению бегунка и далее по тексту.

Добавлено через 15 минут
Все равно не понимаю. Например по нажатию какой-нить кнопки вызывается обработчик, в котором есть:
1. передача в порт данных
2. прием ответа
3. обработка полученных данных и формирование новой команды исходя из полученных данных
4. передача в порт данных
5. прием ответа
6. обработка данных
7. конец обработчика нажатия на кнопку

В пункте 1 я отправляю данные в процедуру, которая оживит поток передачи-приема и передаст данные. Поскольку прием-передача происходят в другом потоке, то код продолжит работу и не дожидаясь получения ответа пошлет следующую команду исходя из непонятно каких данных.
примерно к этому времени поток приема закончит прием данных, дернет событие и через делегат кинет данные. Но они уже никому не нужны. А оборудование на той стороне делает непонятно что.
В общем в башке каша. Читаю мануалы.

Добавлено через 7 минут
Либо нужно перед п. 3 ждать события о получении ответа. И тут все равно ждать...
Или переписывать всю программу сверху до низу. А она не маленькая....
0
[Bicycle Reinventor]
 Аватар для Exerion
332 / 270 / 109
Регистрация: 19.10.2011
Сообщений: 668
Записей в блоге: 2
10.11.2017, 15:16
Цитата Сообщение от USSR_Nic Посмотреть сообщение
TrackBar сдвигается на значение от текстбокс
Я об этом и говорю - вы храните данные в control-ах.
Ну да Бог с ними, это мелочи в сравнении с той проблемой, что вы пытаетесь решить.

Насчёт обработчика клика - разумеется его надо переделать. Если вы просто вынесете часть работы в отдельный поток, всё магически работать не начнёт.

В обработчике клика должно быть только одно - передача потоку данных для отправки и возведение autoresetevent или чем вы там пользуетесь для сигналирования. Всё. Это ваш "пункт 1".
Затем поток отправляет данные, принимает ответ и уже через событие (или как-то иначе) сообщит основному потоку, что пришли данные. Это ваш пункт 2.
В обработчике данного события уже должен выполнится пункт 3. На основном потоке через Invoke.
Далее то же, что и 1.
Далее то же, что и 2.
Снова обработчик события. Готово.
0
 Аватар для USSR_Nic
0 / 0 / 0
Регистрация: 05.04.2017
Сообщений: 14
10.11.2017, 15:16  [ТС]
Есть ли како-нить способ тормознуть код, до события, чтоб он GUI не вешал?
0
[Bicycle Reinventor]
 Аватар для Exerion
332 / 270 / 109
Регистрация: 19.10.2011
Сообщений: 668
Записей в блоге: 2
10.11.2017, 15:19
Естественно нужно ещё завести какой-то флаг/признак, чтобы следить за состоянием передачи и не передавать первый пакет, пока не отправлен второй, базирующийся на содержании ответа от первого. Иначе при каждом движении трекбара у вас побочный поток будет валить первый пакет в канал.
0
 Аватар для USSR_Nic
0 / 0 / 0
Регистрация: 05.04.2017
Сообщений: 14
10.11.2017, 15:20  [ТС]
А как основной код будет ждать между пунктом 1 и 2?
0
[Bicycle Reinventor]
 Аватар для Exerion
332 / 270 / 109
Регистрация: 19.10.2011
Сообщений: 668
Записей в блоге: 2
10.11.2017, 15:21
Цитата Сообщение от USSR_Nic Посмотреть сообщение
Есть ли како-нить способ тормознуть код, до события, чтоб он GUI не вешал?
1. Какой код?
2. В основном потоке или в побочном?
3. Что подразумевается под "событием"? Это штука event или "событие" в общечеловеческом смысле этого слова?
0
 Аватар для USSR_Nic
0 / 0 / 0
Регистрация: 05.04.2017
Сообщений: 14
10.11.2017, 15:24  [ТС]
В основном потоке

Добавлено через 1 минуту
while ((COMport.BytesToRead < (Length_answer + 2)) && !timer_event) ;

Вот строка ожидания ответа она и вешает GUI.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
10.11.2017, 15:24
Помогаю со студенческими работами здесь

Чтение данных с COM порта
Доброго времени, установил javax.comm,в документации указано что: &gt;The javax.comm.properties file must be installed. If it is not, no...

Чтение данных из com-порта
Доброго времени суток! Есть ошибка: &quot;аргуметн типа char несовместим с параметром типа const char&quot; Подскажите как исправить? ...

Чтение данных с COM порта
Есть два оборудования которые между собой подключены через COM. Одно все время передает данные другому. Хочу данные перехватить. Написал...

Чтение данных с COM-порта
Здравствуйте. В ответ на мои запросы, COM порт присылает мне ответ различной длины. Как прочитать полностью то, что он прислал? Я хотел...

Чтение данных из COM порта в массив
задача следующая. прочитать байты приходящие из ком порта и положить их в массив. вот код в котором для теста по нажатию кнопки...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru