Популярно о Модбас https://sites.google.com/site/fieldb...odbuseducation
Вложение 14971
Вид для печати
Популярно о Модбас 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мс. когда были только кнопки проблем небыло со связью.