Работа с вакуумметром ВМЦ по ModBus

RizONE
Offline
Зарегистрирован: 22.03.2018

Доброе!

Необходимо получать данные о давлении с вакуумметра ВМЦ (http://e-beam.ru/production/measurement/vmd). Из формуляра следует, что давление считывается из регистров входа 1000 и 1001 в формате float. Формат данных CDAB.

накидал обычный скетч

#include <ModbusRtu.h>

uint16_t au16data[32]; //читаем сразу 2 регистра
uint8_t u8state;

Modbus master(0,0,0);

modbus_t telegram[2];

unsigned long u32wait;

void setup() {
  master.begin(19200);
  master.setTimeOut(2000);
  u32wait = millis() + 1000;
  u8state = 0; 
}

void loop() {
  switch(u8state) {
  case 0: 
    if (millis() > u32wait) u8state++;
    break;
  case 1: 
    telegram[0].u8id = 10; // slave address
    telegram[0].u8fct = 4; // function code (this one is registers read)
    telegram[0].u16RegAdd = 1000; // start address in slave
    telegram[0].u16CoilsNo = 2; // читаем 2 регистра
    telegram[0].au16reg = au16data; // pointer to a memory array in the Arduino

    master.query(telegram[0]);
    u8state++;
    break;
  case 2:
    master.poll(); // check incoming messages
    if (master.getState() == COM_IDLE) {
      u8state = 0;
      u32wait = millis() + 1000; 
    }
    break;
  }
}

Есть несколько вопросов

1) правильно ли я указал uint16_t au16data[32]; Читаем то 2 регистра сразу

2) как получить из au16data[32] данные в нормальном виде учитывая, что данные нам вернули в формате CDAB?

3) Из того же формуляра следует, что перед измерениями необходимо записать 1 в регистр флагов 1000, правилен ли следующий код?

telegram[1].u8id = 10; // slave address
    telegram[1].u8fct = 15; // function code (this one is registers read)
    telegram[1].u16RegAdd = 1000; // start address in slave
    telegram[1].u16CoilsNo = 1;
    telegram[1].au16reg = 1; // pointer to a memory array in the Arduino

    master.query(telegram[1]);

т.е. строка telegram[1].au16reg = 1; немного смущает

RizONE
Offline
Зарегистрирован: 22.03.2018

uni пишет:

Тип float занимает 4 байта или 2 слова, т.е. 2 регистра modbus. Бывает прямой и обратный (инверсный) float. У инверсного регистры имеют обратный порядок.
Чтобы получить значение во float, нужно сохранить в памяти оба регистра modbus (они должны находиться рядом), далее нужно получить указатель на первый и них, затем преобразовать его в указатель на float и разыменовать его. Это один из возможных способов. Есть и другие варианты.

был бы благодарен за код т.к. сам я этого в ближайшее время не накидаю

RizONE
Offline
Зарегистрирован: 22.03.2018

Dr_grizzly пишет:

Могу ошибиться, но вроде мы обсуждали подобное в этом топике http://arduino.ru/forum/proekty/modbusrtu-modbustcp-arduino-i-owen-plc?page=1#comment-237810

там на посте #58 вопрос аналогичный встает, а в #59 снимается настройками ПЛК. так что собственно ответа на мой вопрос №2 я там не нашел (

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015
union Data
{
    struct REG
    {
        uint16_t LOWORD;
        uint16_t HIWORD;
    } reg;

    float fvalue;
};

Data data;

// 1.0f = 0x3f800000
data.reg.HIWORD = 0x3f80;
data.reg.LOWORD = 0x0000;

printf( "%f", data.fvalue );

 

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

RizONE пишет:

3) Из того же формуляра следует, что перед измерениями необходимо записать 1 в регистр флагов 1000, правилен ли следующий код?

telegram[1].u8id = 10; // slave address
    telegram[1].u8fct = 15; // function code (this one is registers read)
    telegram[1].u16RegAdd = 1000; // start address in slave
    telegram[1].u16CoilsNo = 1;
    telegram[1].au16reg = 1; // pointer to a memory array in the Arduino

    master.query(telegram[1]);

т.е. строка telegram[1].au16reg = 1; немного смущает


Нет, код не правильный. telegram[1].au16reg - это указатель на область памяти, т.е. на буфер (массив), где и содержится передаваемое значение 1.

RizONE
Offline
Зарегистрирован: 22.03.2018

Спасибо!

Переделал так:

#include <ModbusRtu.h>

uint16_t au16data[16];
uint8_t u8state;
int flag[] = {1};
union Data
{
    struct REG
    {
        uint16_t LOWORD;
        uint16_t HIWORD;
    } reg;

    float fvalue;
};

Data data;

Modbus master(0,0,0);

modbus_t telegram;

unsigned long u32wait;

void setup() {
  master.begin(19200);
  master.setTimeOut(2000);
  u32wait = millis() + 1000;
  u8state = 0; 
}

void loop() {
  switch(u8state) {
  case 0: 
    if (millis() > u32wait) u8state++;
    break;
  case 1:
    telegram.u8id = 10;
    telegram.u8fct = 15;
    telegram.u16RegAdd = 1000;
    telegram.u16CoilsNo = 1;
    telegram.au16reg = flag;

    master.query(telegram);
    
    telegram.u8id = 10;
    telegram.u8fct = 4;
    telegram.u16RegAdd = 1000;
    telegram.u16CoilsNo = 1;
    telegram.au16reg = au16data;

    master.query(telegram);
    data.reg.HIWORD = au16data;

    telegram.u8id = 10;
    telegram.u8fct = 4;
    telegram.u16RegAdd = 1001;
    telegram.u16CoilsNo = 1;
    telegram.au16reg = au16data;

    master.query(telegram);
    data.reg.LOWORD = au16data;
    
    u8state++;
    break;
  case 2:
    master.poll(); // check incoming messages
    if (master.getState() == COM_IDLE) {
      u8state = 0;
      u32wait = millis() + 1000;
      Serial.printf( "%f", data.fvalue ); 
    }
    break;
  }
}

 

RizONE
Offline
Зарегистрирован: 22.03.2018

Немного доработал

#include <ModbusRtu.h>
#include <LiquidCrystal.h>

uint16_t au16data[16];
uint8_t u8state;
uint8_t flag = 1;
//uint8_t flag[] = {1};
union Data
{
    struct REG
    {
        uint16_t LOWORD;
        uint16_t HIWORD;
    } reg;

    float fvalue;
};

Data data;

Modbus master(0,0,0);
modbus_t telegram;
unsigned long u32wait;
const int rs = 7, en = 6, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
const int buttonPin = 8;// номер входа, подключенный к кнопке
const int ledPin = 12;// номер входа, подключенный к светодиоду
boolean HighState = false;

void setup() {
  master.begin(19200);
  master.setTimeOut(2000);
  u32wait = millis() + 1000;
  u8state = 0; 
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Pressure: OFF");
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
}

void loop() {
  if (!HighState) {
    if (digitalRead(buttonPin) == HIGH) {   
      telegram.u8id = 10;
      telegram.u8fct = 15;
      telegram.u16RegAdd = 1000;
      telegram.u16CoilsNo = 1;
      telegram.au16reg = flag;
  
      master.query(telegram);
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Pressure: ON");
      digitalWrite(ledPin, HIGH);
      HighState = true;
    }
}
  switch(u8state) {
  case 0: 
    if (millis() > u32wait) u8state++;
    break;
  case 1:
    lcd.setCursor(0, 1);
    lcd.print("SQ...");
    telegram.u8id = 10;
    telegram.u8fct = 4;
    telegram.u16RegAdd = 1000;
    telegram.u16CoilsNo = 1;
    telegram.au16reg = au16data;

    master.query(telegram);
    data.reg.HIWORD = au16data;

    telegram.u8id = 10;
    telegram.u8fct = 4;
    telegram.u16RegAdd = 1001;
    telegram.u16CoilsNo = 1;
    telegram.au16reg = au16data;

    master.query(telegram);
    data.reg.LOWORD = au16data;
    
    u8state++;
    break;
  case 2:
    master.poll(); // check incoming messages
    if (master.getState() == COM_IDLE) {
      u8state = 0;
      u32wait = millis() + 1000;
      lcd.setCursor(0, 1);
      lcd.print(data.fvalue);
    }
    break;
  }
}

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

RizONE
Offline
Зарегистрирован: 22.03.2018

Доброе

Просьба подсказать, что не так в части

uint8_t flag = 1;
//uint8_t flag[] = {1};
...

telegram.u8id = 10;
telegram.u8fct = 15;
telegram.u16RegAdd = 1000;
telegram.u16CoilsNo = 1;
telegram.au16reg = flag;
master.query(telegram);

пробовал передать и uint16_t flag[] = {1}; - результат один: светодиод загорается, но ВМЦ не видит переданные данные

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Нужно убедиться, что операция прошла успешно.

Описание протокола Modbus RTU.

 

RizONE
Offline
Зарегистрирован: 22.03.2018

uni пишет:

Нужно убедиться, что операция прошла успешно.

Вы про ответ на запрос записи и/или возврат кода ошибки?

Будет ли (сразу позле запроса на запись) чтение состояния соответсвующего флага регистров являться этим самым ответом? Просто я никде не встречался с функциями чтения ответа и/или получения ошибки данной библиотеки.

PS. Про ответ от слейва нашел ))

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

> Вы про ответ на запрос записи и/или возврат кода ошибки?

Я про ответ на запрос. Что отвечает прибор. У вас бы не возникало вопросов, если посмотреть на ответ. Лучше всего купить переходник USB-RS485 и посмотреть что происходит на линии.

Вот более полное описание протокола: Modbus_Application_Protocol_V1_1b3.pdf

 

RizONE
Offline
Зарегистрирован: 22.03.2018

uni пишет:

У вас бы не возникало вопросов, если посмотреть на ответ. Лучше всего купить переходник USB-RS485 и посмотреть что происходит на линии.

заказал, уже вылетело с китая...

за ссылки спасибо

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

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Вы хорошо даташит читали ?
Мне почему то там написали, что данные нужно читать по адресу 1004....

RizONE
Offline
Зарегистрирован: 22.03.2018

brokly пишет:

Вы хорошо даташит читали ?
Мне почему то там написали, что данные нужно читать по адресу 1004....

Даташит чего/кого? Если Вы про вакуумметр, то с ним идет формуляр, на странице 7 "Протокол обмена" где ясно сказано откуда читать.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Ясно..

http://e-beam.ru/images/stories/VTRD/vtrd.pdf

Это другой документ ?

RizONE
Offline
Зарегистрирован: 22.03.2018

Увас там ВТРЦ, я про ВМЦ

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Ссылка на формуляр есть ?

Нашел. Там действительно 1000. Все правильно.

Не очень понятно что вы делаете, но нужно так 

uint16_t flag = 1;
...

telegram.u8id = 10;
telegram.u8fct = 15;
telegram.u16RegAdd = 1000;
telegram.u16CoilsNo = 1;
telegram.au16reg = &flag;
master.query(telegram);

 

RizONE
Offline
Зарегистрирован: 22.03.2018

По поводу ответа:

получается так, я шлю для записи 10 0F E8 03 01 00 01 01 00 CRC - ID 10, запись, адресс 1000, 1 флаг,  пишу 1 бит

в ответ при удаче должен получить 10 0F E8 03 01 00 CRC

а в случае неудачи 10 8F Код_ошибки CRC

RizONE
Offline
Зарегистрирован: 22.03.2018

brokly пишет:

Не очень понятно что вы делаете, но нужно так 

пытаюсь передить 1 бит для записи )))

Спасибо за код, попробую

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

RizONE пишет:

По поводу ответа:

получается так, я шлю для записи 10 0F E8 03 01 00 01 01 00 CRC - ID 10, запись, адресс 1000, 1 флаг,  пишу 1 бит

в ответ при удаче должен получить 10 0F E8 03 01 00 CRC

а в случае неудачи 10 8F Код_ошибки CRC

А что получаете в реале ?

 

RizONE
Offline
Зарегистрирован: 22.03.2018

завтра только смогу ответить

RizONE
Offline
Зарегистрирован: 22.03.2018

brokly пишет:

... но нужно так 

uint16_t flag = 1;
...

telegram.u8id = 10;
telegram.u8fct = 15;
telegram.u16RegAdd = 1000;
telegram.u16CoilsNo = 1;
telegram.au16reg = &flag;
master.query(telegram);

наскоком ничего не вышло ((( запись не прошла. нарыл вот такую вещь https://intenso.name/index.php/icpdas/248-i7561

завтра попробую им прочитать/записать.

Возможно у меня ошибка в схеме?

Собрано все так:

Выход Data(+) ВМЦ подключен ко входу А, выход Data(-) к В

RizONE
Offline
Зарегистрирован: 22.03.2018

Косяк, возможно, еще и в строке

Modbus master(0,0,0);

видимо надо

Modbus master(0,0,10);

 

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

RizONE пишет:

Косяк, возможно, еще и в строке

Modbus master(0,0,0);

видимо надо

Modbus master(0,0,10);

Надо, очень надо.

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Если у Вас есть Proteus, то можно отладить работу схемы виртуально.

Для этого нужен набор ПО: 

- Eltima Software Serial Port Monitor (видит обмен на последовательной линии);
- com0com или 2 реальных COM порта, соединённых нуль-модемным кабелем;
- Modbus PLC Simulator или Modbus Slave (Witte Software).

Всё искать в сети самостоятельно. В Proteus есть компонент COMPIN, который позволяет делать вывод Rx/Tx на реальный последовательный порт. Нужна программа-симулятор salve устройства, второй порт и нуль-модемный кабель.

В принципе, чтобы проверить только передачу, я думаю достаточно одного Serial Port Monitor, в котором просто слушать передающий порт. Там хоть пакет увидите, который формируется.

Отладка Modbus RTU протокола - штука, требующая дополнительные программные/аппаратные средства и время.

Кстати, сам Proteus тоже имеет "осциллограф", на котором можно посмотреть что на выходе мк происходит. Нужно только знать как работает UART, чтобы декодировать передаваемые символы.

RizONE
Offline
Зарегистрирован: 22.03.2018

brokly пишет:

надо, очень надо.

С этой строкой меня товарищ VaDoSiQ из http://arduino.ru/forum/programmirovanie/rabota-s-modbus-rtu знатно потролил: то Modbus master(0,0,0); то Modbus master(0,0,10); потом опять Modbus master(0,0,0); и главное пишет, что код у него работает )))) Совсем запутал. Заполночь гуглил и выяснял.

RizONE
Offline
Зарегистрирован: 22.03.2018

uni пишет:

Если у Вас есть Proteus, то можно отладить работу схемы виртуально.

...

Спасибо за подробный расклад. За Proteus ничего не знаю. Вчера возникла надобность нарисовать схему соединения вот и установил ее. Подкупила красивость картинок в нем. А уж потом посмотрел пару видео про симуляцию. Так что протеус это на потом )

Сегодня попробую погонять запросы с эмулятором Modbus мастер-устройства

RizONE
Offline
Зарегистрирован: 22.03.2018

Ахтунг! Все что знал или пришло в голову перепробовал. QModBus все замечательно передает и принимает, ВМЦ откликается. Но вот скетч даже не читает данные! (((((

#include <ModbusRtu.h>
#include <LiquidCrystal.h>

uint16_t au16data[16];
uint8_t u8state;
uint16_t flag = 1;
//uint16_t flag[] = {1};
union Data
{
  struct REG
  {
    uint16_t LOWORD;
    uint16_t HIWORD;
  } reg;

  float fvalue;
};

Data dataM;

Modbus master(0, 0, 10);
modbus_t telegram;
unsigned long u32wait;
const int rs = 7, en = 6, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
const int buttonPin = 8;// номер входа, подключенный к кнопке
const int ledPin = 12;// номер входа, подключенный к светодиоду
boolean HighState = false;

void setup(void) {
  master.begin(19200);
  master.setTimeOut(2000);
  u32wait = millis() + 1000;
  u8state = 0;
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Pressure: OFF");
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
}

void loop(void) {
  if (!HighState) {
    if (digitalRead(buttonPin) == HIGH) {
      telegram.u8id = 10;
      telegram.u8fct = 15;
      telegram.u16RegAdd = 1000;
      telegram.u16CoilsNo = 1;
      telegram.au16reg = &flag;
      master.query(telegram);
      master.poll(); // check incoming messages
      //if (master.getState() == COM_IDLE) {
      //  lcd.print(flag);
      //}
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Pressure: ON");
      digitalWrite(ledPin, HIGH);
      HighState = true;
    }
  }
  //lcd.setCursor(0, 1);
  //lcd.print(u8state);
  switch (u8state) {
    case 0:
      if (millis() > u32wait) {
        u8state++;        
      }
      break;
    case 1:
      //lcd.setCursor(0, 1);
      //lcd.print("SQ...");
      telegram.u8id = 10;
      telegram.u8fct = 4;
      telegram.u16RegAdd = 1000;
      telegram.u16CoilsNo = 1;
      telegram.au16reg = au16data;
      master.query(telegram);
      master.poll();
      delay(100);
      if (master.getState() == COM_IDLE) {
        dataM.reg.HIWORD = au16data;
      }

      telegram.u8id = 10;
      telegram.u8fct = 4;
      telegram.u16RegAdd = 1001;
      telegram.u16CoilsNo = 1;
      telegram.au16reg = au16data;
      master.query(telegram);
      master.poll();
      delay(100);
      if (master.getState() == COM_IDLE) {
        dataM.reg.LOWORD = au16data;
      }
      u8state = 0;
      u32wait = millis() + 1000;
      lcd.setCursor(0, 1);
      lcd.print(dataM.fvalue);
      break;
  }
}

Что еще проверить?

Можно ли как-нить проверить что возвращает ВМЦ? Смотрел компорт - так там какие-то кубики идут, видимо библиотека модбаса туда что-то шлет

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Я писал, что посмотреть можно при помощи Serial Port Monitor. Он позволяет прослушивать последовательные соединения на ПК в различном виде.

RizONE
Offline
Зарегистрирован: 22.03.2018

В Termite я вижу, что посылаю правильные запросы, вот ответа там не вижу

Погуглю "Serial Port Monitor", спасибо 

RizONE
Offline
Зарегистрирован: 22.03.2018

Посмотрел, в принципе вижу то же самое что и в Termite т.е. отправляемые запросы, а вот ответы, как в случае с QModBus, не вижу.

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Нужен вид dump только, где показаны непосредственно данные. И выложите ещё раз тестовую программу с указанием откуда взята библиотека modbus.

RizONE
Offline
Зарегистрирован: 22.03.2018

кажет такую картину (что и Термит показывает)

последний вариант скетча чуть выше: #27

а библиотеку брал тут: https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino

RizONE
Offline
Зарегистрирован: 22.03.2018

интересная картинка:

а в библиотеке modbus первой строкой и не пахнет

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

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

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

RizONE пишет:
а в библиотеке modbus первой строкой и не пахнет

Потому что запрашиваете по 1 регистру, а не два сразу.

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Раз у вас есть QModBus, то можно проверить работу на приём для Arduino. Попробуйте написать скетч для режима modbus rtu slave. Библиотека его поддерживает. Нужно поискать простые примеры для slave и протестировать работу преобразователя, подавая запросы с помощью QModBus.

RizONE
Offline
Зарегистрирован: 22.03.2018

uni пишет:

Потому что запрашиваете по 1 регистру, а не два сразу.

Не факт, на чтение 1го регистра откликается так: 

[28/03/2018 18:11:55] Written data (COM7) 

    0a 04 03 e8 00 01 b0 c1                           ...и..°Б         
 

 

RizONE
Offline
Зарегистрирован: 22.03.2018

Отвечу и на последние два вопроса. На двух шилдах проверил следующий код

#include <ModbusRtu.h>

#define TXEN	10 

// 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 };

Modbus slave(1,0,TXEN); // this is slave @1 and RS-485

void setup() {
  slave.begin( 19200 ); // baud-rate at 19200
}

void loop() {
  slave.poll( au16data, 16 );
}

На обоих слейв на ардуинке непрерывно слал пакеты, а QModBus, подключенный к нетбуку их отлавливал. Значит и шилд работает и как слейв вся схема работает.

RizONE
Offline
Зарегистрирован: 22.03.2018

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

У вас какая-то путаница в объяснениях.

> На обоих слейв на ардуинке непрерывно слал пакеты

Слейв не может ничего непрерывно слать, он может только отвечать на запросы и не более того. Slave - это сервер, он находится в режиме ожидания запросов. Хотя картинка с логом приведена правильная.

> Не факт, на чтение 1го регистра откликается так

Это не "отклик", это дамп запроса 1 регистра 4-й функцией с 1000 адреса.

У вас в #33 посту показано окно, в котором указано считывать 2 регистра, а в программе в #27 (и как видно по #32) делает запросы на чтение по одному регистру. Поэтому я и написал, что запросы по форме разные. В одном случае читается 2 регистра с одного адреса, а во втором по одному регистру с разных адресов.

Теперь скачайте программу симулятор Modbus Slave (http://www.plcsimulator.org/) и попробуйте её использовать как slave устройство, делая запросы к нему. Это примерно то же, что и с QModbus, только наоборот. На Arduino запустите свой скетч клиента (мастера), а на ПК симулятор. Покажите дамп обмена в Serial Port Monitor.

RizONE
Offline
Зарегистрирован: 22.03.2018

del

RizONE
Offline
Зарегистрирован: 22.03.2018

uni пишет:

У вас какая-то путаница в объяснениях.

ну, не совсем, просто в процессе поиска решения проблемы и немного эмоцианирую

uni пишет:

> На обоих слейв на ардуинке непрерывно слал пакеты

Слейв не может ничего непрерывно слать, он может только отвечать на запросы и не более того. Slave - это сервер, он находится в режиме ожидания запросов. Хотя картинка с логом приведена правильная.

Согласен и по-этому предлагаю следующую редакцию предложения "На обоих слейв на ардуинке непрерывно слал пакеты в ответ на запросы мастера"

uni пишет:

> Не факт, на чтение 1го регистра откликается так

Это не "отклик", это дамп запроса 1 регистра 4-й функцией с 1000 адреса.

Эту ситуацию я понял так(начиная с поста #33), поправьте если ошибся. Имеем любой модбас мастер и сканер ком порта. Мастер шлет запросы, сканер их отображает. Сейчас не важно есть ответ от слейва или нет. Если даже ответ и есть, то он должен попасть в лог сканера. 1) Шлем запрос от масетра на ардуино - в сканере видим лог Read data 2) Шлем тот же самый запрос от QModBus и в ответ видим в логе того же самого сканера Written data и Read data! Это меня и удивило и потому написал "интересная картина". И делаю вывод, что мастер на ардуино что-то недосылает в порт, видимо по-этому и ВМЦ не отвечает, он просто не получает запросы. А от программного мастера получает и отвечает. И мое "не факт" на до относить к тому, читаю я один или два регистра все равно в порт попадает запись типа Written data. Собственно вопрос теперь: должен ли я видеть в логе сканера записи типа Written data и Read data при отправке запросов от ардуино?

uni пишет:

У вас в #33 посту показано окно, в котором указано считывать 2 регистра, а в программе в #27 (и как видно по #32) делает запросы на чтение по одному регистру. Поэтому я и написал, что запросы по форме разные. В одном случае читается 2 регистра с одного адреса, а во втором по одному регистру с разных адресов.

тут все просто и с Вами я согласен. Я понимаю, что запросы разные и ответы разные...в скетче отдельно запрашиваются по одному регистры 1000 и 1001. QModBus-ом я читал и по одному регистру отдельно и вместе...видимо запутал Вас запостив картинку чтения двух портов сразу.

uni пишет:

Теперь скачайте программу симулятор Modbus Slave (http://www.plcsimulator.org/) и попробуйте её использовать как slave устройство, делая запросы к нему. Это примерно то же, что и с QModbus, только наоборот. На Arduino запустите свой скетч клиента (мастера), а на ПК симулятор. Покажите дамп обмена в Serial Port Monitor.

Спасибо за советы. На день-два выехал в командировку, по возвращении сделаю и отпищусь.

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

> Собственно вопрос теперь: должен ли я видеть в логе сканера записи типа Written data и Read data при отправке запросов от ардуино?

Вообще говоря, Written data и Read data могут не соответствовать фактическим действиям на линии. Это зависит от "режима прослушивания". Я обычно не обращаю внимание на эти подсказки, а разбираю дамп по его содержимому. Зная протокол, всегда понятно где запрос, а где ответ, кроме некоторых частных случаев.

RizONE
Offline
Зарегистрирован: 22.03.2018

uni пишет:

Теперь скачайте программу симулятор Modbus Slave (http://www.plcsimulator.org/) ...

Попробовал...хм...вот, что вижу:

Не совсем понял как работать с программой

1) не нашел окно для указания ID слейва

2) судя по названию используется протокол RS-232, а у меня выход с шилда RS-485

Правда иногда в логе проскакивали записи типа "reading regisr 1001", но стабильно их получать никак не удалось (

RizONE
Offline
Зарегистрирован: 22.03.2018

uni пишет:

симулятор Modbus Slave (http://www.plcsimulator.org/)

так ничего от него и не добился. Вот, этот товарищ показывает наличие обмена:

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

У меня такие настройки:

Адрес сервера задавать не нужно, т.к. симулятор поддерживает все адреса - это квадратики снизу. Когда идёт обмен с конкретным адресом, то вокруг адреса появляется жёлтая рамка. Проверить наличие обмена можно "пассивно" (без открытия порта) с помощью Serial Port Monitor. При этом симулятор должен быть запущен.
Возможно нужно отключить RTS contorl.

RizONE
Offline
Зарегистрирован: 22.03.2018

У меня такие же настройки. По поводу ID слейва была такая мысль и я потыкал в каждый квадратик и сделал их красными, кроме нужного мне 10го - эфекта никакого. Попробую читать адреса с 40001, а не 1000 и 1001. Интересно, что когда я отключал ардуинку то строки типа Modem status тоже переставали сыпаться...

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

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

> У меня такие же настройки.
Судя по титульной строке - нет. "R - en" - у меня такой надписи нет.

RizONE
Offline
Зарегистрирован: 22.03.2018

uni пишет:

Судя по титульной строке - нет. "R - en" - у меня такой надписи нет.

пардон, не та картинка в посте. Я пробовал со всеми настройками...а теперь мэджик!

Ничего не менял со вчера, просто собрал и запустил!

А там где пропали запросы это я немного изменил скетч и все рухнуло! Собранный макет вообще не трогал! Вернул изменения обратно - нихрена не читает!

RizONE
Offline
Зарегистрирован: 22.03.2018

Этот слейв вроде как победил, видать не совсем драйвера сдружились на компьютере, тем не менее получаю четкую картину

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

#include <ModbusRtu.h>

#define TXEN 10
#define ID 10

uint16_t au16data[16];
uint16_t flag = 1;
union Data
{
  struct REG
  {
    uint16_t LOWORD;
    uint16_t HIWORD;
  } reg;

  float fvalue;
};

Data dataM;

Modbus master(0,0,TXEN);
modbus_t telegram;

void setup(void) {
  master.begin(19200);
  master.setTimeOut(1000);
}

void loop(void) {
  telegram.u8id = ID;
  telegram.u8fct = 4;
  telegram.u16RegAdd = 1000;
  telegram.u16CoilsNo = 1;
  telegram.au16reg = au16data;
  master.query(telegram);
  master.poll();
  if (master.getState() == COM_IDLE) {
    dataM.reg.HIWORD = au16data;
  }
  //dataM.reg.HIWORD = 0xd89b;
  //dataM.reg.LOWORD = 0x3356;
  delay(10);
  telegram.u8id = ID;
  telegram.u8fct = 4;
  telegram.u16RegAdd = 1001;
  telegram.u16CoilsNo = 1;
  telegram.au16reg = au16data;
  master.query(telegram);
  master.poll();
  if (master.getState() == COM_IDLE) {
    dataM.reg.LOWORD = au16data;
  }
  delay(1000);
}

между чтениями поставил задержку, думал быстро читаю. Эффекта нет. Чтение 1001 регистра нет нет ппроскакивает в логе, но только при первых итерациях цикла, далее запрос на 1001 просто пропадает. если завершить работу слейва и запустить его, то первым пойдет запрос на чтение 1001 регистра, а дальше везде 1000й