PDA

Просмотр полной версии : плк63 + му/мв110 по rs-485, modbus, st



mc_
27.12.2012, 13:58
Доброго всем времени суток, и с наступающим.

Так получилось, что один сотрудник ушел на вольные хлеба, и мне по наследству достался недоделанный проект. Вроде бы ничего сложного - контроллер с дополительными модулями по rs-485, алгоритм в принципе простейший... но я ж не знал, что плк63 не умеет это делать по-человечески.
Поменять состав оборудования не вариант, всё уже куплено, деваться некуда.

В общем, надо подружить между собой плк63 и модули мв110 (8АС и 16дн), мв110-16Р, всех по нескольку штук. Связь по rs-485, протокол modbus, язык ST.

Нашел пример (http://plc24.ru/konfiguraciya-oven-plk-63-dlya-svyazi-s-modulem-mdvv/) для МДВВ, пытаюсь его перекроить и сделать подпрограмму для 110-ого, получается не очень (пока связь есть, но команды не идут, экспериментирую с одним му110-16Р).

Подскажите, в какую сторону работать напильником? Чего выкинуть/добавить/поменять? И стоит ли пихать все разновидности модулей в одну подпрограмму, или лучше резделить ввод/вывод и дискретные/аналоговые сигналы?

Буду благодарен за любую помощь.

Гарчев Евгений
27.12.2012, 15:56
Здравствуйте!

Запись выходных значений в МУ110-16Р организуйте по битовой маске (адрес регистра - 50). Объявите все выходные переменные типа Bool (например, var out1:bool; ... out16:bool; end_var). В первые 2 байта буфера для передачи данных, который объявлен как массив из байтов, запишите эти булевые переменные (в нулевой байт - переменные out9...out16, в первый байт - переменные out1...out8), т.е.
Buffer[0].0:=out9; Buffer[0].1:=out10; ... Buffer[0].7:=out16;
Buffer[1].0:=out1; Buffer[1].1:=out2; ... Buffer[1].7:=out8;

mc_
28.12.2012, 08:32
Примерно так?


IF port_opened=0 THEN
settings.Port:=0; (*номер порта RS-485*)
settings.dwBaudRate:=baud_rate; (*скорость*)
settings.byParity:=0;
settings.dwTimeout:=0;
settings.byStopBits:=0;
settings.dwBufferSize:=0;
settings.dwScan:=0;
END_IF

(*открываем COM-порт*)

com_service1(enable:=(port_opened=0), settings:=settings, task:=open_tsk);

(*если COM-порт открыт, пепреходим к приему и передаче данных*)

IF com_service1.Ready THEN
port_opened:=2;
END_IF

IF (port_opened=2) THEN

Buffer[1].0:=out1;
...
Buffer[0].7:=out16;

send_modbus(
enable:=enabl, (*резрешение работы блока*)
mode:=mb_rtu, (*режим передачи*)
DevAddr:=slave_addr, (*адрес*)
FirstAddr:=50, (*номер первого регистра*)
quantity:=16, (*количество записываемых регистров*)
ComHandle:=settings.Port, (*номер СОМ-порта*)
TimeOut:=TimeOut, (*таймаут, естессно*)
buffer:=buffer, (*ну буфер же*)
Complete=>cmpl, (*копировать признак завершения операции*)
Exception=>err, (*копируем регистр ошибок*)
RegCnt=>DataSize); (*кол-во записанных байтов*)
END_IF

Где-то что-то напутал, индикатор rs-485 теперь не загорается. Пойду разберу экибану, надо адрес перепроверить.

lara197a
28.12.2012, 09:48
Если не моргает RS, то начните с проверки открытия порта. Видимо не открывается. Reset после загрузки ПРГ делаете?

mc_
28.12.2012, 10:19
Хм, com_service1.ready=TRUE.
Но settings.port пишет "invalid:0", а send_modbus.exception=254. И выхода в отладчике мигают, как будто я блок управления гирляндами программирую. Отмечать Новый Год вроде еще не начал...

Другие порты ставлю - не глючит, но тогда com_service1.ready=FALSE.

----------
UPD: Лампочки горят :) Все скопом. quantity:=1, а не 16, всего-то.
Видно, долетел до меня запах свободы - коллега рядом сидит плату моет.

Сейчас перерыв на бурную радость, и буду дальше разбираться: на очереди дискретные входы (со счетчиками и без) и 4-20 mA, будь они неладны. Решил на каждй тип прибора делать свою подпрограмму.

Всем спасибо за помощь!

Гарчев Евгений
28.12.2012, 11:00
Но settings.port пишет "invalid:0"
То что появляется данная ошибка, это нормально, т.к. в перечислении PORTS библиотеки SysLibCom нет порта с номером COM0, поэтому и возникает данная ошибка, но порт при этом открывается.


UPD: Лампочки горят :) Все скопом. quantity:=1, а не 16, всего-то.

Вы записываете 16 бит=2 байта=1регистр, quantity - это кол-во регистров, поэтому quantity=1.

mc_
29.12.2012, 10:12
Цепляю МВ-110-16ДН (дискретные входы).
Вышло что-то вроде


IF (port_opened=2) THEN

rd_regs(
...

FirstAddr:=51 (*регистр*)

Quantity:=1, (*кол-во регистров*)
.....
);

END_IF

IF err=0 THEN (*если нет ошибок, потрошим байты на биты*)
in1:=Buffer[1].0;
in2:= Buffer[1].1;
...
in8:=Buffer[1].7;

in9:=Buffer[0].0;
in10:=Buffer[0].1;
...
in16:=Buffer[0].7;
END_IF
но это только входы. Сейчас буду проверять, если железку найду.
Как бы половчее счетчики зацепить, чтобы несколько раз не гонять чтение?

ASo
02.01.2013, 10:48
Как бы половчее счетчики зацепить, чтобы несколько раз не гонять чтение?Естественно, групповым чтением. Укажите в функции соответствующее число регистров.

mc_
02.01.2013, 14:20
Понятно что групповым, хотел скидать в одну кучу с дискретными входами. Но, видимо, лучше все-таки отдельной подпрограммой, и сброс туда же закинуть.

Эх, все железки на работе, ничего под рукой нет - даже дискретные входы остались в нерабочем состоянии, не пойму, где косяков напорол. Праздники вредны для мозга...

ASo
02.01.2013, 19:23
Не рекомендую делать это одним запросом - есть разрыв в адресах.
Рекомендую вынести опрос в отдельный процесс и обмениваться с основной программой через глобалы или еще как. Так проще и понятнее.

mc_
09.01.2013, 10:14
Связь наладил, диод rs моргает. FirstAddr:=51, Quantity:=1, вроде бы ничего не напутал (связь-то есть).

Но чтение не идет :confused:



IF cmpl AND err=0 THEN (*потрошим байты*)
in1:=Buffer[1].0;
in2:= Buffer[1].1;
...
in8:=Buffer[1].7;

in9:=Buffer[0].0;
in10:=Buffer[0].1;
...
in16:=Buffer[0].7;
END_IF

В буфере одни нули, хотя на третий вход единичка подана. На приборе диод горит.

Попробовал еще так:


inp_word:=BYTE_TO_WORD(rd_buffer[1]) OR SHL(BYTE_TO_WORD(rd_buffer[0]),8);

in1:=(inp_word AND 1)=1;
in2:=(inp_word AND 2)=2;
in3:=(inp_word AND 4)=4;
...

и махнул MB_RD_INP_REGS на MB_RD_HOLD_REGS, теперь читает, но сильно эпизодически. Диод rs моргает как-то "порциями", очень редко по сравнению и МУ110-16Р в той же сети (стоят парой, для теста 16Р повторяет выходами входы 16ДН).

Гарчев Евгений
10.01.2013, 10:39
Введите задержку после опроса каждого из модулей.

mc_
10.01.2013, 15:57
Пока закоментил обращение блоку вывода, оставил один 16ДН. Работает значительно лучше (больше не пытаются друг друга перекричать), но задержки всё равно доходят до пяти секунд.

Открытие порта тоже, наверное, стоит вынести в PLC_PRG и отрабатывать один раз при старте?

mc_
11.01.2013, 10:02
Эх, не получается сделать красиво.
Скидал всё в одну программу и перебираю операции через CASE: чтение - задержка 100мс - запись - задержка 100 мс.
Теперь вечная ошибка 253, не могу избавиться.

А МВ110-16ДН всё время передает сигнал на третьем входе, независимо от реального состояния.

-----
UPD: поковырял немного (адреса терялись), теперь блоки работают, но именно что по очереди - один моргает диодом, другой устает ждать и ошибку показывает. А потом меняются ролями.
Err почти всегда 255, это вроде бы "таймаут". Может, с сетью что (длина икебаны на столе 0,5 метра), или с настройками самих блоков?

-----
UPD2: убрал проверку ошибок при связи с МУ110 (было условие "операция завершена и нет ошибок", стало просто "операция завершена"), то есть теперь контроллер просто кидается данными в сторону блока вывода. МУ110 реагирует адекватно и очень быстро - даже не успеваю разглядеть моргающий диод. Сомневаюсь, насколько это безопасно - аппарат будет стоять в цехе, рядом с движками, частотниками и прочим.

Пробовал так же изменить условия при чтении с МВ110, но в буфер писалась феерическая каша, вернул контроль ошибок на место.

Теперь аппарат работает так: МВ110 долго тупит (по таймауту), затем всё-таки читает данные и передает очередь. МУ110 получает данные, мгновенно срабатывает и передает очередь.
Настройки обоих блоков стандартные (кроме адреса), скорость 9600. Может, поднять до 19200?