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

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

10.11.2017, 12:14. Показов 4939. Ответов 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
[Bicycle Reinventor]
 Аватар для Exerion
332 / 270 / 109
Регистрация: 19.10.2011
Сообщений: 668
Записей в блоге: 2
10.11.2017, 15:24
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от USSR_Nic Посмотреть сообщение
А как основной код будет ждать между пунктом 1 и 2?
Хмм... никак? Вам не нужно об этом думать.
Как только обработчик клика завершил работу (первый пункт завершился), основной поток просто будет простаивать и обрабатывать события от ОС как обычно. Вам не нужно ничего делать. Это тот же штатный режим, как если бы никакого нажатия на кнопку вовсе не было.
Вторичный поток в это время будет делать своё дело, и вызовет event когда закончит. В подписке на event должен быть произведен Invoke, чтобы последнующий код выполнялся в основном потоке. Так результаты дойдут до основного потока.
0
 Аватар для USSR_Nic
0 / 0 / 0
Регистрация: 05.04.2017
Сообщений: 14
10.11.2017, 15:25  [ТС]
Именно эта строка стоит между п.1 и п.2
0
[Bicycle Reinventor]
 Аватар для Exerion
332 / 270 / 109
Регистрация: 19.10.2011
Сообщений: 668
Записей в блоге: 2
10.11.2017, 15:25
Цитата Сообщение от USSR_Nic Посмотреть сообщение
она и вешает GUI.
Она вешает ГУИ потому что она должна быть в отдельном потоке. Эта строка не должна быть "между" пунктами, это и есть пункт 2.
0
 Аватар для USSR_Nic
0 / 0 / 0
Регистрация: 05.04.2017
Сообщений: 14
10.11.2017, 15:32  [ТС]
у меня эта функция вызывается из сотни мест. Если все полученные данные обрабатывать только в обработчике получения данных то у меня вся программа засунется в этот обработчик.
0
[Bicycle Reinventor]
 Аватар для Exerion
332 / 270 / 109
Регистрация: 19.10.2011
Сообщений: 668
Записей в блоге: 2
10.11.2017, 15:42
Логично, что нужно
Цитата Сообщение от USSR_Nic Посмотреть сообщение
все полученные данные обрабатывать только в обработчике получения данных
для этого он и нужен.


Но это уже вопросы архитектуры программы. Вы свой ответ получили и уже давно: чтобы форма не висла, весь обмен данными (особенно бесконечные / длинные циклы while) нужно выполнять в отдельном потоке. Как это сделать - есть миллион и ещё десять разных способов.

У меня складывается впечатление, что из-за долгой работы над задачей, у вас замылился взор. Рекомендую отложить её в сторонку, взять msdn, и внимательно там изучить следующие вопросы:
1. Thread. Что такое, как создавать, запускать, блокировать, чем отличается от основного потока.
2. AutoResetEvent и прочие механизмы синхронизации потоков. Как усыпить побочный поток и разбудить с помощью AutoResetEvent.
3. ключевое слово event. Создание событий, вызов событий, подписка на события.
4. Invoke и InvokeRequired. Выполнение кода в основном потоке из побочного.

Это четыре вещи (именно в таком порядке), которые вам необходимо реализовать (как минимум) для решения проблемы зависания формы. С полученными знаниями можно будет вернуться к задаче и переосмыслить её.
Если у вас код, блокирующий поток, вызывается из сотни мест, что ж.. придётся пересмотреть свою архитектуру.
0
 Аватар для USSR_Nic
0 / 0 / 0
Регистрация: 05.04.2017
Сообщений: 14
10.11.2017, 15:54  [ТС]
Бум думать...

Добавлено через 26 секунд
Спасибо Всем.
0
Эксперт .NET
 Аватар для insite2012
5548 / 4311 / 1218
Регистрация: 12.10.2013
Сообщений: 12,371
Записей в блоге: 2
10.11.2017, 16:17
Цитата Сообщение от USSR_Nic Посмотреть сообщение
дальше я уже не понимаю.
Хм... Исходя из вашего вИдения задачи, я бы предложил следующий подход.
Отдельный класс для обмена с портом. В нем метод, стартующий поток.
В потоке бесконечный цикл (с признаком отмены). Также в классе есть очередь, куда вы и складываете все команды от ГУИ.
Если очередь пуста-рабочий поток ждет на AutoResetEvent, только в очереди что-то появилось - идет выполнение это задачи, проверка очереди и так далее.
Соответственно, в данном классе должны быть события уведомления ГУИ о прогрессе/результатах обработки и метод, который добавляет очередное задание/задания в очередь.
Вот примерно такая структура, думаю, будет вполне работоспособна.
0
 Аватар для USSR_Nic
0 / 0 / 0
Регистрация: 05.04.2017
Сообщений: 14
10.11.2017, 16:44  [ТС]
Странно как-то, но задача неперерисовки текстбокса решилась командой
Стандарт_mTB_Step_1.Update();
между изменением тексбокса и вызовом процедуры обмена.

Добавлено через 35 секунд
А в остальном и так все хорошо работает.
0
burning1ife
 Аватар для kenny69
1466 / 1287 / 294
Регистрация: 21.09.2008
Сообщений: 3,438
Записей в блоге: 9
10.11.2017, 19:31
А нельзя ли просто делать вызовы к COM порту, когда перестали перетаскивать track?
Или поэкспериментировать с TickFrequency, чтобы уменьшить кол-во обращений к COM порту.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
10.11.2017, 19:31
Помогаю со студенческими работами здесь

Чтение данных с 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 порта в массив
задача следующая. прочитать байты приходящие из ком порта и положить их в массив. вот код в котором для теста по нажатию кнопки...


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

Или воспользуйтесь поиском по форуму:
29
Ответ Создать тему
Новые блоги и статьи
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