Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/6: Рейтинг темы: голосов - 6, средняя оценка - 4.67
0 / 0 / 0
Регистрация: 10.12.2016
Сообщений: 18

Опять про COM порт

26.04.2017, 14:38. Показов 1485. Ответов 18
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте. Наверняка данный вопрос уже неоднократно появлялся, но т.к. я к сожалению не программист, а скорей "железяньщик", то заранее прошу простить. Итак есть железка, которая принимает команды по последовательному порту, а потом по нему же передаёт некоторые данные, предварительно упакованные в пакет. Количество пакетов передаваемых между командами не ограничено. С портом я работаю с помощью ф-ций WINAPI (create file и т.д.). Всего в программе 3 потока (1 записи в порт, 1 чтения из порта и 1 активируется потоком чтения и осуществляет отображение данных в Memo и ListBox). Так вот мне понадобилось отображать содержимое принятых пакетов в строку (точнее 1пакет, 1 строка). Я сделал это следующим образом:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
DWORD WINAPI Thread_ListBox(LPVOID) // поток вывода данных в Memo и ListBox
  {
    String str;
     while ( TRUE )
     {
        WaitForSingleObject( hEventListBox, INFINITE ); // Ожидаем пока поток чтения активизирует данный поток
        
        str = NULL;                 // Обнуляем промежуточный буфер для преобразования столбик -> строка    
        
        for(int i = 0; i < btr1; i++)
        {
            Form1 -> ListBox1 -> Items -> Add(IntToHex((int)BufRx[i], 2));  // В ListBox выводим данные в столбик 
            str += IntToHex(BufRx[i],2);                    // Заполняем наш временный буффер столбик -> строка
        }
        Form1 -> Memo1->Lines-> Add( str );                     // Выводим данные в строчку в Memo1
 
        
     }
  }
Но как известно COM очень рандомно определяет сколь ко же ему пришло данных и соответственно рандомно их и выплёвывает (скажем послал я ему 10 байт, а он выплюнул ,например, сначала 8 потом 2). Ну и естественно длинна строк ползёт (в какой то пол пакета а в какой то их 3 и т.д.). Количество байт в пакете я в принципе знаю и посчитать наверное смогу, но вот если вдруг чугуняка перестанет передавать данные (провод отвалится или ещё что то хитрое), то программка встанет пока ей не придёт необходимое количество байт. Так вот понятно, что нужно поставить какой то таймер, но вот как бы это получше сделать не совсем понятно. Может кто то сможет подсказать?
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
26.04.2017, 14:38
Ответы с готовыми решениями:

Опять про связь таблиц
Как бы покороче. Есть две таблицы 1. Sector(Name, Code) сектор 2. Line(Name, Code, Sector) линия Вторая таблица связана с...

Опять COM-порт
Для чтения данных с компорта создаю вспомогательный поток, далее как обычно: OverlapPort.hEvent = CreateEvent( NULL, false, true, NULL );...

опять про ПР
Если у меня 1 страничный сайт и с index.php идут 12 локальных линков на форум, фурум я не яндексирую. Хочу удержать PR на морде, как мне...

18
Эксперт .NET
 Аватар для Rius
13165 / 7725 / 1679
Регистрация: 25.05.2015
Сообщений: 23,535
Записей в блоге: 14
26.04.2017, 15:58
Можно читать входящие данные фукцией ReadFile с overlapped и WaitForSingleObject. Тогда можно получить либо завершение операции (прочитано указанное число байт), либо таймаут. Таймаут можно задать больше, чем разбрасывает COM порт, но меньше, чем между посылками.

Добавлено через 3 минуты
Вот пример
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
BOOL read(BYTE *buffer, DWORD bytesToRead, DWORD *bytesReaded, DWORD timeout)
{
    BOOL result = FALSE;
 
    *bytesReaded = 0;
    DWORD dwRead, dwWait;
    OVERLAPPED sync = { 0 };
 
    // Создаём событие для контроля за асинхронным чтением
    sync.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 
    // Если событие создано без ошибок
    if (sync.hEvent != NULL) {
        // Начинаем чтение…
        if (ReadFile(this->mPort, buffer, bytesToRead, &dwRead, &sync)) {
            // Операция чтения уже завершилась,
            // можно обрабатывать полученные данные
            *bytesReaded = dwRead;
            result = TRUE;
        } else {
            if (GetLastError() != ERROR_IO_PENDING) {
                // Ошибка чтения данных
            } else {
                // Ожидаем завершение операции чтения
                dwWait = WaitForSingleObject(sync.hEvent, timeout);
 
                switch (dwWait) {
                    case WAIT_OBJECT_0: { // Операция чтения закончена
                        if (GetOverlappedResult(this->mPort, &sync, &dwRead, FALSE)) {
                            // Обработка полученных данных
                            *bytesReaded = dwRead;
                            result = TRUE;
                        } else {
                            // Ошибка выполения операции
                        }
 
                        break;
                    }
 
                    case WAIT_TIMEOUT: {
                        // Операция чтения данных ещё не закончилась
                        // можно занятся чем-нибудь полезным
                        break;
                    }
 
                    default: {
                        // Ошибка выполнения WaitForSingleObject
                        break;
                    }
                }
            }
        }
 
        CloseHandle(sync.hEvent);
    }
 
    return (result);
}
0
0 / 0 / 0
Регистрация: 10.12.2016
Сообщений: 18
26.04.2017, 17:54  [ТС]
Цитата Сообщение от Rius Посмотреть сообщение
Таймаут можно задать больше, чем разбрасывает COM порт, но меньше, чем между посылками.
Спасибо за ответ. Но скажите, а если пакеты идут практически один за другим...
0
Эксперт .NET
 Аватар для Rius
13165 / 7725 / 1679
Регистрация: 25.05.2015
Сообщений: 23,535
Записей в блоге: 14
26.04.2017, 17:55
Если это пакеты, они должны быть как-то разделены. Это либо время (таймаут), либо содержимое (типа CR LF).
Время вы можете по осциллографу посмотреть. Содержимое - в сниффере или протоколе обмена.
0
0 / 0 / 0
Регистрация: 10.12.2016
Сообщений: 18
26.04.2017, 18:34  [ТС]
Ясно, спасибо!
0
Эксперт .NET
 Аватар для Rius
13165 / 7725 / 1679
Регистрация: 25.05.2015
Сообщений: 23,535
Записей в блоге: 14
26.04.2017, 18:38
В случае, если разделение в содержимом, надо считывать постоянно и пополнять некий самодельный буфер FIFO. Как только он заполнился одним пакетом, т.е. в нём есть и маркер начала, и маркер конца, то из буфера пакет вычитывается и используется.
0
0 / 0 / 0
Регистрация: 10.12.2016
Сообщений: 18
26.04.2017, 21:36  [ТС]
А вот за мысль с fifo отдельное спасибо. Пакеты действительно отличаются содержимым а вот идут почти один за другим. Я прочитал про таймауиы для com порта, но не совсем понял как мне это может помочь, а вот с вашем кодиком всё стало намного яснее. Завтра с утра поэксперементирую.
0
0 / 0 / 0
Регистрация: 10.12.2016
Сообщений: 18
28.04.2017, 10:59  [ТС]
Снова здравствуйте. Опять появилась проблема с портом. Уму не приложу в чём дело. В общем железяка работает нормально, поэтому пока с таймаутаи решил не заморачиваться. Но появилась другая напасть. Каждый пакет, который мне приходит состоит из 14 байт, при этом я знаю, что каждый пакет начинается с цифры 0х02. Т.к. в содержимом пакета такая цифра то же может появиться, решил сделать синхронизацию следующим образом: выделить 42-х байтный буфер (3х14) а в функции чтения порта указал 14 байт. Когда с порта приходят данные, я записываю их в старшие 14 байт выделенного буфера. Далее я проверяю равны ли 0 и 14 байты буфера 0х2. Если да, то делаю вывод, что за синхронизировался и выдаю данные. Если нет, то, сдвигаю весь 42-байтный блок на 1 в сторону младших разрядов и снова проверяю. Эта операция повтаряется 14 раз (пока младшие 14 байт полностью не выдвинутся из буфера). Вот мой код потока обработки:
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
DWORD WINAPI Thread_ListBox(LPVOID)
{
    
    while ( TRUE )
    {
        WaitForSingleObject( hEventListBox, INFINITE ); // Ожидаем пока поток чтения активизирует данный поток
        String str;                 // Обнуляем промежуточный буфер для преобразования столбик -> строка    
        
        for (int i=0; i < 14; i++)          // Записываем принятые 14 байт в старшие регистры рабочего буффера 
        {WorkBufRx[i+28] = BufRx[i];}       
        
        bool sync = 0;          // флаг синхронизации
        
        for (int i=0; i<14; i++)    // сдвигаем 28-ми байтный блок рабочего буфера на 14 байт
        {
            if ((WorkBufRx[0] == 0x02) & (WorkBufRx[14] == WorkBufRx[0]))   // проверяем, что засинхронизировались
            {sync = 1;break;}                       // если засинхронизировались выдаём данные
            for(int i=0; i< 28; i++)                    // сдвигаем 28-ми байтный блок на 1 позицию               
            {WorkBufRx[i] = WorkBufRx[i+1];}
        }
        
        if (sync)               
        {
            for(int i = 0; i < 14; i++)
            {
                Form1 -> ListBox1 -> Items -> Add(IntToHex((int)BufRx[i], 2)); // В ListBox выводим данные в столбик  
                str += IntToHex(WorkBufRx[i],2);        // Заполняем наш временный буффер столбик -> строка 
            }
            
            
            for(int i=0; i < 28; i++)
            {WorkBufRx[i] = WorkBufRx[i+14];}         // Выдвигаем из буфера отработанный пакет
            Form1 -> Memo1 -> Lines-> Add( str );   // Выводим данные в строчку в Memo1
                    
        }
    }
}
Сначала всё работает хорошо, но вот затем... Затем поток отображаемый в Memo замедляется, а затем и вовсе прекращается. Я посмотрел, на то, что выводится, так вот железяка исправно шлёт пакеты, а вот COM порт с определённого момента начинает их рвать совсем не постижимым образом. В чём может быть дело. Может я не правильно настроил порт, куда лезть, на что внимание обратить? При этом, если порт закрыть, а потом опять открыть, работа возобновляется в прежнем режиме, но вскоре снова всё замерает
0
Эксперт .NET
 Аватар для Rius
13165 / 7725 / 1679
Регистрация: 25.05.2015
Сообщений: 23,535
Записей в блоге: 14
28.04.2017, 11:12
От сдвига избавьтесь. Есть такой способ как кольцевой буфер.
У вас отдельный поток вроде есть. Читайте в нём не однократно 14 байт, а постоянно: 14, 14, 14,... И всё принятое записывайте в хвост вышеуказанного буфера.
Добавьте такое понятие, которое назовём "окном проверки". В него будут попадать первые 14 байт от головы буфера.
После каждого завершения чтения, или по таймауту, проверяйте наличие в окне набора байт, подходящего под описание пакета.
Если не подходит, первый байт из головы выбрасываете (окно сдвигается далее), и проверяете снова.
Если подходит, забираете из буфера и обрабатываете.

А вообще вот такого:
Цитата Сообщение от Грендайзер Посмотреть сообщение
каждый пакет начинается с цифры 0х02. Т.к. в содержимом пакета такая цифра то же может появиться
не должно быть. Такие протоколы должны иметь способ разделения пакетов.
Приведите описание протокола.
0
0 / 0 / 0
Регистрация: 10.12.2016
Сообщений: 18
28.04.2017, 11:39  [ТС]
Разобрался. В строке
C++
1
for(int i=0; i< 28; i++)    // сдвигаем 28-ми байтный блок на 1 позицию
необходимо заменить 28 на 42, иначе сдвигается лишь часть буфера.
От сдвига избавьтесь. Есть такой способ как кольцевой буфер.
Большое спасибо. Вот это очень полезно, а то конечно тасавать буферы не очень хорошо.
А вообще вот такого:
Цитата Сообщение от Грендайзер Посмотреть сообщение
каждый пакет начинается с цифры 0х02. Т.к. в содержимом пакета такая цифра то же может появиться
не должно быть.
Наверное Вы правы, но железяка не моя... Сама она на плисине, я лишь проверяю работоспособность схемы, которая в неё зашита (код то же не мой). Я лишь к коду который делает свою работу присобачил ответную часть, которая позволяет управлять основной схемой, по uart. Основной протокол, такой как есть, сначала 0x02 потом служебная информация (в ней правда есть адрес приёмника, то биш мой и можно ещё и его наверное проверять) но в целом, т.к. моя часть в основную схему не пойдёт, а нужна лишь для проверки, то и выдумывать я ничего не стал, тем более время поджимает, а в программировании под ОС я если честно не особо.

Добавлено через 11 минут
Rius, а Вы не могли бы поподробней объяснить, как читать голову буфера, если я пакеты записываю ему в хвост, так или иначе мне сдвигать то всё и так и так придётся...
0
Эксперт .NET
 Аватар для Rius
13165 / 7725 / 1679
Регистрация: 25.05.2015
Сообщений: 23,535
Записей в блоге: 14
28.04.2017, 11:49
Ссылку посмотрите.
Там ничего не сдвигается. Меняются только индексы головы (чтения) и хвоста (записи) .
1
0 / 0 / 0
Регистрация: 10.12.2016
Сообщений: 18
28.04.2017, 11:51  [ТС]
Ясно, спасибо ещё раз.
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
02.05.2017, 21:11
Цитата Сообщение от Грендайзер Посмотреть сообщение
Так вот понятно, что нужно поставить какой то таймер, но вот как бы это получше сделать не совсем понятно. Может кто то сможет подсказать?
1. Нельзя из потока обращаться к компонентам и их свойствам напрямую без синхронизации потоков.
2. Вместо WinApi лучше попробуйте использовать компонент(модуль) BComPort. (Или вообще другой фрейморк/ЯП)
0
0 / 0 / 0
Регистрация: 10.12.2016
Сообщений: 18
02.05.2017, 23:03  [ТС]
А можете поподробней рассказать или какую нибудь ссылочку дать почитать... Или каким нибудь примерчиком угостить. А то про COM порт везде одно и тоже, открываем, передаём байтик, его же сразу же читаем, закрываем порт. Всё! Для начала, конечно не плохо, но практического применения никакого...
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
03.05.2017, 10:58
Цитата Сообщение от Грендайзер Посмотреть сообщение
А то про COM порт везде одно и тоже, открываем, передаём байтик, его же сразу же читаем, закрываем порт. Всё!
Так а большего и не нужно.
0
0 / 0 / 0
Регистрация: 10.12.2016
Сообщений: 18
03.05.2017, 15:24  [ТС]
Цитата Сообщение от Avazart Посмотреть сообщение
Так а большего и не нужно.
Для того что бы принять байтик наверное да...
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
03.05.2017, 15:50
Так в других случаях все просто, алгоритм таков:

1. Включаем мозг.
2. Смотрим пример с принятием байтика.
3. Думаем головой (и не чем другим).
4. И реализуем код на его основе.
5. Можем выключать мозг )))
0
Практикантроп
 Аватар для nick42
4841 / 2726 / 534
Регистрация: 23.09.2011
Сообщений: 5,798
03.05.2017, 15:55
Цитата Сообщение от Грендайзер Посмотреть сообщение
поподробней рассказать или какую нибудь ссылочку дать почитать...
bitte_ Асинхронное чтение данных из COM порта
0
0 / 0 / 0
Регистрация: 10.12.2016
Сообщений: 18
03.05.2017, 17:36  [ТС]
Цитата Сообщение от nick42 Посмотреть сообщение
bitte_ Асинхронное чтение данных из COM порта
Ух ты... Спасибо, ознакомимся
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
03.05.2017, 17:36
Помогаю со студенческими работами здесь

Опять про ПР... :/
Вот у меня опять назрел вопрос, который пытаюсь уже давно выяснить... Для примера возьмем сайт на WP (все, думаю, знают, что это) ...

Опять про layout
Всех приветствую! Извиняюсь, но проведя 3 часа в попытках разобраться с layout я в конец запутался, поэтому вынужден обратится здесь...

Опять про камеру
Доброе время дня! На старости лет решил попробовать изучить Xamarin FORMS на C#. Передо мной стоит следующая задача и я ни как не могу с...

Опять про массивы
Всем привет. Подружка попросила помочь ее сыну решить пару лабораторных по информатике на vba, из 6 задач с четырьмя справилась, а вот...

Опять же про сапу
Ув сео. Я купила на сапе примарно 150 тематических сылок, с ключевыми словами новости, и новости сми. Эти сылки уже проиндексировались, и...


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

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
Новые блоги и статьи
Автозаполнение реквизита при выборе элемента справочника
Maks 27.03.2026
Программный код из решения ниже на примере нетипового документа "ЗаявкаНаРемонтСпецтехники" разработанного в конфигурации КА2. При выборе "Спецтехники" (Тип Справочник. Спецтехника), заполняется. . .
Сумматор с применением элементов трёх состояний.
Hrethgir 26.03.2026
Тут. https:/ / fips. ru/ EGD/ ab3c85c8-836d-4866-871b-c2f0c5d77fbc Первый документ красиво выглядит, но без схемы. Это конечно не даёт никаких плюсов автору, но тем не менее. . . всё может быть. . .
Автозаполнение реквизитов при создании документа
Maks 26.03.2026
Программный код из решения ниже размещается в модуле объекта документа, в процедуре "ПриСозданииНаСервере". Алгоритм проверки заполнения реализован для исключения перезаписи значения реквизита,. . .
Команды формы и диалоговое окно
Maks 26.03.2026
1. Команда формы "ЗаполнитьЗапчасти". Программный код из решения ниже на примере нетипового документа "ЗаявкаНаРемонтСпецтехники" разработанного в конфигурации КА2. В качестве источника данных. . .
Кому нужен AOT?
DevAlt 26.03.2026
Решил сделать простой ланчер Написал заготовку: dotnet new console --aot -o UrlHandler var items = args. Split(":"); var tag = items; var id = items; var executable = args;. . .
Отправка уведомления на почту при создании или изменении элементов справочника
Maks 24.03.2026
Программная отправка письма электронной почты на примере типового справочника "Склады" в конфигурации БП3. Перед реализацией необходимо выполнить настройку системной учетной записи электронной. . .
модель ЗдравоСохранения 5. Меньше увольнений- больше дохода!
anaschu 24.03.2026
Теперь система здравосохранения уменьшает количество увольнений. 9TO2GP2bpX4 a42b81fb172ffc12ca589c7898261ccb/ https:/ / rutube. ru/ video/ a42b81fb172ffc12ca589c7898261ccb/ Слева синяя линия -. . .
Midnight Chicago Blues
kumehtar 24.03.2026
Такой Midnight Chicago Blues, знаешь?. . Когда вечерние улицы становятся ночными, а ты не можешь уснуть. Ты идёшь в любимый старый бар, и бармен наливает тебе виски. Ты смотришь на пролетающие. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru