Создание Slave устройства в сети Modbus
Добавлено: 04 сен 2019, 15:54
На базе одноплатного ПК imx6ul создаем Slave устройство в сети Modbus.
Канал RS-485, витая пара, 115200.
Используем порт /dev/ttymxc0
флаги открытия порта
flags = O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL;
ctx->s = open(ctx_rtu->device, flags);
параметры порта
stty < /dev/ttymxc0
speed 115200 baud; 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>; flush = <undef>; min = 0; time = 0;
-brkint -icrnl -imaxbel
-opost -onlcr
-isig -icanon -iexten -echo -echoe -echok -echoctl -echoke
stty -a < /dev/ttymxc0
speed 115200 baud;stty: standard input
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>; flush = <undef>; min = 0; time = 0;
-parenb -parodd 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
Дополнительно пакеты не ставим, используем библиотеку LibModbus, далее вызовы Posix
Структура tios для этого порта
tios @0x740fc8e4 struct termios
c_cc @0x740fc8f5 cc_t[32]
[0] 0 cc_t
[1] 0 cc_t
[2] 0 cc_t
[3] 0 cc_t
[4] 0 cc_t
[5] 0 cc_t
[6] 0 cc_t
[7] 0 cc_t
[8] 0 cc_t
[9] 0 cc_t
[10] 0 cc_t
[11] 0 cc_t
[12] 0 cc_t
[13] 0 cc_t
[14] 0 cc_t
[15] 0 cc_t
[16] 0 cc_t
[17] 0 cc_t
[18] 0 cc_t
[19] 0 cc_t
[20] 0 cc_t
[21] 0 cc_t
[22] 0 cc_t
[23] 0 cc_t
[24] 0 cc_t
[25] 0 cc_t
[26] 0 cc_t
[27] 0 cc_t
[28] 0 cc_t
[29] 0 cc_t
[30] 0 cc_t
[31] 0 cc_t
c_cflag (hex) 18b2 tcflag_t
c_iflag 0 tcflag_t
c_ispeed (hex) 1002 speed_t
c_lflag 0 tcflag_t
c_line 0 cc_t
c_oflag 0 tcflag_t
c_ospeed (hex) 1002 speed_t
Вызов самой функции настройки порта
if (tcsetattr(ctx->s, TCSANOW, &tios) < 0) {
close(ctx->s);
ctx->s = -1;
return -1;
}
Далее настройки
rs485conf @0x740fc900 struct serial_rs485
delay_rts_after_send 0 __u32
delay_rts_before_send 0 __u32
flags 5 __u32
padding @0x740fc90c __u32[5]
[0] 0 __u32
[1] 0 __u32
[2] 0 __u32
[3] 0 __u32
[4] 0 __u32
ioctl(ctx->s, TIOCSRS485, &rs485conf);
Затем еще
rs485conf @0x740fc900 struct serial_rs485
delay_rts_after_send 0 __u32
delay_rts_before_send 0 __u32
flags 5 __u32
padding @0x740fc90c __u32[5]
[0] 0 __u32
[1] 0 __u32
[2] 0 __u32
[3] 0 __u32
[4] 0 __u32
ioctl(ctx->s, TIOCSRS485, &rs485conf);
Все остальные настройки на прикладном уровне.
Алгоритм работы:
зависаем на порте в функции Posix
select(ctx->s+1, rset, NULL, NULL, tv);
на бесконечный таймаут, когда в канале появяться данные, считываем несколькоми портциями (могу рассказать подробнее, но сейчас это не важно, там проблем вроде нет)
анализируем данные, отправляем ответ.
И все работает отлично какое то время, например 6000 посылок/ответов.
Далее два варианта ошибок.
1. Затем посылаем очередной запрос от Master, но ПО с функции select не уходит, то есть прикладная программа данных не видит. Но при этом в канал в ответ уходит 4кБ информации,
частино соответствующей прошлям запросам, это по нашему мнению на сейчас полностью выдается выходной буфер.
Далее обмен восстанавливается. До новых 4кБ. Проявляется при запросах, когда длина ответной посылки более 35 байт.
2. При запросах более коротких ответов нормальный обмен может проходить и более 100 000 раз, но потом порт обрывается наглухо, требуется пререзагрузка Slave устройства.
Канал RS-485, витая пара, 115200.
Используем порт /dev/ttymxc0
флаги открытия порта
flags = O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL;
ctx->s = open(ctx_rtu->device, flags);
параметры порта
stty < /dev/ttymxc0
speed 115200 baud; 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>; flush = <undef>; min = 0; time = 0;
-brkint -icrnl -imaxbel
-opost -onlcr
-isig -icanon -iexten -echo -echoe -echok -echoctl -echoke
stty -a < /dev/ttymxc0
speed 115200 baud;stty: standard input
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>; flush = <undef>; min = 0; time = 0;
-parenb -parodd 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
Дополнительно пакеты не ставим, используем библиотеку LibModbus, далее вызовы Posix
Структура tios для этого порта
tios @0x740fc8e4 struct termios
c_cc @0x740fc8f5 cc_t[32]
[0] 0 cc_t
[1] 0 cc_t
[2] 0 cc_t
[3] 0 cc_t
[4] 0 cc_t
[5] 0 cc_t
[6] 0 cc_t
[7] 0 cc_t
[8] 0 cc_t
[9] 0 cc_t
[10] 0 cc_t
[11] 0 cc_t
[12] 0 cc_t
[13] 0 cc_t
[14] 0 cc_t
[15] 0 cc_t
[16] 0 cc_t
[17] 0 cc_t
[18] 0 cc_t
[19] 0 cc_t
[20] 0 cc_t
[21] 0 cc_t
[22] 0 cc_t
[23] 0 cc_t
[24] 0 cc_t
[25] 0 cc_t
[26] 0 cc_t
[27] 0 cc_t
[28] 0 cc_t
[29] 0 cc_t
[30] 0 cc_t
[31] 0 cc_t
c_cflag (hex) 18b2 tcflag_t
c_iflag 0 tcflag_t
c_ispeed (hex) 1002 speed_t
c_lflag 0 tcflag_t
c_line 0 cc_t
c_oflag 0 tcflag_t
c_ospeed (hex) 1002 speed_t
Вызов самой функции настройки порта
if (tcsetattr(ctx->s, TCSANOW, &tios) < 0) {
close(ctx->s);
ctx->s = -1;
return -1;
}
Далее настройки
rs485conf @0x740fc900 struct serial_rs485
delay_rts_after_send 0 __u32
delay_rts_before_send 0 __u32
flags 5 __u32
padding @0x740fc90c __u32[5]
[0] 0 __u32
[1] 0 __u32
[2] 0 __u32
[3] 0 __u32
[4] 0 __u32
ioctl(ctx->s, TIOCSRS485, &rs485conf);
Затем еще
rs485conf @0x740fc900 struct serial_rs485
delay_rts_after_send 0 __u32
delay_rts_before_send 0 __u32
flags 5 __u32
padding @0x740fc90c __u32[5]
[0] 0 __u32
[1] 0 __u32
[2] 0 __u32
[3] 0 __u32
[4] 0 __u32
ioctl(ctx->s, TIOCSRS485, &rs485conf);
Все остальные настройки на прикладном уровне.
Алгоритм работы:
зависаем на порте в функции Posix
select(ctx->s+1, rset, NULL, NULL, tv);
на бесконечный таймаут, когда в канале появяться данные, считываем несколькоми портциями (могу рассказать подробнее, но сейчас это не важно, там проблем вроде нет)
анализируем данные, отправляем ответ.
И все работает отлично какое то время, например 6000 посылок/ответов.
Далее два варианта ошибок.
1. Затем посылаем очередной запрос от Master, но ПО с функции select не уходит, то есть прикладная программа данных не видит. Но при этом в канал в ответ уходит 4кБ информации,
частино соответствующей прошлям запросам, это по нашему мнению на сейчас полностью выдается выходной буфер.
Далее обмен восстанавливается. До новых 4кБ. Проявляется при запросах, когда длина ответной посылки более 35 байт.
2. При запросах более коротких ответов нормальный обмен может проходить и более 100 000 раз, но потом порт обрывается наглухо, требуется пререзагрузка Slave устройства.