parovoZZ, какой у Вас ПЛК?
Вид для печати
parovoZZ, какой у Вас ПЛК?
ОВЕН ПЛК100
1. Адресацию PSB, PSW, PFW можно начинать с любого адреса, но в адресах от 0 до 255 находятся системные регистры PSB, PSW, PFW и если Вы, не зная их назначения, запишите в них чего нибудь, то не обижайтесь после этого на панель:rolleyes:
2."А как в 8 bit input module записать?" Ни как, само название input module говорит, что модуль предназначен для чтения. Для записи нужен другой модуль, который output module :)
3."регистр 8 bit input module с адресом 256 и регистр Register input module с адресом 256 не пересекутся?" Не пересекутся.
4.А где они физически находятся? Кто они:confused:, если Вы про 8 bit input module и Register input module, то они находятся в ПЛК, каждый модуль по очереди формирует запрос к панели, на пример на запись регистров и получает ответ от панели о результате операции, или на чтение регистров панели и получает от нее содержимое затребованных регистров. ПЛК никакого адресного пространства в панели не делает, адресное пространство в панели существует даже если к ней не подключен ПЛК, это ее внутренняя память в виде трех непрерывных областей регистров PSW, PFW, PSB.
Про марку ПЛК ответа не получил, по этому сделал учебный проект для ПЛК100
Вложение 14470
и для панели
Вложение 14471
Хорошо, спасибо!
Только не понятно - два universal modbus device с одним адресом - допустимо?
Про адресное пространство я имел ввиду инициализацию переменных, но раз там только регистры, то ясно.
Ещё вопрос - как в один и тот же регистр и писать и читать из него же (хочу в панельке сделать чтение и запись настроек через один цифровой дисплей.
1. "два universal modbus device с одним адресом - допустимо?" - Допустимо, хоть 100 штук.
2. "как в один и тот же регистр и писать и читать из него же?" - Нужно иметь Register input module(для чтения) и Register output module(для записи) с одинаковыми адресами регистра.
Для увеличения скорости реакции панели и уменьшения трафика, все input module поместите в один universal modbus device, а все output module помести в другой universal modbus device, как в моем примере.
Для universal modbus device, в котором модули input, установите для параметра (6) Work mode значение By poll time. Т.е. ПЛК все время, с заданной периодичностью читает регистры панели (органы управления и элементы ввода)
Для universal modbus device, в котором модули output, установите для параметра (6) Work mode значение By value change или By command. В первом случае запись в регистры панели будет только при изменении значения в переменных output module, а во втором нужно в программе командовать записью в нужные регистры панели. Возможно понадобятся несколько universal modbus device с модулями input, для одних Work mode - By poll time, а для других Work mode - By comman. Это понадобится например для: -"хочу в панельке сделать чтение и запись настроек через один цифровой дисплей". Потому что, если хранить настройки в ПЛК, то после включения питания все настройки в ПЛК могут обнулиться, если Вы вздумаете в панели для ввода/вывода настроек использовать регистры PSW, а не PFW.
Не понятно ваше упорное желание иметь ПЛК мастером, а панель слейвом. Сплошной "геморрой" будет. Куда лучше наоборот сделать - панель мастер, а ПЛК слейв. Все переменные в модуле Slave ПЛК энергонезависимые. Значения переменных всегда актуальные, даже если панель "отвалиться". Конфигурирование Modbus Slave в ПЛК значительно проще чем Modbus Master. Скорость реакция системы ПЛК-панель будет выше.
а как командовать записью в регистры из программы?
у меня есть модули мв и му - для них плк мастер. если я на этот же интерфейс повешу панель мастер - косяка не произойдет? или лучше панель цеплять на отдельный 232?
и еще вопрос
адрес ввода, адрес вывода, адрес диагностики - это что?
есть еще вопрос по графику архивных данных - у меня их 16 штук и у всех указана область хранения psw 500-psw507. так и должно быть?
а если переменные в плк обозначить var retain? мне же настройки в панельке не за чем хранить.
У вас 16 входных переменных (4х1, 4х2 и т.д.) графика?
В области хранения PSW 500-506 хранятся координаты одной точки + дата + время.
В вашем случае (PSW500-507) либо у вас две выборки WORD, либо одна DWORD + время.
Текущие данные нужны для перемещения по тренду курсора с помощью 'Кнопка события'. Ставите две кнопки, выбираете в них действия: next item, prev item. Запускаете проект. Теперь при нажатии кнопок у вас появится курсор, который будет перемещаться по графику. В ячейке psw 500 будет отображаться текущее значение под курсором.
Как посмотреть где на самом деле хранятся данные архивного графика? Входите в свойства графика, переходите на вкладку управления. Там указан область хранения PSW/PFW и начальный номер регистра хранения. Количество регистров, выделяемых под хранение, меняется автоматически. В зависимости от количества входных переменных и точек графика.
Настройки в панели можно сохранять в регистрах PFW панели. В таком случае они сохранятся при отключении питания.
В этой теме http://www.owen.ru/forum/showthread.php?t=13179 выложены системные регистры панели
Среди них есть настройки портов
В своём проекте я использую оба порта. PLC настроен в мастер и занимается опросом оборудования. Download настроен подчинённым и будет подключаться у заказчика. Думаю, возможность настройки параметров по этому порту без перепрошивки панели будет весьма полезной. Делал ли кто-нибудь окно таких настроек?
На счет окна настроек Вам нужно к Андрею обратиться. http://www.owen.ru/forum/showthread.php?t=16765
На видео это окно на 46 сек.
:
Исчёрпывающе, спасибо
Вариашечка
Сделал отдельным экраном, так гораздо приятнее и универсальнее
Если кто-нибудь подскажет как конкатенацию строк сделать, попробую сделать поле, отображающее текущие настройки сети
И теперь вопрос
Вроде видел работу панелью со временем, но не знаю как искать
Мне требуется задавать текущее время и день недели в панели, а также время и день недели нескольких событий. Ну и делать всякие дела по наступлении событий этих.
Возможно такое? Какова реакция на потерю питания будет?
Здесь помогут регистры
PSW74,75 для порта PLC
Вложение 14633
и PSW64,65 для порта Download
Вложение 14634
Если ограничится из всех протоколов, имеющихся в панели http://www.owen.ru/forum/showthread....l=1#post101140,только протоколом ModBus, то
Настройки порта PSW64(74) PSW65(75) Порт не используется 0 0 Modbus RTU (Панель мастер) 5 13 Modbus ASCII (Панель мастер) 22 15 Modbus RTU Slave (ПЛК мастер) 23 5
В скобках регистры для порта PLC
Таким образом показывать поле адреса панели нужно (использовать IF) если, например, PSW64 или PSW74 равно 23 для выбранного порта.
Подскажите как можно с помощью панели задавать время работы блока "Blink" в ПЛК 160 ?
Смотрите пример на диске, который идет с ПЛК
Вложение 14645
или можно скачать отсюда http://www.owen.ru/forum/showthread.php?t=13581
Пример http://kipshop.ru/Primeri/HMI/03_06_...ter]_timer.zip
Проблема раз:
СП270 сильно умная, МУ110 не понимает глубины полёта мысли.
Использую для управления модулем скриптовую функцию Writes и регистр 50й (в него записывается состояние сразу всех выходов, это удобно), ожидая от неё запроса 0x10. Однако панелька оптимизирует запросы и, поскольку изменить требуется только один регистр, посылает запрос 0х06. К сожалению, МУ110 обрабатывать такие не умеет. Есть ли какой-либо способ уговорить панель использовать запрос 0х10? Ну, кроме работы с портом напрямую.
Проблема два:
Трудно выделить ключевые моменты, поэтому описываю целиком ситуацию.
Та же СП270 и МУ110. За обмен информацией отвечает скрипт. Его задача - при наличии разрешения (PSB) отправить регистры (PSW) по заданному адресу. Разрешение сделано с прицелом на расширение, поэтому бит разрешения сразу в скрипте устанавливается сразу и не снимается.
Теперь ситуация. Сразу после запуска панели она устанавливает нужное состояние выходов модуля. Как только действия оператора приводят к тому, что состояние выходов должно измениться, панель выполняет это (выходы переходят в нужное состояние) и тут же виснет (появляется микросхемка), перезагружается и всё по новой.
Причём:
1) Комментирование строчки скрипта, отвечающей за установку бита (SetPSB(...); ), делает прошивку стабильной.
2) Перенос строчки в другое место и усиленная проверка на ошибки ничего не меняет.
3) При закомментированной строчке скрипта тот же самый бит, установленный любым другим способом (вручную кнопкой управления битом или функциональной областью), не приводит к зависанию панели.
К сожалению, в "поле" у меня не было особой возможности и желания проводить эксперименты. Панельку работать заставил, однако неплохо бы знать причину такого поведения. Сталкивался ли кто-нибудь с подобным?
Спасибо, но хотелось бы решить это на скриптах
Вариант №1
Вложение 14935
Создаем команду 0х10 прямо в функции
Вариант №2Код://В примере адрес устройства равен 1
//Данные с маской выхoдов МУ в регистре PSW300
//*************************************************
BYTE snd[11]={0x01,0x10,0x00,0x32,0x00,0x01,0x02};//буфер для посылки команды slave
//[0]-адрес устройства(0x01)
//[1]-Код функции ModbusRTU 0x10 -запись нескольких регистров
//[2]-ст.байт адреса начального регистра(0x00)
//[3]-мл.байт адреса начального регистра(0x32)
//[4]-ст.байт количества регистров(0x00)
//[5]-мл.байт количества регистров(0x01)
//[6]-количество байтов(0x02)
//[7]-ст.байт значения в регистре(Определим ниже)
//[8]-мл.байт значения в регистре(Определим ниже)
//[9]-ст.байт CRC(Определим ниже)
//[10]-мл.байт CRC(Определим ниже)
BYTE rcv[8];//буфер для приема ответа от slave
//[0]-адрес устройства
//[1]-Код функции ModbusRTU-запись нескольких регистров 0x10
//[2]-ст.байт адреса начального регистра(0x00)
//[3]-мл.байт адреса начального регистра(0x32)
//[4]-ст.байт количества регистров(0x00)
//[5]-мл.байт количества регистров(0x01)
//[6]-ст.байт CRC
//[7]-мл.байт CRC
snd[7]=HIBYTE(PSW[300]);
snd[8]=LOBYTE(PSW[300]);
snd[9]=HIBYTE(Crc(snd,9));//дополнить команду CRC, сначала Hi
snd[10]=LOBYTE(Crc(snd,9));//затем Lo
//Crc() -внутренняя функция, ее писать не надо
Enter(PLC);//Захватить порт PLC
Send(PLC,snd,11);//Отправить команду
Receive(PLC,rcv,8,1000,6);//Получить ответ (тайм-аут 1000мс)
Leave(PLC);//Освободить порт
Вложение 14936
Создаем глобальную функцию для записи маски выходов в МУ110 с любым адресом
Теперь эту свою функцию можем использовать в любых местах любых скриптов наравне с стандартными функциями Write() или Writes()Код:BYTE MY_16WRITE(BYTE Adres, WORD Mask)
{
BYTE rcv[8];//буфер для приема ответа от slave
//[0]-адрес устройства
//[1]-Код функции ModbusRTU-запись нескольких регистров 0x10
//[2]-ст.байт адреса начального регистра(0x00)
//[3]-мл.байт адреса начального регистра(0x32)
//[4]-ст.байт количества регистров(0x00)
//[5]-мл.байт количества регистров(0x01)
//[6]-ст.байт CRC
//[7]-мл.байт CRC
BYTE snd[11]={0x01,0x10,0x00,0x32,0x00,0x01,0x02};//буфер для посылки команды slave
//[0]-адрес устройства
//[1]-Код функции ModbusRTU 0x10 -запись нескольких регистров
//[2]-ст.байт адреса начального регистра
//[3]-мл.байт адреса начального регистра
//[4]-ст.байт количества регистров
//[5]-мл.байт количества регистров
//[6]-количество байтов
//[7]-ст.байт значения в регистре
//[8]-мл.байт значения в регистре
//[9]-ст.байт CRC
//[10]-мл.байт CRC
snd[0]=Adres;
snd[7]=HIBYTE(Mask);//Данные с маской выхoдов МУ110 сначала Hi
snd[8]=LOBYTE(Mask);затем Lo
snd[9]=HIBYTE(Crc(snd,9));//дополнить команду CRC, сначала Hi
snd[10]=LOBYTE(Crc(snd,9));//затем Lo
//Crc() -внутренняя функция, ее писать не надо
Enter(PLC);//Захватить порт PLC
Send(PLC,snd,11);//Отправить команду
Receive(PLC,rcv,8,1000,6);//Получить ответ (тайм-аут 1000мс)
Leave(PLC);//Освободить порт
//Надо бы сделать проверку ошибок
//обмена, хотя бы CRC ответа сравнить
return TRUE;//Пока так
}
Например
UPD. Обновил вложения и картинки (были ошибки)Код://Используется глобальная функцияMY_16WRITE(BYTE Adres, WORD Mask)
//где
//Adres -Адрес устройства
//Mask -маска выходов
MY_16WRITE(1,PSW[300]);//Запись в МУ110 с адресом 1, маска в PSW300
MY_16WRITE(16,PSW[301]);//Запись в МУ110 с адресом 16, маска в PSW301
MY_16WRITE(32,PSW[302]);//Запись в МУ110 с адресом 32, маска в PSW302
То есть единственный вариант победить это - работа с портом напрямую
Спасибо большое
Ничего не поделаешь, буду пробовать реализовать
После создания своих функций в секции "Глобальная функция", а в этой секции глобальных функций может быть несколько, обращение к ним из скриптов ничем не отличается от обращения к встроенным функциям.
Для MY_16WRITE(BYTE Adres, WORD Mask)
Аргументы Adres и Mask могут быть константами, регистрами панели или результатом вычислений в текущем скрипте.
Что очень круто наваяли.:)
Изначально ведь нужно было записать всего один регистр командой 0х10. И в этом, частном случае нужно формировать посылку всего из 11 байт. Зачем своя функция для записи больше чем один регистр? По тому, что если регистров больше чем один, то и Writes() будет использовать команду 0х10.
А уж групповая посылка 124 регистров за раз это наверно через чур много.
А в этом фрагменте
Для ссылки 3х команда 0x0f не применимаКод:switch (objType) {
case MODBUS_RTU_REGS_3X:
bSend[1] = 0x0f;
case MODBUS_RTU_REGS_4X:
bSend[1] = 0x10;
default:
return Writes(comID, staID, objType, add1, regs, pRegs); //don't know what to do
}
http://www.owen.ru/forum/attachment....1&d=1397777586
Проще слепить свою универсальную функцию и не мучиться потом
Забавно, что панель записать позволяет в 3х регистры... Убрал досадную оплошность, спасибо.
В панели вроде работает, только не могу проверить обработку ошибок. Использую симулятор слейва PeakHMI http://www.hmisys.com/
Сейчас доведём до идеала :)
Чтобы не ошибиться, в первом регистре успешные попытки связи, во втором все безуспешные, в третьем все таймауты, в четвёртом все ошибки данных, причём второй равен сумме третьего и четвёртого, всё верно?
Увеличить таймаут до десяти секунд, подключить вместо нормального устройства просто терминал и любой ответ заслать
Любой ответ нельзя.
Вложение 14968
ЗЫ. Во вложении описание протокола
Популярно о Модбас https://sites.google.com/site/fieldb...odbuseducation
Вложение 14971
Насколько я понимаю, соответствие RS-485 будет обеспечено терминалом при передаче (если порт правильно настроен), а соответствие стандарту Modbus и правильность ответа проверяет уже скрипт.
Вот новая функция, проверить по-прежнему нет возможностиКод:const BYTES_PER_REG = 2;
const N_RETRIES = 3;
const RETRY_TIMEOUT = 1000; //ms
BOOL MWrites(int comID, int staID, int objType, int add1, int regs, void* pRegs) {
BYTE bSend[256], bRecieve[256], i;
WORD bBytesToSend = 0, bBytesRecieved = 65535;
BYTE nRetry = N_RETRIES; //Количество попыток повтора
BYTE offset_PSW_log;
int CrcSum;
switch (comID) {
case DOWNLOAD:
offset_PSW_log = 60;
break;
case PLC:
offset_PSW_log = 70;
break;
default:
return Writes(comID, staID, objType, add1, regs, pRegs); //don't know what to do
}
bSend[0] = staID;
switch (objType) {
case MODBUS_RTU_REGS_4X:
bSend[1] = 0x10;
break;
default:
return Writes(comID, staID, objType, add1, regs, pRegs); //don't know what to do
}
bSend[2] = HIBYTE(add1);
bSend[3] = LOBYTE(add1);
bSend[4] = HIBYTE(regs);
bSend[5] = LOBYTE(regs);
bSend[6] = regs * BYTES_PER_REG;
bBytesToSend = 7;
for (i=0; i<regs*2; i++) {
bSend[bBytesToSend] = ((BYTE*)pRegs)[i];
bBytesToSend++;
}
CrcSum = Crc(bSend, bBytesToSend);
bSend[bBytesToSend] = LOBYTE(CrcSum);
bSend[bBytesToSend + 1] = HIBYTE(CrcSum);
bBytesToSend += 2;
if (bBytesToSend > 256)
return FALSE;
Enter(comID);//Захватить порт PLC
do {
if (bBytesRecieved != 65535) { //Была ошибка связи
PSW[offset_PSW_log+1]++;
if (bBytesRecieved != 0) // Ошибка данных
PSW[offset_PSW_log+3]++;
//else //Таймаут
// PSW[offset_PSW_log+2]++;
}
Send(comID, bSend, bBytesToSend);//Отправить команду
bBytesRecieved = Receive(comID, bRecieve, 256, RETRY_TIMEOUT, 6);//Получить ответ (тайм-аут 1000мс)
} while ((bBytesRecieved == 0 || //Если данные получены
bRecieve[0] != staID || //От правильного устройства
bRecieve[1] != bSend[1] || //Правильной функцией
MAKEWORD(bRecieve[3], bRecieve[2]) != add1 || // По правильному адресу
MAKEWORD(bRecieve[5], bRecieve[4]) != regs || // Правильное количество регистров
Crc(bRecieve, bBytesRecieved) != 0 //Контрольная сумма в порядке
) && (nRetry--)>0); //... то всё ок, иначе отнимаем попытку и, если они остались, пытаемся ещё
Leave(comID);//Освободить порт
if (nRetry>0) { //Если попытки остались, значит, последняя попытка связи была успешной
PSW[offset_PSW_log]++;
return TRUE;
} else
return FALSE;
}
Скрипт не проверяет ситуацию ошибок второго типа, например если мастер пытается записать регистр в слейв по несуществующему адресу регистра, то в ответ будет послан пакет из 5 байт, а не из 8.
//[0]-адрес устройства
//[1]-Код функции ModbusRTU с индикацией ошибки-запись нескольких регистров 0x90
//[2]-код ошибки (0x02)
//[3]-ст.байт CRC
//[4]-мл.байт CRC
см пост#620
ЗЫ. Стандартые процедуры обмена при ошибках записывают в регистре PSW61(PSW71) число не успешных попыток обмена без учета повторных попыток, а в PSW62(PSW72) и PSW64(PSW73) с учетом повторных попыток, т.е. если число повторов задано 3, то при тайм-ауте PSW61(PSW71)=N, а PSW62(PSW72)=3хN, где N-число команд записи
А теперь? :)
По задумке эта строка проверяет чего там вернуло устройство, и в случае возвращённой ошибки там будет не 0х10, а 0х90. Скрипт ещё несколько раз помучает устройство и отстанет, записав всё в ошибки. По задумке.Код:bRecieve[1] != bSend[1] || //Правильной функцией
Если нам не важна причина ошибок, тот же неверный адрес регистра, для дальнейшего принятия решений, то тогда можно ограничится и просто констатацией ошибки.
Я не вижу других вариантов
Штатные функции не поддерживают такого и смысла расширять возможности нет
Самое интересное, что похоже без наших усилий в регистры PSW62(PSW72) панель и так сама пишет даже для команд Send() и Receive()
Регистры PSW63(PSW73) проверяю.
ЗЫ PSW60(PSW70) (Успешные попытки) автоматически не обновляются
В общем тайм-аут Receive() вызывает автоматическое увеличение PSW62(PSW72) на 1
PSW60(PSW71), PSW61(PSW71), PSW63(PSW73) автоматически не увеличиваются.
Правда? Хм... Ну убрал тогда таймауты
Помогите с проблемой: создаю проект (панель мастер, частотник слэцв) в проекте создаю две кнопки управления (пуск и стоп чп), в настройках этими кнопками указываю Регистр: 0х, адрес регистра пуска 0 для стоп 1. загружаю проект в панель, перезагружаю ее, все работает: нажимаю на пуск на частотнике загорается кнопка пуск - частотник стартует, нажимаю стоп - на частотник приходит команда стоп, частотник останавливается. все ок. на этом этапе нет проблем.
в проекте создаю "цифровой дисплей" регистр 4х (инпутЪ), адрес 1 (должен отображать частоту на выходе частотника), также добавляю цифровой ввод регистр 3х (холдинг) (типо задание Hz).
гружу в панель. перезагружаю ее и тут возникают проблемы, вылазиет окно в котором сообщается: потеря связи с плк.
ожидание в настройках панели выставил 250мс. когда были только кнопки проблем небыло со связью.