Modbus RTU

nik182
Offline
Зарегистрирован: 04.05.2015

Прочитайте описание протокола MODBUS. Все ответы там. Конкректно по #46. Ответте на вопрос: Какой номер команды для чтения регистров слейва? А теперь попробуйте найти эту команду в вашем скетче. Наводка - телеграмм должно быть как минимум две - одна для записи, другая для чтения.

James
Offline
Зарегистрирован: 26.02.2016

я скетч и выложил полностью, что бы показать, что номер сериала задается вами в Modbus slave(ID, 0, 10); где 0- номер сериала
вот пример чтения аналоговых портов

 

#include "ModbusRtu.h"

#define ID   1      // адрес ведомого
#define stlPin  13  // номер выхода индикатора работы
                    // расположен на плате Arduino


//Задаём ведомому адрес, последовательный порт, выход управления TX
Modbus slave(ID, 0, 10); 
int8_t state = 0;
unsigned long tempus;

// массив данных modbus
uint16_t au16data[11];

void setup() {
  // настраиваем входы и выходы
  io_setup();
  // настраиваем последовательный порт ведомого
  slave.begin( 9600 ); 
  // зажигаем светодиод на 100 мс
  tempus = millis() + 100; 
  digitalWrite(stlPin, HIGH );
}

void io_setup() {
  
  digitalWrite(stlPin, HIGH ); 
  pinMode(stlPin, OUTPUT);   
}

void loop() {
  // обработка сообщений
  state = slave.poll( au16data, 11);  
  // если получили пакет без ошибок - зажигаем светодиод на 50 мс 
  if (state > 4) {
    tempus = millis() + 50;
    digitalWrite(stlPin, HIGH);
  }
  if (millis() > tempus) digitalWrite(stlPin, LOW );
  //обновляем данные в регистрах Modbus и в пользовательской программе
  io_poll();
} 

void io_poll() {
  //Копируем Coil[1] в Discrete[0]
  //Сохраняем состояние аналоговых входов
  au16data[1,1] = analogRead( A0 );
  au16data[2,2] = analogRead( A1 );
  au16data[3,3] = analogRead( A2 );
  au16data[4,4] = analogRead( A3 );
  
  //Сохраняем в регистры отладочную информацию
  au16data[8] = slave.getInCnt();
  au16data[9] = slave.getOutCnt();
  au16data[10] = slave.getErrCnt();
}

и зачем тебе именно программный ? 

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

James пишет:

я скетч и выложил полностью, что бы показать, что номер сериала задается вами в Modbus slave(ID, 0, 10); где 0- номер сериала
вот пример чтения аналоговых портов

и зачем тебе именно программный ? 

спасибо за пример, это я понял что второй параметр это номер сериала, но хотел использовать программный чтоб сериал 0 не занимать на микро. но в принципи буду использовать его а для отладки попользую программный сериал.

тут другая проблемка вылезла не могу от слейва прочитать настере ответ.. пока не понимаю почему, У Вас случаем нет примера рабочего?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
// интересная конструкция
// запуск отложеного действия
tempus = millis() + 50;
digitalWrite(stlPin, HIGH);
// и выподнение этого действия  
if (millis() > tempus) digitalWrite(stlPin, LOW );
// но это действие повторяется много раз уже позже.
// и в этом у него недостаток

// Но есть интересная модификация этого приема

uint8_t stl; //  можно и bool, но все равно будет байт потерян

// запуск 
tempus = millis() + 50;
digitalWrite(stlPin, stl=1);
// разумеется можно так , но выше короче запись
// stl=1;
//digitalWrite(stlPin, stl);

// и наконец само действие
if (stl && millis() > tempus) digitalWrite(stlPin, stl=0);
// которое тоже можно разложить на две строки взятые в {}
// плюс в том что можно даже отослать единственное сообщение отложеное во времени
Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

qwone, убейся об стену, твой говнокод не будет правильно работать

tempus = millis() + 50;

Это 100% ошибка.

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

qwone пишет:

// интересная конструкция
// запуск отложеного действия
tempus = millis() + 50;
digitalWrite(stlPin, HIGH);
// и выподнение этого действия  
if (millis() > tempus) digitalWrite(stlPin, LOW );
// но это действие повторяется много раз уже позже.
// и в этом у него недостаток

// Но есть интересная модификация этого приема

uint8_t stl; //  можно и bool, но все равно будет байт потерян

// запуск 
tempus = millis() + 50;
digitalWrite(stlPin, stl=1);
// разумеется можно так , но выше короче запись
// stl=1;
//digitalWrite(stlPin, stl);

// и наконец само действие
if (stl && millis() > tempus) digitalWrite(stlPin, stl=0);
// которое тоже можно разложить на две строки взятые в {}
// плюс в том что можно даже отослать единственное сообщение отложеное во времени

я чтото вас совсем не пойму... что это такое?

nik182
Offline
Зарегистрирован: 04.05.2015

Baks пишет:

я проблемка вылезла не могу от слейва прочитать настере ответ.. пока не понимаю почему, У Вас случаем нет примера рабочего?

Вы в коде мастера #46 поменяйте функцию с 6 на 3 и всё получите. 

James
Offline
Зарегистрирован: 26.02.2016

 

я читаю через ОРС сервер, мастером как то не заморачивался, пока не приходилось

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

со слейва отправляю так  au16data[1,1] = 1;

		  au16data[1,1] = 1;
		  au16data[2,2] = 3;
		  au16data[3,3] = 3;
		  au16data[4,4] = 3;
		    Serial.println(  '1' );
		 Serial.println( au16data[3,3] );

 в манитор того же слейва приходит один мусор в виде черточек

James
Offline
Зарегистрирован: 26.02.2016
Serial.println( au16data[3,3] ,DEC);

http://arduino.ru/Reference/Serial/Println

nik182
Offline
Зарегистрирован: 04.05.2015

Baks пишет:

со слейва отправляю так  au16data[1,1] = 1;

		  au16data[1,1] = 1;
		  au16data[2,2] = 3;
		  au16data[3,3] = 3;
		  au16data[4,4] = 3;
		    Serial.println(  '1' );
		 Serial.println( au16data[3,3] );

 в манитор того же слейва приходит один мусор в виде черточек

Скажите, почему au16data двух мерный массив? Он должен быть одномерным для работы с MODBUS.

James
Offline
Зарегистрирован: 26.02.2016

кому он должен?
там идет [номер регистра], бит. ну тут это излишество. но оно работает. Пример вылаживал свой, под определенные цели

nik182
Offline
Зарегистрирован: 04.05.2015

Ну да конечно. Никто ни кому не должен. Вот только библиотека кушает линейно с начала массива и третий элемент никак не может быть au16data[3,3]. 

James
Offline
Зарегистрирован: 26.02.2016

вот пример из самой библиотеки
 

void io_poll() {
  //Копируем Coil[1] в Discrete[0]
  au16data[0] = au16data[1];
  //Выводим значение регистра 1.3 на светодиод 
  digitalWrite( ledPin, bitRead( au16data[1], 3 ));
  //Сохраняем состояние кнопки в регистр 0.3 //0,3 Карл
  bitWrite( au16data[0], 3, digitalRead( btnPin ));
  //Копируем Holding[5,6,7] в Input[2,3,4]
  au16data[2] = au16data[5];
  au16data[3] = au16data[6];
  au16data[4] = au16data[7];
  //Сохраняем в регистры отладочную информацию
  au16data[8] = slave.getInCnt();
  au16data[9] = slave.getOutCnt();
  au16data[10] = slave.getErrCnt();
}

 

nik182
Offline
Зарегистрирован: 04.05.2015

Может быть мы про разные библиотеки говорим? Вот этот бред я вообще не понимаю au16data[0] = au16data[1];

У меня ModBusRTU. Там

void io_poll() {
  // get digital inputs -> au16data[0]
  bitWrite( au16data[0], 0, digitalRead( 2 ));
  bitWrite( au16data[0], 1, digitalRead( 3 ));
  bitWrite( au16data[0], 2, digitalRead( 4 ));
  bitWrite( au16data[0], 3, digitalRead( 5 ));

  // set digital outputs -> au16data[1]
  digitalWrite( 6, bitRead( au16data[1], 0 ));
  digitalWrite( 7, bitRead( au16data[1], 1 ));
  digitalWrite( 8, bitRead( au16data[1], 2 ));
  digitalWrite( 9, bitRead( au16data[1], 3 ));

  // set analog outputs
  analogWrite( 10, au16data[2] );
  analogWrite( 11, au16data[3] );

  // read analog inputs
  au16data[4] = analogRead( 0 );
  au16data[5] = analogRead( 1 );

  // diagnose communication
  au16data[6] = slave.getInCnt();
  au16data[7] = slave.getOutCnt();
  au16data[8] = slave.getErrCnt();
} 

нет никаких переприсвоений внутри массива. Только присвоение элементам массива значений.

James
Offline
Зарегистрирован: 26.02.2016

https://habrahabr.ru/post/249043/
вот статья, брал отсюда. Наверное просто на гите обнова была, и у меня версия старая

nik182
Offline
Зарегистрирован: 04.05.2015

Ну да. Один бред наложен на другой. Брать надо первоисходники. Это раз. Читать стандарт. Это два. Сравнить стандарт с реализацией. Это три.

Конкретно по данной библиотеке нет различия для coil holding и прочих регистров. Разница есть только в доступе при чтении разными командами. При этом одину и туже ячейку памяти можно читать разными командами как coil и как holding, так и писАть. Копирование из регистра в регистр не имеет смысла, если явно не объявлено количество coil регистров.

 

James
Offline
Зарегистрирован: 26.02.2016

брать нужно под задачу. Не всегда обновления приносят "радость и легкость". Для моей задачи этого было достаточно. стандарт? покажи мне единый стандарт на регистры. Вот что нужно делать только так. Да нет такого, каждый свой производитель свой лепит.Да ладно, прям они все открыты  для чтения/записи?
а по поводу смысла к копировании, он был прост. Пример для регистров, соберите его и попробуйте с ОРС сервера или скады в input вписать что-то. пример - это пример. смысл в нем обычно показать базовые команды.
Пример не мой, так что выводы это мое личное мнение. Мне лично было очень легко по нему понять как пользоваться библиотекой. 

James
Offline
Зарегистрирован: 26.02.2016

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

 au16data[1,1] = 1;
 au16data[1,2] = 3;
 au16data[1,3] = 3;
 au16data[1,4] = 3;

вот тогда оно поломается. Согласен. Я писал тот скетч давно, вот правильно

 au16data[1] = 1;
 au16data[2] = 3;
 au16data[3] = 3;
 au16data[4] = 3;
 

nik182
Offline
Зарегистрирован: 04.05.2015

James пишет:

Да ладно, прям они все открыты  для чтения/записи?

В реализации данной библиотеки, все объявленные регистры открыты для чтения/записи.

Зачем стандарт на регистры? Я имел в виду стандарт на протокол MODBUS. В нем все написано про регистры. Вы сам должны выбрать, что куда писать и что читать. Никогда не пользовался ни ОРС ни скадой. Сам писал на дельфи мастера и никаких ограничений на запись чтение регистров не имел.   

James
Offline
Зарегистрирован: 26.02.2016

я же и прошу показать где это четко прописано. Не рекомендации, а тот как должно быть
т.е. вы программно на слейве не ограничивали на запись никакие регистры? странно, кто ж тогда стандарт не соблюдает

nik182
Offline
Зарегистрирован: 04.05.2015

Ещё раз. Это чужая библиотека. Я к ней не имею ни какого отношения. Ничего на слейве я ограничить не могу. Тем более что ( цитата из Wiki) Спецификация не определяет, что физически должны представлять собой элементы таблиц и по каким внутренним адресам устройства они должны быть доступны. Например, допустимо организовать перекрывающиеся таблицы. В этом случае команды работающие с дискретными данными и с 16-битными регистрами будут фактически обращаться к одним и тем же данным.

Или из святцев: It’s obvious that all the data handled via MODBUS (bits, registers) must be located in device application memory. But physical address in memory should not be confused with data reference. The only requirement is to link data reference with physical address.

Последнее предложение как раз и говорит, что вы должны обеспечить связь между физическими адресами и логическими запросами. Ограничений в спецификации MODBUS не прописано. 

James
Offline
Зарегистрирован: 26.02.2016

вы меня не так поняли, я имел ввиду, что если вы на слейве делали Input регистр, то с мастера могли его перезаписывать?

nik182
Offline
Зарегистрирован: 04.05.2015

Я не делал на слейве ничего. Это библиотека. Для неё нет понятия Input регистр. У неё есть ячейки памяти в которые можно писать и которые можно читать. Если бы я писал слейва и мне нужно было бы ограничить запись в эти ячейки, я бы это сделал. 

James
Offline
Зарегистрирован: 26.02.2016
enum MB_FC {
  MB_FC_NONE                     = 0,   /*!< null operator */
  MB_FC_READ_COILS               = 1,	/*!< FCT=1 -> read coils or digital outputs */
  MB_FC_READ_DISCRETE_INPUT      = 2,	/*!< FCT=2 -> read digital inputs */
  MB_FC_READ_REGISTERS           = 3,	/*!< FCT=3 -> read registers or analog outputs */
  MB_FC_READ_INPUT_REGISTER      = 4,	/*!< FCT=4 -> read analog inputs */
  MB_FC_WRITE_COIL               = 5,	/*!< FCT=5 -> write single coil or output */
  MB_FC_WRITE_REGISTER           = 6,	/*!< FCT=6 -> write single register */
  MB_FC_WRITE_MULTIPLE_COILS     = 15,	/*!< FCT=15 -> write multiple coils or outputs */
  MB_FC_WRITE_MULTIPLE_REGISTERS = 16	/*!< FCT=16 -> write multiple registers */
};
вот с библиотеки

 

nik182
Offline
Зарегистрирован: 04.05.2015

Это список команд, которые понимает библиотека. Какое отношение они имеют к регистрам? Откройте хотя бы вики и прочитайте про регистры и команды.

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

мужики да хорош вам, я выложил массив многомерный только для пробы, и еще гдето видел пример тоже кто то делал в сети.

а вообще пробую по всякому и пытаюсь понять что за фигня и почему слейв не отвечает мастеру или пакеты не доходят или я читаю не правильно

 

вот  что выдала терминальная программка и помоему что то тут не все в порядке с пакетами, или я ошибаюсь? и какойто бред в столбике slaveID

nik182
Offline
Зарегистрирован: 04.05.2015

Это не терминальная программа. Её нельзя использовать для дешифрации чужих мастер пакетов. В правом верхнем окне показаны RAW пакеты идущие по сети. Они абсолютно правильные для включения - выключения диода, такие же как в вашем посте #27,которые по вашим словам диодом мигали. Т.Е. ваш мастер посылает правильные пакеты. Ищите где вы не правильно соеденили мастер и слэйв. И обратите внимание на пост #32. Программа покажет правильно ли работает мастер. И напоминаю. Этими пакетами можно только записывать данные в слэйв. Прочитать можно командой 3. 

James
Offline
Зарегистрирован: 26.02.2016

nik182 пишет:
Это список команд, которые понимает библиотека. Какое отношение они имеют к регистрам? Откройте хотя бы вики и прочитайте про регистры и команды.

nik182 пишет:

Я не делал на слейве ничего. Это библиотека. Для неё нет понятия Input регистр. У неё есть ячейки памяти в которые можно писать и которые можно читать. Если бы я писал слейва и мне нужно было бы ограничить запись в эти ячейки, я бы это сделал. 


блин мне просто интересно, насколько коротка твоя кратковременная память

James
Offline
Зарегистрирован: 26.02.2016

Baks, попробуй masterOPC universal modbus server. довольна просто и бесплатна до 32-х тегов 
у тебя скорость стоит какая на дуйне 19200? линии а и в не перепутаны?

nik182
Offline
Зарегистрирован: 04.05.2015

James пишет:

блин мне просто интересно, насколько коротка твоя кратковременная память

Извини, но я не понял твоего сарказма. 

Ты привел список команд библиотеки https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino.

Да,там есть команды для чтения и записи разных регистров. Если бы мы ощались с каким нибудь конкретным устройством, где были определены регистры, в которые нельзя писать или читать, то нужно было бы искользовать соответствующие команды. Но мы общаемся с ардуиной, в которую загружена эта библиотека. В данной библиотеке определён массив регистров в виде массива ячеек памяти. Эти ячейки можно писать и читать любой из приведённых команд. В момент написания слейва пользователь определяет сколько ячеек использовать и под какие нужды. Кроме того в библиотеке есть возможность отделить coil от holdind регистров. Но в приведённых в топике примерах эта возможножность ни разу не использована. Что не так?     

James
Offline
Зарегистрирован: 26.02.2016

Вот теперь нормальный, понятный ответ. Просто по неполным фразам может сложится неправильное мнение. Все так

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

и снова привет колегам, чето меня засада с непониманием причины НЕ работы модбуса по рс485 уже достала, хоть бросай и на чтото другое  переходи

вот что получается мастер и если убрать делай из loop то очень быстро проходит передача и на слейве моргает 13 пином, а в ответ от слейва посылаю тоже значение мастеру для 13 пина, но фигвам, не хочет работать, и что и как проверить не знаю... кто в курсе дайте совет

#include <ModbusRtu.h>
#define TXEN 4
// data array for modbus network sharing
uint16_t au16data[16];
uint8_t u8state;
int pin = 13;
int raz = 0;
volatile int state = LOW;

/**
    Modbus object declaration
    u8id : node id = 0 for master, = 1..247 for slave
    u8serno : serial port (use 0 for Serial)
    u8txenpin : 0 for RS-232 and USB-FTDI
                 or any pin number > 1 for RS-485
*/
Modbus master(0, 0, TXEN); // this is master and RS-232 or USB-FTDI

/**
   This is an structe which contains a query to an slave device
*/
modbus_t telegram;

unsigned long u32wait;

void setup() {
  master.begin( 19200 ); // baud-rate at 19200
  master.setTimeOut( 2000 ); // if there is no answer in 2000 ms, roll over
  u32wait = millis() + 5000;
  u8state = 0;
  pinMode(pin, OUTPUT);
  pinMode(TXEN, OUTPUT);
}

void loop() {
    delay(300);
  switch ( u8state ) {
    case 0:
      if (millis() > u32wait) {
        u8state++; // wait state
       // digitalWrite(pin, au16data[3]);
      //}
  }
  break;
case 1:
  telegram.u8id = 1; // slave address
  telegram.u8fct = 6; // function code (this one is registers read)
  telegram.u16RegAdd = 1; // start address in slave
  telegram.u16CoilsNo = 1; // number of elements (coils or registers) to read
  telegram.au16reg = au16data  ; // pointer to a memory array in the Arduino
  au16data[0] = random(2);
  //au16data[1] = 0;
  //au16data[2] = 0;
  //au16data[3] = 0;
 // au16data[4] = 0;
  master.query( telegram ); // send query (only once)
  u8state++;
  break;
case 2:
  master.poll(); // check incoming messages
  if (master.getState() == COM_IDLE) {
    u8state = 0;
    u32wait = millis() + 100;

    raz = au16data[3];
    if ( raz == 0) state = LOW; else state = HIGH;
    digitalWrite(pin, state);


    //  for (int i=0; i < raz; i++){
    //   analogWrite(pin, 1);
    //   delay(100);
    //  analogWrite(pin, 0);
    //   delay(100);
    // }
  }
  break;
}
 }
/**
 *  Modbus slave example 1:
 *  The purpose of this example is to link a data array
 *  from the Arduino to an external device.
 *
 *  Recommended Modbus Master: QModbus
 *  <a href="<a href="http://qmodbus.sourceforge.net/" rel="nofollow">http://qmodbus.sourceforge.net/</a>" rel="nofollow"><a href="http://qmodbus.sourceforge.net/" rel="nofollow">http://qmodbus.sourceforge.net/</a></a>
 */
 #include <Arduino.h>
#include <ModbusRtu.h>

#define TXEN 4
int pin = 13;
volatile int state = LOW;

// data array for modbus network sharing
//  uint16_t au16data[16] = {
// 3, 1415, 9265, 4, 2, 7182, 28182, 8, 0, 0, 0, 0, 0, 0, 1, -1 };
  uint16_t au16data[16]; 

/**
 *  Modbus object declaration
 *  u8id : node id = 0 for master, = 1..247 for slave
 *  u8serno : serial port (use 0 for Serial)
 *  u8txenpin : 0 for RS-232 and USB-FTDI 
 *               or any pin number > 1 for RS-485
 */
Modbus slave(1,0,TXEN); // this is slave @1 and RS-232 or USB-FTDI

void setup() {
  slave.begin( 19200 ); // baud-rate at 19200
  pinMode(pin, OUTPUT);
  pinMode(TXEN, OUTPUT);


}


int vP1 = 0;
int8_t packet = 0;
//void loop() {
 // au16data[0]=analogRead(A0);
 // slave.poll( au16data, 16 );
 // if(au16data[0]==0) state = LOW; else state= HIGH;
 // digitalWrite(pin, state);
//}
void loop() {
	//au16data[0]=analogRead(A0);
	packet = slave.poll( au16data, 16 );
	/**
	*если пришел правeльный пакет  то ответ будет больше 4
	* int8_t packet = 0;
	*/
	if (packet > 4) {
		vP1 = au16data[1];
		if( vP1 ==0) state = LOW; else state= HIGH;
		digitalWrite(pin, state);
		//au16data[0] = 3;
		//au16data[1] = 3;
		//au16data[2] = 3;
		// au16data[3] = 3;
		  //au16data[1] = 1;
		  au16data[2] =  random(2);
		  au16data[3] =  random(2);
		  au16data[4] =  random(2);
		   //  Serial.println(  '1' );
	//	  Serial.println( au16data[5],DEC );
 
 }	
}

слейв

и скрин с терминала

 https://drive.google.com/file/d/0Bw55nc23As-3VGRxR21yZ2tXNlU/view?usp=sharing

https://drive.google.com/file/d/0Bw55nc23As-3OG82QnloQ21iSWc/view?usp=sharing

nik182
Offline
Зарегистрирован: 04.05.2015

Я вам уже несколько раз сказал. Слейв ничего не может послать мастеру в ответ на ваш код. У вас в коде нет запроса мастера на посылку ему данных. Сам слейв без запроса данные не посылает. Измените код. Или вы ждёте, что его напишут за вас?

James
Offline
Зарегистрирован: 26.02.2016
#include <ModbusRtu.h>

uint16_t au16data[16]; //!< data array for modbus network sharing
uint8_t u8state; //!< machine state
uint8_t u8query; //!< pointer to message query

/**
 *  Modbus object declaration
 *  u8id : node id = 0 for master, = 1..247 for slave
 *  u8serno : serial port (use 0 for Serial)
 *  u8txenpin : 0 for RS-232 and USB-FTDI 
 *               or any pin number > 1 for RS-485
 */
Modbus master(0,0,0); // this is master and RS-232 or USB-FTDI

/**
 * This is an structe which contains a query to an slave device
 */
modbus_t telegram[2];

unsigned long u32wait;

void setup() {
  // telegram 0: read registers
  telegram[0].u8id = 1; // slave address
  telegram[0].u8fct = 3; // function code (this one is registers read)
  telegram[0].u16RegAdd = 0; // start address in slave
  telegram[0].u16CoilsNo = 4; // number of elements (coils or registers) to read
  telegram[0].au16reg = au16data; // pointer to a memory array in the Arduino

  // telegram 1: write a single register
  telegram[1].u8id = 1; // slave address
  telegram[1].u8fct = 6; // function code (this one is write a single register)
  telegram[1].u16RegAdd = 4; // start address in slave
  telegram[1].u16CoilsNo = 1; // number of elements (coils or registers) to read
  telegram[1].au16reg = au16data+4; // pointer to a memory array in the Arduino
	
  master.begin( 19200 ); // baud-rate at 19200
  master.setTimeOut( 5000 ); // if there is no answer in 5000 ms, roll over
  u32wait = millis() + 1000;
  u8state = u8query = 0; 
}

void loop() {
  switch( u8state ) {
  case 0: 
    if (millis() > u32wait) u8state++; // wait state
    break;
  case 1: 
    master.query( telegram[u8query] ); // send query (only once)
    u8state++;
	u8query++;
	if (u8query > 2) u8query = 0;
    break;
  case 2:
    master.poll(); // check incoming messages
    if (master.getState() == COM_IDLE) {
      u8state = 0;
      u32wait = millis() + 1000; 
    }
    break;
  }

  au16data[4] = analogRead( 0 );
  
}

попробуй этот

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

nik182 пишет:
Я вам уже несколько раз сказал. Слейв ничего не может послать мастеру в ответ на ваш код. У вас в коде нет запроса мастера на посылку ему данных. Сам слейв без запроса данные не посылает. Измените код. Или вы ждёте, что его напишут за вас?

Спасибо за наводку, но  где можно посмотреть пример запроса мастера на посылку ему данных ?

    master.poll(); // check incoming messages
    if (master.getState() == COM_IDLE) {  // если ответ от слейва пришел ...
      u8state = 0;
      u32wait = millis() + 100; 
    }

 * This method checks if there is any incoming answer if pending.
 * If there is no answer, it would change Master state to COM_IDLE.
 * This method must be called only at loop section.

или попробовать заменить 

 COM_IDLE на COM_WAITING ?

James спасибо у меня то же самое

James
Offline
Зарегистрирован: 26.02.2016

нет не тоже самое, попробуй со стандартным

James
Offline
Зарегистрирован: 26.02.2016

в своем коде, ты пытаешься прочитать 1 регистр, но в слейве он закомментирован 

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

Вот в том то и прикол что слейв работает, моргает 13 пином, а мастер нет,.

Вечером обязательно попробую

nik182
Offline
Зарегистрирован: 04.05.2015

Телеграммы нужно посылать отдельно друг от друга. Послали первую телеграмму - дождались ответа, проверили что ошибки нет - посылаем вторую и тоже ждем ответа. Попробуйте предыдущий код удвоить и посылать телеграммы с кодами 3 и 6 или по времени - раз в 2 секунды, или по нажатию разных клавишь. Всё заработает.

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

что вот это значить +4?

 telegram[1].au16reg = au16data+4; // pointer to a memory array in the Arduino

если я правильно понял то это увеличиваем пакет для передачи?

nik182
Offline
Зарегистрирован: 04.05.2015

Присвоение адреса первого регистра MODBUS третьему элементу объявленного предварительно массива. Ответ слейва будет писаться с этого элемента массива. На пакет передачи такое присвоение ни как не влияет.
Скажите, где вы такую хрень берёте? В стандартных примерах библиотеки такого нет.

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

взял чуть выше #85 я не понял что это такое, поээтомуу и спросил,

а теперь по вашим рекомендациям 

задержка между отправками пакетов и ожидание ответа не помогла

зато я теперь точно знаю что когда выполняется условие  if (master.getState() == COM_IDLE ) { то мастер получает ответ от слейва, в моем случае это давольно быстро происходит

с кодами 3 не работает, с 6  работает на слейве а мастер ответ не читает, telegram[1].u16CoilsNo = 1; // number of elements (coils or registers) to read тут на 16 изменил

немного подовнял настройку пакета  start address in slave но толку нет

       telegram.u8id = 1; // slave address
      telegram.u8fct = 6; // function code (this one is registers read)
      telegram.u16RegAdd = 0; // start address in slave
      telegram.u16CoilsNo = 16; // читать количество  элементов number of elements (coils or registers) to read
      telegram.au16reg = au16data  ; // pointer to a memory array in the Arduino

 

nik182
Offline
Зарегистрирован: 04.05.2015

Можете описать, что вы хотите сделать? Я уже потерялся в ваших хотелках. Коды программ совершенно не соответствуют тому, что вы описываете.

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

нужно от мастера послать пакет слейву с 1 или 2 значения. Эта часть получилась и значение считывается в слейве.

вторая часть задачи это послать ответный пакет от слейва к мастеру в котором будет к примеру 10 значений.  и прочитать их на мастере. - это не выходит.

на данный мамент из мастера включаю и выключаю 13 пин на слейве, а из слейва не могу включить 13 пин мастеру ответ от слейва доходит до мастера проверял так 

      if (master.getState() == COM_IDLE ) {
        // digitalWrite(pin, HIGH); // при получении ответного пакета пин 13 включается

мастер 

#include <ModbusRtu.h>
#define TXEN 4
// data array for modbus network sharing
uint16_t au16data[16];
uint8_t u8state;
int speedSend = 300;//ms между отправками
int pin = 13;
int raz = 0;
volatile int state = LOW;

/**
    Modbus object declaration
    u8id : node id = 0 for master, = 1..247 for slave
    u8serno : serial port (use 0 for Serial)
    u8txenpin : 0 for RS-232 and USB-FTDI
                 or any pin number > 1 for RS-485
*/
Modbus master(0, 0, TXEN); // this is master and RS-232 or USB-FTDI

/**
   This is an structe which contains a query to an slave device
*/
modbus_t telegram;

unsigned long u32wait;

void setup() {
  master.begin( 19200 ); // baud-rate at 19200
  master.setTimeOut( 2000 ); // if there is no answer in 2000 ms, roll over
  u32wait = millis() + 5000;
  u8state = 0;
  pinMode(pin, OUTPUT);
  pinMode(TXEN, OUTPUT);

       telegram.u8id = 1; // slave address
      telegram.u8fct = 6; // function code (this one is registers read)
      telegram.u16RegAdd = 0; // start address in slave
      telegram.u16CoilsNo = 16; // читать количество  элементов number of elements (coils or registers) to read
      telegram.au16reg = au16data  ; // pointer to a memory array in the Arduino
  
}

void loop() {
  //  delay(300);
  switch ( u8state ) {
    case 0:
      if (millis() > u32wait) {
        u8state++; // wait state
      }
      break;
    case 1:
    
      au16data[0] = random(2);

      master.query( telegram ); // send query (only once)
      u8state++;
      break;

    case 2:
      master.poll(); // check incoming messages
      if (master.getState() == COM_IDLE ) {
        // digitalWrite(pin, HIGH); // при получении ответного пакета пин 13 включается
        u8state = 0;
        u32wait = millis() + speedSend;

        raz = au16data[3];// пытаюсь прочитать ответ от слейва
        if ( raz == 0) state = LOW ; else state = HIGH;
        digitalWrite(pin, state);// если что то больше 0 то включить 13 пин

        //  for (int i=0; i < raz; i++){ 
        //   analogWrite(pin, 1);
        //   delay(100);
        //  analogWrite(pin, 0);
        //   delay(100);
        // }
      }
      break;
  }
} 

слейв 


 #include <Arduino.h>
#include <ModbusRtu.h>

#define TXEN 4
int pin = 13;
volatile int state = LOW;

// data array for modbus network sharing
 // uint16_t au16data[16] = {
// 6, 1415, 9265, 4, 2, 7182, 28182, 8, 0, 0, 0, 0, 0, 0, 1, -1 };
  uint16_t au16data[16]; 

/**
 *  Modbus object declaration
 *  u8id : node id = 0 for master, = 1..247 for slave
 *  u8serno : serial port (use 0 for Serial)
 *  u8txenpin : 0 for RS-232 and USB-FTDI 
 *               or any pin number > 1 for RS-485
 */
Modbus slave(1,0,TXEN); // this is slave @1 and RS-232 or USB-FTDI

void setup() {
  slave.begin( 19200 ); // baud-rate at 19200
  pinMode(pin, OUTPUT);
  pinMode(TXEN, OUTPUT);
}

int vP1 = 0;
int8_t packet = 0;
//void loop() {
 // au16data[0]=analogRead(A0);
 // slave.poll( au16data, 16 );
 // if(au16data[0]==0) state = LOW; else state= HIGH;
 // digitalWrite(pin, state);
//}
void loop() {
	//au16data[0]=analogRead(A0);
	packet = slave.poll( au16data, 16 );
	/**
	*если пришел правeльный пакет  то ответ будет больше 4
	* int8_t packet = 0;
	*/
	if (packet > 4) {
		vP1 = au16data[0];
		if( vP1 ==0) state = LOW; else state= HIGH;
		digitalWrite(pin, state);
		// заполним все регисты числами больше 0 чтобы включить на мастере 13 пин
		  au16data[1] = 4;
		  au16data[2] = 4; // random(2);
		  au16data[3] = 4; // random(2);
		  au16data[4] = 4;
		  au16data[5] = 4;
		  au16data[6] = 4;
		  au16data[7] = 4;
		  au16data[8] = 4;
		  au16data[9] = 4;
		  au16data[10] = 1;
		  au16data[11] = 1;
		  au16data[12] = 1;
		  au16data[13] = 1;
		  au16data[14] = 1;
		  au16data[15] = 1;
		  au16data[16] = 1;
 }	
}

 

nik182
Offline
Зарегистрирован: 04.05.2015

 

Вот чуть чуть модифицированный код мастера под ваш слэйв(рандом на четвёртую ячейку в слэйве вернуть надо. И уберите  au16data[16] = 1; такой ячейки не существует, а запись в неё может портить программу). У меня не начем проверить. Работает ли не знаю, но думаю где-то так. 

/**
 *  Modbus master example 2:
 *  The purpose of this example is to query several sets of data
 *  from an external Modbus slave device. 
 *  The link media can be USB or RS232.
 *
 *  Recommended Modbus slave: 
 *  diagslave <a data-cke-saved-href="http://www.modbusdriver.com/diagslave.html" href="http://www.modbusdriver.com/diagslave.html" rel="nofollow">http://www.modbusdriver.com/diagslave.html</a>
 *
 *  In a Linux box, run 
 *  "./diagslave /dev/ttyUSB0 -b 19200 -d 8 -s 1 -p none -m rtu -a 1"
 * 	This is:
 * 		serial port /dev/ttyUSB0 at 19200 baud 8N1
 *		RTU mode and address @1
 */

#include <ModbusRtu.h>

uint16_t au16data[16]; //!< data array for modbus network sharing
uint8_t u8state; //!< machine state
uint8_t u8query; //!< pointer to message query

/**
 *  Modbus object declaration
 *  u8id : node id = 0 for master, = 1..247 for slave
 *  u8serno : serial port (use 0 for Serial)
 *  u8txenpin : 0 for RS-232 and USB-FTDI 
 *               or any pin number > 1 for RS-485
 */
Modbus master(0,0,TXEN); // this is master and RS-232 or USB-FTDI

/**
 * This is an structe which contains a query to an slave device
 */
modbus_t telegram[2];

unsigned long u32wait;

int pin = 13;
int raz = 0;
int state = LOW;
#define TXEN 4


void setup() {
  // telegram 0: read registers
  telegram[0].u8id = 1; // slave address
  telegram[0].u8fct = 3; // function code (this one is registers read)
  telegram[0].u16RegAdd = 0; // start address in slave
  telegram[0].u16CoilsNo = 16; // number of elements (coils or registers) to read
  telegram[0].au16reg = au16data; // pointer to a memory array in the Arduino

  // telegram 1: write a single register
  telegram[1].u8id = 1; // slave address
  telegram[1].u8fct = 6; // function code (this one is write a single register)
  telegram[1].u16RegAdd = 0; // start address in slave
  telegram[1].u16CoilsNo = 1; // number of elements (coils or registers) to read
  telegram[1].au16reg = au16data; // pointer to a memory array in the Arduino
	
  master.begin( 19200 ); // baud-rate at 19200
  master.setTimeOut( 5000 ); // if there is no answer in 5000 ms, roll over
  u32wait = millis() + 1000;
  u8state = u8query = 0; 
}

void loop() {
  switch( u8state ) {
  case 0: 
    if (millis() > u32wait) u8state++; // wait state
    break;
  case 1: 
    master.query( telegram[u8query] ); // send query (only once)
    u8state++;
	u8query++;
	if (u8query > 2) u8query = 0;
    break;
  case 2:
    master.poll(); // check incoming messages
    if (master.getState() == COM_IDLE) {
      u8state = 0;
      u32wait = millis() + 1000; 
    }
    break;
  }

 au16data[0] = random(2);
       
 raz = au16data[3];// пытаюсь прочитать ответ от слейва
 if ( raz == 0) state = LOW ; else state = HIGH;
 digitalWrite(pin, state);// если что то больше 0 то включить 13 пин
  
}
 

 

nik182
Offline
Зарегистрирован: 04.05.2015

Вогнал код в нану и запустил diagslave, тот что по ссылке из шапки скетча. Вот вывод

Microsoft Windows [Version 10.0.14393]
(c) Корпорация Майкрософт (Microsoft Corporation), 2016. Все права защищены.
 
c:\Users\Toshiba\Documents\Arduino\libraries\MODBUSRTU\examples\win32>diagslave -m rtu -a 1 -b 19200 -p none COM7
diagslave 2.12 - FieldTalk(tm) Modbus(R) Diagnostic Slave Simulator
Copyright (c) 2002-2012 proconX Pty Ltd
Visit http://www.modbusdriver.com for Modbus libraries and tools.
 
Protocol configuration: Modbus RTU
Slave configuration: address = 1, master activity t/o = 3.00
Serial port configuration: COM7, 19200, 8, 1, none
 
Server started up successfully.
Listening to network (Ctrl-C to stop)
Slave   1: readHoldingRegisters from 1, 16 references
Slave   1: writeHoldingRegisters from 1, 1 references
Slave   1: readHoldingRegisters from 1, 16 references
Slave   1: writeHoldingRegisters from 1, 1 references
Slave   1: readHoldingRegisters from 1, 16 references
Slave   1: writeHoldingRegisters from 1, 1 references
Slave   1: readHoldingRegisters from 1, 16 references
Slave   1: writeHoldingRegisters from 1, 1 references
..
Как видите регулярно читает 16 регистров и пишет 1 регистр. Т.Е. работает.
James
Offline
Зарегистрирован: 26.02.2016
telegram[1].au16reg = au16data+4; // pointer to a memory array in the Arduino

я это не писал, что за +4?

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

ничего себе, как же я не замтил вот таких строк // telegram 0: read registers,  // telegram 1: write a single register

Чувствую 5 точкой что зработает как надо

nik182 спасибо за Вашу помощ!

 

nik182
Offline
Зарегистрирован: 04.05.2015

James пишет:

telegram[1].au16reg = au16data+4; // pointer to a memory array in the Arduino

я это не писал, что за +4?

Это обращение к третей ячейке MODBUS. По другому это можно записать так ...=&au16data[2]. Так действуют, когда надо отправить слейву не первую ( au16data[0] ) ячейку памяти.