Инициализация слейва в сети modbus RTU
- Войдите на сайт для отправки комментариев
Вс, 09/04/2017 - 12:20
Помогите хотя бы составить алгоритм действий как можно проверять мастером слейв на предмет того, в сети он или нет. Мое видение такое.
Слейв периодически записывает в какой-нибудь регистр модбаса, то «0», то «1». Мастер периодически считывает этот регистр например сериями по 4 раза. В одной серии каждое считывание записывается в свою переменную. По окончании серии (4—ое считывание) переменные сравниваются на предмет равенства между собой, и если они равны друг другу (все ноли либо все единицы) то слейв не отзывается. Если разные - он дергает регистром, значит в сети.
Но мне кажется это громоздко, так сказать будет поговнокодски. Опытные, подскажите как проще сделать?
Достаточно послать любой запрос. Если случился любой error - не в сети. Если ответ пришёл - в сети. На любой запрос библиотека возвращает статус. Его надо проверять. Этого достаточно.
Каждый слейв с точки зрения МК мастера должен быть объектом, который описан как класс или как структура. Скорее у мастера даже есть указатель на обьект Cl_slave * Slave1, Slave2; И вот в МК мастера идет команда Slave1->Ready(); И если возвращает 0, то слев тю-тю . А вот если 1 то он в сети. И разумеется в методе byte Cl_slave::Ready() или идет прямой запрос по сети и ждет ответ. Разумеется это тормозит процессор. Или скорее всего раз в минуту мастер посылает общий запрос по сети "Кто живой". И заносит в объекты Slave1, Slave2 их ответы. Это ускоряет работу МК вцелом.
ПС: Что тут придумавать . Вот посмотрите работу Serial.available();
спасибо, ваш ответ направил меня на поиск туда, с помощью чего я создаю модбас - программа FLprog. Оказывается автор проги всё уже сделал, для этого есть специальная функция
вот что получилось. работает
////////////// Пример Master-а считывающего Coils Register 01, ////////////// и мониторящего slave ID-1 на предмет пропадания в сети // ниже для модбаса #include <SoftwareSerial.h> SoftwareSerial Serial100(7, 8); // модбас (RS 485) висит на софтсериале. 7-RX; 8-TX bool _modbusMasterDataTable_0_reg_1[1]; int _modbusMasterAddressTable_0_reg_1[1] = {0}; // адреса считываемого регистра, в данном случае "0" Coils byte _modbusMasterBufferSize = 0; byte _modbusMasterState = 1; long _modbusMasterSendTime; byte _modbusMasterLastRec = 0; long _modbusMasterStartT35; byte _modbusMasterBuffer[64]; byte _modbusMasterCurrentReg = 0; byte _modbusMasterCurrentVariable = 0; struct _modbusMasterTelegramm { byte slaveId; byte function; int startAddres; int numbeRegs; int valueIndex; }; _modbusMasterTelegramm _modbusTelegramm; long _startTimeMasterRegs[1]; long _updateTimeMasterRegsArray[] = {1000}; // интервал обмена данными со слейвом - 1 секунда const unsigned char _modbusMaster_fctsupported[] = {1, 5}; byte _modbuseLastError1_ErrCode = 0; //////ниже наши переменные bool Register1_Coils = 0; // сюда пишется регистр 01 coils модбаса long prevMillis_Serial = 0; // храним время последнего вывода в сериал порт long prevMillis_Errors = 0; // храним время последнего считываения ошибок модбаса int errorsSlave1 =0; // количество ошибок "слейв не отвечает" int Slave1good = 0; // количество измерений, при которых отсутствуют ошибки "слейв не отвечает" bool StatusSlave = 0; // статус активности слейва void setup() { Serial.begin (9600); Serial100.begin(9600); // софт сериал для модбаса( RS-485) pinMode(4, OUTPUT); // пин DE-RE RS-485 к 4 пину дуни, нельзя менять digitalWrite(4, LOW); pinMode(13, OUTPUT); // индикация втроенным светодиодом, когда слейв не отвечает digitalWrite(13, LOW); // цикл фор нужен для модбаса for(int i=0; i<1; i++) {_startTimeMasterRegs[i] = millis();} } void loop() { /////// Проверка и подсчет ошибок "слейв не отвечает" 1 раз в секунду unsigned long curMillis_Errors = millis(); if(curMillis_Errors - prevMillis_Errors > 1000 ) { // в описании ошибок FLpog неправильно указана ошибка "слейв не отвечает" (там 244, на самом деле ошибка 254) if (_modbuseLastError1_ErrCode==254) errorsSlave1++; // прибавляем счетчик ошибок при их наличии if (_modbuseLastError1_ErrCode==0) Slave1good++; // прибавляем счетчик отсутствия ошибок при их отсутствии prevMillis_Errors = curMillis_Errors;} ///////Вывод данных в сериал раз в полсекунды unsigned long curMillis_Serial = millis(); if(curMillis_Serial - prevMillis_Serial > 500 ) { Serial.print ("Error ID01: "); Serial.print (_modbuseLastError1_ErrCode); Serial.print (" Coils_Reg01: "); Serial.print (Register1_Coils); Serial.print (" ErrorsSlave1: "); Serial.print (errorsSlave1); Serial.print (" Slave1good: "); Serial.print (Slave1good); Serial.print (" StatusSlave: "); Serial.println (StatusSlave); prevMillis_Serial = curMillis_Serial;} ////////диапазон счетчиков ошибок от 0 до 10 if (Slave1good>10) {Slave1good =10; errorsSlave1 = 0;} if (errorsSlave1>10) {errorsSlave1 =10; Slave1good = 0;} ////////если 10 ошибок набралось, значит слейв молчит, статус в ноль if (errorsSlave1>=10) StatusSlave = 0; ////////если 10 секунд без ошибок - слейв активен, статус 1 if (Slave1good>=10) StatusSlave = 1; /////// зажигаем сигнальную лампу, если слейв упал. digitalWrite (13,!StatusSlave); /////// пишем регистр модбаса в переменную Register1_Coils = (_modbusMasterDataTable_0_reg_1[0]); // всё что ниже, требуха для модбаса switch ( _modbusMasterState ) { case 1: _nextModbusMasterQuery(); break; case 2: pollModbusMaster(); break; } } bool _isTimer(unsigned long startTime, unsigned long period ) { unsigned long currentTime; currentTime = millis(); if (currentTime>= startTime) {return (currentTime>=(startTime + period));} else {return (currentTime >=(4294967295-startTime+period));} } int modbusCalcCRC(byte length, byte bufferArray[]) { unsigned int temp, temp2, flag; temp = 0xFFFF; for (unsigned char i = 0; i < length; i++) { temp = temp ^ bufferArray[i]; for (unsigned char j = 1; j <= 8; j++) { flag = temp & 0x0001; temp >>= 1; if (flag) temp ^= 0xA001; } } temp2 = temp >> 8; temp = (temp << 8) | temp2; temp &= 0xFFFF; return temp; } void _nextModbusMasterQuery() { _selectNewModbusMasterCurrentReg(_modbusMasterCurrentReg, _modbusMasterCurrentVariable); if (_modbusMasterCurrentReg == 0) return; _createMasterTelegramm(); _modbusMasterSendQuery(); } void _selectNewModbusMasterCurrentReg(byte oldReg, byte oldVar) { bool isNeeded = 1; if (oldReg == 0) {_selectNewModbusMasterCurrentReg(1, 0); return;} if (!(_isTimer ((_startTimeMasterRegs[oldReg - 1]),(_updateTimeMasterRegsArray[oldReg -1])))) {isNeeded = 0;} if( ! isNeeded ) {if(oldReg < 1) {_selectNewModbusMasterCurrentReg(oldReg+1, 0); return;} else {_modbusMasterCurrentReg = 0; _modbusMasterCurrentVariable = 0; return;}} if (oldVar == 0) {_modbusMasterCurrentReg = oldReg; _modbusMasterCurrentVariable = 1; return;} byte temp; switch (oldReg) { case 1: temp = 1; break; } if (oldVar < temp) {_modbusMasterCurrentReg = oldReg; _modbusMasterCurrentVariable = oldVar +1; return;} _startTimeMasterRegs[oldReg -1] = millis(); if(oldReg < 1) { _selectNewModbusMasterCurrentReg(oldReg+1, 0); return;} _modbusMasterCurrentReg = 0; _modbusMasterCurrentVariable = 0; return; } void _createMasterTelegramm() { switch (_modbusMasterCurrentReg) { case 1: _modbusTelegramm.slaveId = 1; switch (_modbusMasterCurrentVariable) { case 1: _modbusTelegramm.function = 1; _modbusTelegramm.startAddres = 0; _modbusTelegramm.numbeRegs = 1; _modbusTelegramm.valueIndex = 0; break; } break; } } void _modbusMasterSendQuery() { byte currentIndex = _modbusTelegramm.valueIndex; _modbusMasterBuffer[0] = _modbusTelegramm.slaveId; _modbusMasterBuffer[1] = _modbusTelegramm.function; _modbusMasterBuffer[2] = highByte(_modbusTelegramm.startAddres ); _modbusMasterBuffer[3] = lowByte( _modbusTelegramm.startAddres ); switch ( _modbusTelegramm.function ) { case 1: _modbusMasterBuffer[4] = highByte(_modbusTelegramm.numbeRegs ); _modbusMasterBuffer[5] = lowByte( _modbusTelegramm.numbeRegs ); _modbusMasterBufferSize = 6; break; } _modbusMasterSendTxBuffer(); _modbusMasterState = 2; } void _modbusMasterSendTxBuffer() { byte i = 0; int crc = modbusCalcCRC( _modbusMasterBufferSize, _modbusMasterBuffer ); _modbusMasterBuffer[ _modbusMasterBufferSize ] = crc >> 8; _modbusMasterBufferSize++; _modbusMasterBuffer[ _modbusMasterBufferSize ] = crc & 0x00ff; _modbusMasterBufferSize++; digitalWrite(4, 1 ); delay(5); Serial100.write( _modbusMasterBuffer, _modbusMasterBufferSize ); digitalWrite(4, 0 ); Serial100.flush(); _modbusMasterBufferSize = 0; _modbusMasterSendTime = millis(); } void pollModbusMaster() { if (_modbusTelegramm.slaveId == 0) { _modbusMasterState = 1; return;} if (_isTimer(_modbusMasterSendTime, 1000)) { _modbusMasterState = 1; switch ( _modbusTelegramm.slaveId ) {case 1: _modbuseLastError1_ErrCode = 254; break; } return; } byte avalibleBytes = Serial100.available(); if (avalibleBytes == 0) return; if (avalibleBytes != _modbusMasterLastRec) { _modbusMasterLastRec = avalibleBytes; _modbusMasterStartT35 = millis(); return; } if (!(_isTimer(_modbusMasterStartT35, 5 ))) return; _modbusMasterLastRec = 0; byte readingBytes = _modbusMasterGetRxBuffer(); if (readingBytes < 5) { _modbusMasterState = 1; return ; } byte exeption = validateAnswer(); if (exeption != 0) { switch ( _modbusTelegramm.slaveId ) {case 1: _modbuseLastError1_ErrCode = exeption; break; } _modbusMasterState = 1; return; } _modbuseLastError1_ErrCode = 0; switch ( _modbusMasterBuffer[1] ) { case 1: get_FC1(0); break; } _modbusMasterState = 1; return; } byte _modbusMasterGetRxBuffer() { boolean bBuffOverflow = false;digitalWrite(4, LOW ); _modbusMasterBufferSize = 0; while (Serial100.available() ) { _modbusMasterBuffer[ _modbusMasterBufferSize ] = Serial100.read(); _modbusMasterBufferSize ++; if (_modbusMasterBufferSize >= 64) bBuffOverflow = true; } if (bBuffOverflow) {return -3;} return _modbusMasterBufferSize; } byte validateAnswer() { uint16_t u16MsgCRC = ((_modbusMasterBuffer[_modbusMasterBufferSize - 2] << 8) | _modbusMasterBuffer[_modbusMasterBufferSize - 1]); if ( modbusCalcCRC( _modbusMasterBufferSize - 2,_modbusMasterBuffer ) != u16MsgCRC ) { return 255; } if ((_modbusMasterBuffer[1] & 0x80) != 0) {return _modbusMasterBuffer[2] ;} boolean isSupported = false; for (byte i = 0; i < sizeof( _modbusMaster_fctsupported ); i++) { if (_modbusMaster_fctsupported[i] == _modbusMasterBuffer[1]) { isSupported = 1; break; } } if (!isSupported) {return 1;} return 0; } void get_FC1(byte table) { byte currentByte = 3; byte currentBit = 0; bool value; byte i; int currentIndex = _modbusTelegramm.valueIndex; for (i = 0; i < _modbusTelegramm.numbeRegs; i++) { value= bitRead(_modbusMasterBuffer[currentByte], currentBit); switch ( _modbusMasterCurrentReg ) { case 1 : if(table == 0) {_modbusMasterDataTable_0_reg_1[currentIndex] =value;} break; } currentIndex ++; currentBit ++; if (currentBit > 7) { currentBit = 0; currentByte ++; } } _modbusMasterState = 1; }И что это за письменное народное творчество- называемое ФИГ-ВАМ. И куда эту простынь засунуть.
Я размечтался что будет так. А получилось как в сказке.
#include "Cl_wire.h" Cl_wire Wire; #include "Cl_Slave.h" Cl_Slave Slave_1(&Wire, 0x01);//0x01 адрес 1 внеш устройства Cl_Slave Slave_2(&Wire, 0x02);//0x02 адрес 2 внеш устройства void setup() { Serial.begin(9600); Wire.setup(); Slave_1.setup(); Slave_2.setup(); } void loop() { Slave_1.loop(); Slave_2.loop(); if (Slave_1.available())Serial.println(Slave_1.buffer); if (Slave_2.available())Serial.println(Slave_2.buffer); }Как смог так и сделал. Опыта мало. Надо было с детства начинать программировать. А простыню можно во вкладку отдельную сложить. ВигВа... Модбас называется.
Так это не вкладка будет, а библиотека. Вот я поэтому вам подсказываю куда двигать. Вот посмотрите вариант Пакет здесь https://yadi.sk/d/WaW7iUgj3GPUvp
Головной файл выложу если интересно кому
/*Wire_74HC595.ino */ const int Latch_pin = 3; const int CLK_pin = 4; const int Data_pin = 2; const int max_device = 4; bool stat = 0; #include "Out_74HC595.h" Out_74HC595 Out(Latch_pin, CLK_pin, Data_pin, max_device); #include "Cl_led.h" Cl_led led[] = { Cl_led(&Out, 0, 1, 0), // шина-Out,1 горит,1-я 74HC595,D0 Cl_led(&Out, 0, 1, 1), // шина-Out,1 горит,1-я 74HC595,D1 Cl_led(&Out, 0, 1, 2), // шина-Out,1 горит,1-я 74HC595,D2 Cl_led(&Out, 0, 1, 3) // шина-Out,1 горит,1-я 74HC595,D3 }; void setup() { Out.setup(); for (byte i = 0; i < 4; i++) led[i].setup(); led[0].blink(100); led[1].blink(150); led[2].blink(500); led[3].blink(1000); } void loop() { for (byte i = 0; i < 4; i++) led[i].loop(); }