Форум программистов, компьютерный форум, киберфорум
C/С++ под Linux
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.92/36: Рейтинг темы: голосов - 36, средняя оценка - 4.92
2 / 2 / 1
Регистрация: 23.03.2015
Сообщений: 78

Как работать с tty в программе, обращающейся к COM-порту

16.05.2015, 14:26. Показов 7298. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго дня!
Пишу программу, которая должна собирать данные от COM-порта и обрабатывать их. Соответственно, пытаюсь разобраться, как работать с tty из-под c++.
Для тестирования есть ардуинка, которая выдает примеры нужных сообщений через последовательный порт. Параметры порта - 8N1, 9600.
Чтобы разобраться с технологией, взял готовый код:

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
void tty_collect(settings* config)
{
int fd; /* Файловый дескриптор для порта */
char buf[512];/*размер зависит от размера строки принимаемых данных*/
int outa=0; 
int iIn;
 
int open_port(void);
    fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY); /*'open_port()' - Открывает последовательный порт */
      if (fd == -1)
        {
          /*
           * Возвращает файловый дескриптор при успехе или -1 при ошибке.
           */
           printf("error port\n");
           perror("open_port: Unable to open /dev/ttyUSBn - ");
        }
     else
        {
         struct termios options; /*структура для установки порта*/
         tcgetattr(fd, &options); /*читает пораметры порта*/
        
         cfsetispeed(&options, B9600); /*установка скорости порта*/
         cfsetospeed(&options, B9600); /*установка скорости порта*/
         
         options.c_cflag &= ~PARENB; /*выкл проверка четности*/
         options.c_cflag &= ~CSTOPB; /*выкл 2-х стобит, вкл 1 стопбит*/
         options.c_cflag &= ~CSIZE; /*выкл битовой маски*/
         options.c_cflag |= CS8; /*вкл 8бит*/
         tcsetattr(fd, TCSANOW, &options); /*сохронения параметров порта*/
        
        }
 read_port:
  iIn=read(fd,buf,8); /*чтения приходящих данных из порта*/
   
       
  printf("%s",buf);
проблема в том, что данный код ничего не принимает, пока в терминале не выполнить настройку порта этим костылем:
Bash
1
stty -F /dev/ttyUSB0 raw ispeed 9600 ospeed 9600 -ignpar cs8 -cstopb -echo
прошу вправить руки!
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
16.05.2015, 14:26
Ответы с готовыми решениями:

Как заставить программу работать на одном порту?
Вообщем вопрос такой. Есть программа, которая работает по сети, например браузер. При запросе страницы, браузер обращается к OS и она...

Arduino UNO. Как работать c RFID-сканнером и Arduino на одном Serial-порту?
Рас уж тут речь зашла об ардуине и многопоточности COM порта, думаю могу обратиться именно сюда за помощью. Имеется у меня arduino...

Как сделать автозапуск приложений на других tty?
Здравствуйте. Как осуществить автозапуск (при загрузке) приложений на tty2, 3 и 4? Делал .service файлы в /usr/lib/systemd/system, но...

8
Жарю без масла
867 / 749 / 225
Регистрация: 13.01.2012
Сообщений: 1,702
16.05.2015, 16:25
вот эта команда
Цитата Сообщение от bonanza Посмотреть сообщение
Bash
1
stty -F /dev/ttyUSB0 raw ispeed 9600 ospeed 9600 -ignpar cs8 -cstopb -echo
в С коде:
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
struct termios options;
tcgetattr(fd, &options);
 
/*
 * stty -F /dev/ttyUSB0 raw ispeed 9600 ospeed 9600 \
 *      -ignpar cs8 -cstopb -echo
 */
 
cfsetispeed(&options, B9600); /* ispeed 9600 */
cfsetospeed(&options, B9600); /* ospeed 9600 */
 
/*
 * маны говорят:
 * raw    same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr
 *  -igncr -icrnl  -ixon  -ixoff-iuclc  -ixany -imaxbel -opost -isig
 *  -icanon -xcase min 1 time 0
 * можно вызвать cfmakeraw() и добавить нужные флаги, но сделаем все
 * явно для наглядности.
 */
options.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP |
                     INLCR | IGNCR | ICRNL | IXON | IXOFF | IUCLC |
                     IXANY | IMAXBEL);
options.c_oflag &= ~OPOST;
options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
options.c_cflag &= ~(CSIZE | PARENB | CSTOPB);
options.c_cflag |= CS8;
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 0;
/* вроде ничего не упустил(?) */
tcsetattr(fd, TCSANOW, &options);
1
2 / 2 / 1
Регистрация: 23.03.2015
Сообщений: 78
17.05.2015, 16:17  [ТС]
блин, очевидно же было!
спасибо, буду пробовать...

Добавлено через 36 секунд
retmas, не взлетело. Ситуация осталась ровно та же.

Добавлено через 2 часа 42 минуты
Прошу прощения, заработало нормально после того, как заставил ардуинку заканчивать сообщение возвратом каретки (Serial.println() вместо Serial.print()). До этого валился всякий шлак из пробелов и повторов кусков сообщений, при том, что принимаю сообщение по одному символу.
Подскажите, можно ли как-то корректно принимать сообщения переменной длины, не заканчивающиеся возвратом каретки?
Использую этот код:
C++
1
2
3
4
5
6
7
    while (TRUE)
    {
        if (read(fd,buf,1) != -1)        //чтения приходящих данных из порта
        {
            cout << buf;
        }
    }
0
Жарю без масла
867 / 749 / 225
Регистрация: 13.01.2012
Сообщений: 1,702
17.05.2015, 16:54
я не очень представляю, что у вас там творится и в каком виде, но логика чтения текстовых данных в общем случае из любого дескриптора примерно такова:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    while (TRUE)
    {
        char buf[];
        int nread;
 
        nread = read(fd, buf, sizeof(buf) - 1); //чтения приходящих данных из порта
        if(nread == 0) // EOF или "нормальное" закрытие порта с "той"
            break;     // стороны (не знаю бывает ли у вас такое)
        if(nread == -1)
        {
            perror("read");
            // обработка ошибки
            // exit(EXIT_FAILURE); (?)
        }
        if(nread > 0)
        {
            buf[nread] = '\0';
            // работаем с буфером
            cout << buf;
        }
    }
1
2 / 2 / 1
Регистрация: 23.03.2015
Сообщений: 78
17.05.2015, 17:39  [ТС]
очень похоже на то что нужно! спасибо.

Добавлено через 25 минут
Скажите, я правильно понимаю, что когда nread == -1, это означает отсутствие в буфере порта непрочитанных данных и программа должна ждать ждать дальше?

Переписал Ваш код таким образом:
C++
1
2
3
4
5
6
7
8
9
        while (TRUE)
        {
            char buf[250];
            int nread;
            nread = read(fd, buf, sizeof(buf) - 1);
            if (nread == -1 || nread == 0)  continue;
            buf[nread] = '\0';                           // finishing message
            cout << buf << endl;
        }
если ардуина заканчивает сообщение переводом каретки - то все нормально, приходит цельное сообщение:
2003/06/28 09:30:57,00:00:21,0,01707392200,I,299999 ,299999,,0,1000014160,0,V9502,VM Channel 2,T9002,LINE 1.2,0,0

если не заканчивает, то сообщение рубится на куски произвольной длины и в терминале мы видим это:
Кликните здесь для просмотра всего текста
2002
/06/2
8
09:
30:5
7
,0
0
:00
:13,
7,017
073
9
22
0
0,I
,
299
999
,29
99
99
,
,0
,1
000
01
4
160,
1,E
4
750,
Joh
n Sm
it
h,
T
90
02
,LIN
E 1
.2,
11
,0


Думаю, что в бою будет высокая вероятность именно второго случая.
Подскажите, откуда растут ноги и как с этим бороться?
з.ы. если интересно, то это пример сообщения от АТС о звонке в формате smdr.
0
Жарю без масла
867 / 749 / 225
Регистрация: 13.01.2012
Сообщений: 1,702
17.05.2015, 18:12
ноги растут из этой строки:
Цитата Сообщение от bonanza Посмотреть сообщение
C++
1
cout << buf << endl;
данные приходят частями и вы каждую часть выводите в новой строке

Добавлено через 4 минуты
просто имейте ввиду, что даже если на том конце отправили "цельное" сообщение, то совсем не обязательно, что оно придет к вам таким же цельным. это касается не только вашего конкретного случая, но и в общем( в т.ч. при передаче данных по сети, например)
0
2 / 2 / 1
Регистрация: 23.03.2015
Сообщений: 78
17.05.2015, 18:18  [ТС]
интересное явление, без << endl программа накапливает 1024 знака и выдает их оптом. это при размере буфера 250 байт. с чем это может быть связано?
0
Жарю без масла
867 / 749 / 225
Регистрация: 13.01.2012
Сообщений: 1,702
17.05.2015, 18:32
буферизация в cout

Добавлено через 10 минут
просто для сравнения попробуйте
C++
1
cout << buf << flush;
1
2 / 2 / 1
Регистрация: 23.03.2015
Сообщений: 78
18.05.2015, 05:33  [ТС]
Спасибо за помощь!
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
18.05.2015, 05:33
Помогаю со студенческими работами здесь

Подключение АЦП к LPT порту ПК (необходимы комментарии к программе)
Здравствуйте дорогие форумчане! Недавно гуляя по просторам интернета я наткнулся на интересную статью. В ней написано про подключение АЦП...

Сделать, чтобы программа могла работать только на одном порту и IP
Доброго времени суток... Скажите возможно ли как то сделать чтоб по определенному ip и port можно было подключиться только именно с одной...

Шина USB: на каком порту или портах работать с хост-конроллером
Ребята подскажите на каком порту или портах работать с хост-конроллером в компьютере архитекторы x86, какие адреса при этом использует...

Как работать с реестром в консольной программе?
как работать с реестром в консольное программе с http ини файлами и прочем?

Второе окно в программе. Как с ним работать?
В mainWindow прописано появление второго окна в программу, Эмуляции браузинга. QWebView* view = new QWebView(); ...


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

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
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 . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru