Создание Slave устройства в сети Modbus

встраиваемые модели

Модераторы: Olej, vikos

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Создание Slave устройства в сети Modbus

Непрочитанное сообщение Olej » 12 сен 2019, 16:24

Olej писал(а):

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/Vector/modbus/modopt$ sudo stty -a -F /dev/ttyS0
speed 115200 baud; rows 0; columns 0; line = 0;
intr = <undef>; quit = <undef>; erase = <undef>; kill = <undef>; eof = <undef>; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = <undef>; stop = <undef>; susp = <undef>; rprnt = <undef>;
werase = <undef>; lnext = <undef>; discard = <undef>; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8
-opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
-isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke -flusho -extproc
Всё поплыло (установлен неканонический режим):
И теперь сравню с тем, что вы писали на 1-й странице ... и различие я нашёл только одно (может что и недосмотрел):
- у вас:
min = 0; time = 0;
- в этом Modbus проекте:
min = 1; time = 0;
P.S. И вспомнил я, что лет 10 назад, возясь с PPP, TCP/IP over UART - там тоже нужен RAW mode, там тоже были какие-то такие установки, и на них мы тогда "попали"... Попробуйте поменять.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Создание Slave устройства в сети Modbus

Непрочитанное сообщение Olej » 12 сен 2019, 19:20

Olej писал(а): PPP, TCP/IP over UART - там тоже нужен RAW mode
Попробовал посмотреть как инициализирует порт демон pppd - PPP должен гнать RAW бинарные данные через нуль-модемную линию..
Сам pppd для поднятия TCP/IP канала конфигурировать не стал (там очень много для нормальной работы) ... чуть-чуть только подправил /etc/ppp/options - только чтобы pppd стартовал и не сваливался ... аппаратный UART он при этом уже должен инициализировать:

Код: Выделить всё

# cat /etc/ppp/options
...
#auth
local
lock
...
passive
silent
...

Стартую pppd:

Код: Выделить всё

root@ACER:/etc/ppp# /sbin/pppd /dev/ttyS0 38400 10.0.1.30:

root@ACER:/etc/ppp# ps -A | grep pppd
16764 ttyS0    00:00:00 pppd
Инициализация /dev/ttyS0 сделана так:

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/Vector/modbus/modopt$ sudo stty -a -F /dev/ttyS0
speed 38400 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O;
min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread -clocal -crtscts
ignbrk -brkint ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl ixon ixoff -iuclc -ixany -imaxbel -iutf8
-opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
-isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke -flusho -extproc
Уже можно сравнивать что там с флагами...
Или по сравнению с дефаултными режимами соседнего UART:

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/Vector/modbus/modopt$ diff <(sudo stty -a -F /dev/ttyS0) <(sudo stty -a -F /dev/ttyS1)
1c1
< speed 38400 baud; rows 0; columns 0; line = 0;
---
> speed 9600 baud; rows 0; columns 0; line = 0;
5,6c5,6
< -parenb -parodd -cmspar cs8 hupcl -cstopb cread -clocal -crtscts
< ignbrk -brkint ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl ixon ixoff
---
> -parenb -parodd -cmspar cs8 hupcl -cstopb cread clocal -crtscts
> -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
8,10c8,10
< -opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
< -isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt
< -echoctl -echoke -flusho -extproc
---
> opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
> isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
> echoctl echoke -flusho -extproc

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Создание Slave устройства в сети Modbus

Непрочитанное сообщение Olej » 13 сен 2019, 16:41

Larisa писал(а):Если можете - окажите консультацию по этому вопросу.
Первые предварительные итого...
Что бы я сделал (поменял) уже по результатам того, что обсуждалось?:

1. Открывать порт /dev/ttymxc0 с другими флагами (в другом режиме), что-то типа:

Код: Выделить всё

fd = open( "/dev/ttymxc0", O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY );

Нужно ли открывать порт для чтения в неблокирующем режиме - это ещё тоже вопрос дальнейшего разбирательства подробного (как лучше?), а если использовать блокирующий режим, то и вообще останется:

Код: Выделить всё

fd = open( "/dev/ttymxc0", O_RDWR | O_NOCTTY );


2. При переводе открытого терминального порта в неканонический режим, для побайтной передачи, инициализацию сделать так, чтобы она затрагивала параметры порта min и time (это очень подробно описано и обсуждается в книге Стивенса, которую я показывал раньше), так, чтобы min = 1.
С time - это тоже интересная история (на дальнейшее рассмотрение), это время (в десятых секунды) которое максимально ожидает операция чтения + это может очень пригодится для создания тайм-аутов, разделяющих сообщения Modbus RTU.

2b. При завершении любой программы трогающей termios - нужно его возвращать в первоначальное состояние (PPP, например, этого не делает). И делать это хорошо бы не каким-то ручным "закрытием" порта, а ... обязательным восстановительным действием по завершению, независимо от природы завершения -

Код: Выделить всё

struct termios told;
void restore_port_mode( void ) {  
   tcsetattr( fd, TCSANOW, &told );
}
...
   tcgetattr( fd, &told );
   atexit( restore_port_mode );    
// а теперь можно менять флаги
...

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Создание Slave устройства в сети Modbus

Непрочитанное сообщение Olej » 13 сен 2019, 16:51

1 - 2 - 2b - это может выглядеть как-то так ... чтоб не рассказывать "на пальцах":

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/Vector/modbus/termopt$ cat termopt.c 
#include <fcntl.h>
#include <termios.h>
#include <strings.h>
#include <stdio.h>
#include <stdlib.h>

int fd;
struct termios told, tnew; 

void restore_port_mode( void ) {  
   tcsetattr( fd, TCSANOW, &told );
}

void change_port_mode( void ) {
//   tnew = told;
   bzero( &tnew, sizeof( struct termios ) );
   tnew.c_cflag = B115200;            // 115200 бод
   tnew.c_iflag &= ~( IGNBRK | BRKINT | PARMRK | ISTRIP
                             | INLCR | IGNCR | ICRNL | IXON );
   tnew.c_oflag &= ~OPOST;
   tnew.c_lflag &= ~( ECHO | ECHONL | ICANON | ISIG | IEXTEN );
   tnew.c_cflag &= ~( CSIZE | PARENB );
   tnew.c_cflag |= CS8;
   tnew.c_cc[ VMIN ] = 1;
   tnew.c_cc[ VTIME ] = 0;

   tcflush( fd, TCIFLUSH );
   if( tcsetattr( fd, TCSANOW, &tnew ) < 0 ) { 
      printf( "Can't set terminal parameters: %m" );
      exit( 2 );
   }
   tcflush( fd, TCIOFLUSH );
}

int main() {
   if( ( fd = open( "/dev/ttyS0", O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY ) ) < 0 ) {
      printf( "Open device failure: %m\n" );
      exit( 1 );
   }
   tcgetattr( fd, &told );
   atexit( restore_port_mode );       // восстановить при завершении
   change_port_mode();
   getchar();						  // hit <return> to stop program 
}
Смотрим до запуска:

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/Vector/modbus/modopt$ sudo stty -a -F /dev/ttyS0
speed 9600 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V;
discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc
Поменяем режим на побайтовый:

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/Vector/modbus/termopt$ sudo ./termopt

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/Vector/modbus/modopt$ sudo stty -a -F /dev/ttyS0
speed 115200 baud; rows 0; columns 0; line = 0;
intr = <undef>; quit = <undef>; erase = <undef>; kill = <undef>; eof = <undef>; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = <undef>; stop = <undef>;
susp = <undef>; rprnt = <undef>; werase = <undef>; lnext = <undef>; discard = <undef>; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb -cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8
-opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
-isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke -flusho -extproc
Проверяем флаги...
И завершаем программу ./termopt (любым способом: нажатием Enter, Ctrl+C, kill ...):

Код: Выделить всё

olej@ACER:~/2019_WORK/own.WORK/Vector/modbus/modopt$ sudo stty -a -F /dev/ttyS0
speed 9600 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V;
discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc

olej@ACER:~/2019_WORK/own.WORK/Vector/modbus/modopt$ diff <(sudo stty -a -F /dev/ttyS0) <(sudo stty -a -F /dev/ttyS1)
olej@ACER:~/2019_WORK/own.WORK/Vector/modbus/modopt$
Вложения
termopt.c
(1.22 КБ) 131 скачивание

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Создание Slave устройства в сети Modbus

Непрочитанное сообщение Olej » 13 сен 2019, 17:01

Olej писал(а):
Larisa писал(а):Если можете - окажите консультацию по этому вопросу.
Первые предварительные итого...
Что бы я сделал (поменял) уже по результатам того, что обсуждалось?:
Дальше...

3. Я бы поменял select() на poll() - pol() введен в POSIX на 20 лет позже select(), и именно для того, чтобы нивелировать те сложности и артефакты, которые может порождать select().
Опять же, Стивенс в книге описывает и объясняет ... и select() и poll()...

4. Дальше самое интересное...
После точки select()/poll() у вас стоит read(), да ещё и в неблокирующем режиме.
Но такой read() будет читать только то число байт, которое к моменту вызова успело поступить из канала. А канал UART - очень медленный, с точки зрения процессора... И в чипах UART присутствует аппаратная буферизация, но размер и условия этой буферизации меняется как попало у разных производителей.
Я предполагаю (IMHO), что именно здесь возникают проблемы, и именно здесь возникает зависимость от длины пакета, то что вы описали: "проблемы возникают начиная с пакетов длиной больше 34 байт"... Т.е. предположение состоит в том, что иногда вы читаете после select() не весь Modbus пакет, а только его начало ... а хвост зависает в буферах терминальной системы и портит последующие циклы обмена.
Но это нужно уже смотреть и испытывать код после рубежа select()/poll().

Ответить

Вернуться в «Одноплатные компьютеры»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 4 гостя