Прочитайте описание протокола MODBUS. Все ответы там. Конкректно по #46. Ответте на вопрос: Какой номер команды для чтения регистров слейва? А теперь попробуйте найти эту команду в вашем скетче. Наводка - телеграмм должно быть как минимум две - одна для записи, другая для чтения.
я скетч и выложил полностью, что бы показать, что номер сериала задается вами в 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();
}
я скетч и выложил полностью, что бы показать, что номер сериала задается вами в Modbus slave(ID, 0, 10); где 0- номер сериала
вот пример чтения аналоговых портов
и зачем тебе именно программный ?
спасибо за пример, это я понял что второй параметр это номер сериала, но хотел использовать программный чтоб сериал 0 не занимать на микро. но в принципи буду использовать его а для отладки попользую программный сериал.
тут другая проблемка вылезла не могу от слейва прочитать настере ответ.. пока не понимаю почему, У Вас случаем нет примера рабочего?
// интересная конструкция
// запуск отложеного действия
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);
// которое тоже можно разложить на две строки взятые в {}
// плюс в том что можно даже отослать единственное сообщение отложеное во времени
// интересная конструкция
// запуск отложеного действия
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);
// которое тоже можно разложить на две строки взятые в {}
// плюс в том что можно даже отослать единственное сообщение отложеное во времени
Ну да. Один бред наложен на другой. Брать надо первоисходники. Это раз. Читать стандарт. Это два. Сравнить стандарт с реализацией. Это три.
Конкретно по данной библиотеке нет различия для coil holding и прочих регистров. Разница есть только в доступе при чтении разными командами. При этом одину и туже ячейку памяти можно читать разными командами как coil и как holding, так и писАть. Копирование из регистра в регистр не имеет смысла, если явно не объявлено количество coil регистров.
брать нужно под задачу. Не всегда обновления приносят "радость и легкость". Для моей задачи этого было достаточно. стандарт? покажи мне единый стандарт на регистры. Вот что нужно делать только так. Да нет такого, каждый свой производитель свой лепит.Да ладно, прям они все открыты для чтения/записи?
а по поводу смысла к копировании, он был прост. Пример для регистров, соберите его и попробуйте с ОРС сервера или скады в input вписать что-то. пример - это пример. смысл в нем обычно показать базовые команды.
Пример не мой, так что выводы это мое личное мнение. Мне лично было очень легко по нему понять как пользоваться библиотекой.
В реализации данной библиотеки, все объявленные регистры открыты для чтения/записи.
Зачем стандарт на регистры? Я имел в виду стандарт на протокол MODBUS. В нем все написано про регистры. Вы сам должны выбрать, что куда писать и что читать. Никогда не пользовался ни ОРС ни скадой. Сам писал на дельфи мастера и никаких ограничений на запись чтение регистров не имел.
я же и прошу показать где это четко прописано. Не рекомендации, а тот как должно быть
т.е. вы программно на слейве не ограничивали на запись никакие регистры? странно, кто ж тогда стандарт не соблюдает
Ещё раз. Это чужая библиотека. Я к ней не имею ни какого отношения. Ничего на слейве я ограничить не могу. Тем более что ( цитата из 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 не прописано.
Я не делал на слейве ничего. Это библиотека. Для неё нет понятия Input регистр. У неё есть ячейки памяти в которые можно писать и которые можно читать. Если бы я писал слейва и мне нужно было бы ограничить запись в эти ячейки, я бы это сделал.
Это не терминальная программа. Её нельзя использовать для дешифрации чужих мастер пакетов. В правом верхнем окне показаны RAW пакеты идущие по сети. Они абсолютно правильные для включения - выключения диода, такие же как в вашем посте #27,которые по вашим словам диодом мигали. Т.Е. ваш мастер посылает правильные пакеты. Ищите где вы не правильно соеденили мастер и слэйв. И обратите внимание на пост #32. Программа покажет правильно ли работает мастер. И напоминаю. Этими пакетами можно только записывать данные в слэйв. Прочитать можно командой 3.
Это список команд, которые понимает библиотека. Какое отношение они имеют к регистрам? Откройте хотя бы вики и прочитайте про регистры и команды.
nik182 пишет:
Я не делал на слейве ничего. Это библиотека. Для неё нет понятия Input регистр. У неё есть ячейки памяти в которые можно писать и которые можно читать. Если бы я писал слейва и мне нужно было бы ограничить запись в эти ячейки, я бы это сделал.
блин мне просто интересно, насколько коротка твоя кратковременная память
Baks, попробуй masterOPC universal modbus server. довольна просто и бесплатна до 32-х тегов
у тебя скорость стоит какая на дуйне 19200? линии а и в не перепутаны?
Да,там есть команды для чтения и записи разных регистров. Если бы мы ощались с каким нибудь конкретным устройством, где были определены регистры, в которые нельзя писать или читать, то нужно было бы искользовать соответствующие команды. Но мы общаемся с ардуиной, в которую загружена эта библиотека. В данной библиотеке определён массив регистров в виде массива ячеек памяти. Эти ячейки можно писать и читать любой из приведённых команд. В момент написания слейва пользователь определяет сколько ячеек использовать и под какие нужды. Кроме того в библиотеке есть возможность отделить coil от holdind регистров. Но в приведённых в топике примерах эта возможножность ни разу не использована. Что не так?
и снова привет колегам, чето меня засада с непониманием причины НЕ работы модбуса по рс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 );
}
}
Я вам уже несколько раз сказал. Слейв ничего не может послать мастеру в ответ на ваш код. У вас в коде нет запроса мастера на посылку ему данных. Сам слейв без запроса данные не посылает. Измените код. Или вы ждёте, что его напишут за вас?
#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 );
}
Я вам уже несколько раз сказал. Слейв ничего не может послать мастеру в ответ на ваш код. У вас в коде нет запроса мастера на посылку ему данных. Сам слейв без запроса данные не посылает. Измените код. Или вы ждёте, что его напишут за вас?
Спасибо за наводку, но где можно посмотреть пример запроса мастера на посылку ему данных ?
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.
Телеграммы нужно посылать отдельно друг от друга. Послали первую телеграмму - дождались ответа, проверили что ошибки нет - посылаем вторую и тоже ждем ответа. Попробуйте предыдущий код удвоить и посылать телеграммы с кодами 3 и 6 или по времени - раз в 2 секунды, или по нажатию разных клавишь. Всё заработает.
Присвоение адреса первого регистра MODBUS третьему элементу объявленного предварительно массива. Ответ слейва будет писаться с этого элемента массива. На пакет передачи такое присвоение ни как не влияет.
Скажите, где вы такую хрень берёте? В стандартных примерах библиотеки такого нет.
взял чуть выше #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
нужно от мастера послать пакет слейву с 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;
}
}
Вот чуть чуть модифицированный код мастера под ваш слэйв(рандом на четвёртую ячейку в слэйве вернуть надо. И уберите 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 пин
}
telegram[1].au16reg = au16data+4; // pointer to a memory array in the Arduino
я это не писал, что за +4?
Это обращение к третей ячейке MODBUS. По другому это можно записать так ...=&au16data[2]. Так действуют, когда надо отправить слейву не первую ( au16data[0] ) ячейку памяти.
Прочитайте описание протокола MODBUS. Все ответы там. Конкректно по #46. Ответте на вопрос: Какой номер команды для чтения регистров слейва? А теперь попробуйте найти эту команду в вашем скетче. Наводка - телеграмм должно быть как минимум две - одна для записи, другая для чтения.
я скетч и выложил полностью, что бы показать, что номер сериала задается вами в Modbus slave(ID, 0, 10); где 0- номер сериала
вот пример чтения аналоговых портов
и зачем тебе именно программный ?
я скетч и выложил полностью, что бы показать, что номер сериала задается вами в Modbus slave(ID, 0, 10); где 0- номер сериала
вот пример чтения аналоговых портов
и зачем тебе именно программный ?
спасибо за пример, это я понял что второй параметр это номер сериала, но хотел использовать программный чтоб сериал 0 не занимать на микро. но в принципи буду использовать его а для отладки попользую программный сериал.
тут другая проблемка вылезла не могу от слейва прочитать настере ответ.. пока не понимаю почему, У Вас случаем нет примера рабочего?
qwone, убейся об стену, твой говнокод не будет правильно работать
tempus = millis() + 50;
Это 100% ошибка.
я чтото вас совсем не пойму... что это такое?
я проблемка вылезла не могу от слейва прочитать настере ответ.. пока не понимаю почему, У Вас случаем нет примера рабочего?
Вы в коде мастера #46 поменяйте функцию с 6 на 3 и всё получите.
я читаю через ОРС сервер, мастером как то не заморачивался, пока не приходилось
со слейва отправляю так au16data[1,1] = 1;
в манитор того же слейва приходит один мусор в виде черточек
http://arduino.ru/Reference/Serial/Println
со слейва отправляю так au16data[1,1] = 1;
в манитор того же слейва приходит один мусор в виде черточек
Скажите, почему au16data двух мерный массив? Он должен быть одномерным для работы с MODBUS.
кому он должен?
там идет [номер регистра], бит. ну тут это излишество. но оно работает. Пример вылаживал свой, под определенные цели
Ну да конечно. Никто ни кому не должен. Вот только библиотека кушает линейно с начала массива и третий элемент никак не может быть au16data[3,3].
вот пример из самой библиотеки
Может быть мы про разные библиотеки говорим? Вот этот бред я вообще не понимаю au16data[0] = au16data[1];
У меня ModBusRTU. Там
нет никаких переприсвоений внутри массива. Только присвоение элементам массива значений.
https://habrahabr.ru/post/249043/
вот статья, брал отсюда. Наверное просто на гите обнова была, и у меня версия старая
Ну да. Один бред наложен на другой. Брать надо первоисходники. Это раз. Читать стандарт. Это два. Сравнить стандарт с реализацией. Это три.
Конкретно по данной библиотеке нет различия для coil holding и прочих регистров. Разница есть только в доступе при чтении разными командами. При этом одину и туже ячейку памяти можно читать разными командами как coil и как holding, так и писАть. Копирование из регистра в регистр не имеет смысла, если явно не объявлено количество coil регистров.
брать нужно под задачу. Не всегда обновления приносят "радость и легкость". Для моей задачи этого было достаточно. стандарт? покажи мне единый стандарт на регистры. Вот что нужно делать только так. Да нет такого, каждый свой производитель свой лепит.Да ладно, прям они все открыты для чтения/записи?
а по поводу смысла к копировании, он был прост. Пример для регистров, соберите его и попробуйте с ОРС сервера или скады в input вписать что-то. пример - это пример. смысл в нем обычно показать базовые команды.
Пример не мой, так что выводы это мое личное мнение. Мне лично было очень легко по нему понять как пользоваться библиотекой.
Но мы отошли от темы. да пусть пишет как хочет. библиотека может и кушает, но мы ей задаем всеравно одномерный масив. т.к. нигде нет
вот тогда оно поломается. Согласен. Я писал тот скетч давно, вот правильно
Да ладно, прям они все открыты для чтения/записи?
В реализации данной библиотеки, все объявленные регистры открыты для чтения/записи.
Зачем стандарт на регистры? Я имел в виду стандарт на протокол MODBUS. В нем все написано про регистры. Вы сам должны выбрать, что куда писать и что читать. Никогда не пользовался ни ОРС ни скадой. Сам писал на дельфи мастера и никаких ограничений на запись чтение регистров не имел.
я же и прошу показать где это четко прописано. Не рекомендации, а тот как должно быть
т.е. вы программно на слейве не ограничивали на запись никакие регистры? странно, кто ж тогда стандарт не соблюдает
Ещё раз. Это чужая библиотека. Я к ней не имею ни какого отношения. Ничего на слейве я ограничить не могу. Тем более что ( цитата из 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 не прописано.
вы меня не так поняли, я имел ввиду, что если вы на слейве делали Input регистр, то с мастера могли его перезаписывать?
Я не делал на слейве ничего. Это библиотека. Для неё нет понятия Input регистр. У неё есть ячейки памяти в которые можно писать и которые можно читать. Если бы я писал слейва и мне нужно было бы ограничить запись в эти ячейки, я бы это сделал.
Это список команд, которые понимает библиотека. Какое отношение они имеют к регистрам? Откройте хотя бы вики и прочитайте про регистры и команды.
мужики да хорош вам, я выложил массив многомерный только для пробы, и еще гдето видел пример тоже кто то делал в сети.
а вообще пробую по всякому и пытаюсь понять что за фигня и почему слейв не отвечает мастеру или пакеты не доходят или я читаю не правильно
вот что выдала терминальная программка и помоему что то тут не все в порядке с пакетами, или я ошибаюсь? и какойто бред в столбике slaveID
Это не терминальная программа. Её нельзя использовать для дешифрации чужих мастер пакетов. В правом верхнем окне показаны RAW пакеты идущие по сети. Они абсолютно правильные для включения - выключения диода, такие же как в вашем посте #27,которые по вашим словам диодом мигали. Т.Е. ваш мастер посылает правильные пакеты. Ищите где вы не правильно соеденили мастер и слэйв. И обратите внимание на пост #32. Программа покажет правильно ли работает мастер. И напоминаю. Этими пакетами можно только записывать данные в слэйв. Прочитать можно командой 3.
Я не делал на слейве ничего. Это библиотека. Для неё нет понятия Input регистр. У неё есть ячейки памяти в которые можно писать и которые можно читать. Если бы я писал слейва и мне нужно было бы ограничить запись в эти ячейки, я бы это сделал.
блин мне просто интересно, насколько коротка твоя кратковременная память
Baks, попробуй masterOPC universal modbus server. довольна просто и бесплатна до 32-х тегов
у тебя скорость стоит какая на дуйне 19200? линии а и в не перепутаны?
блин мне просто интересно, насколько коротка твоя кратковременная память
Извини, но я не понял твоего сарказма.
Ты привел список команд библиотеки https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino.
Да,там есть команды для чтения и записи разных регистров. Если бы мы ощались с каким нибудь конкретным устройством, где были определены регистры, в которые нельзя писать или читать, то нужно было бы искользовать соответствующие команды. Но мы общаемся с ардуиной, в которую загружена эта библиотека. В данной библиотеке определён массив регистров в виде массива ячеек памяти. Эти ячейки можно писать и читать любой из приведённых команд. В момент написания слейва пользователь определяет сколько ячеек использовать и под какие нужды. Кроме того в библиотеке есть возможность отделить coil от holdind регистров. Но в приведённых в топике примерах эта возможножность ни разу не использована. Что не так?
Вот теперь нормальный, понятный ответ. Просто по неполным фразам может сложится неправильное мнение. Все так
и снова привет колегам, чето меня засада с непониманием причины НЕ работы модбуса по рс485 уже достала, хоть бросай и на чтото другое переходи
вот что получается мастер и если убрать делай из loop то очень быстро проходит передача и на слейве моргает 13 пином, а в ответ от слейва посылаю тоже значение мастеру для 13 пина, но фигвам, не хочет работать, и что и как проверить не знаю... кто в курсе дайте совет
слейв
и скрин с терминала
https://drive.google.com/file/d/0Bw55nc23As-3VGRxR21yZ2tXNlU/view?usp=sharing
https://drive.google.com/file/d/0Bw55nc23As-3OG82QnloQ21iSWc/view?usp=sharing
Я вам уже несколько раз сказал. Слейв ничего не может послать мастеру в ответ на ваш код. У вас в коде нет запроса мастера на посылку ему данных. Сам слейв без запроса данные не посылает. Измените код. Или вы ждёте, что его напишут за вас?
попробуй этот
Спасибо за наводку, но где можно посмотреть пример запроса мастера на посылку ему данных ?
или попробовать заменить
COM_IDLE на COM_WAITING ?
James спасибо у меня то же самое
нет не тоже самое, попробуй со стандартным
в своем коде, ты пытаешься прочитать 1 регистр, но в слейве он закомментирован
Вот в том то и прикол что слейв работает, моргает 13 пином, а мастер нет,.
Вечером обязательно попробую
Телеграммы нужно посылать отдельно друг от друга. Послали первую телеграмму - дождались ответа, проверили что ошибки нет - посылаем вторую и тоже ждем ответа. Попробуйте предыдущий код удвоить и посылать телеграммы с кодами 3 и 6 или по времени - раз в 2 секунды, или по нажатию разных клавишь. Всё заработает.
что вот это значить +4?
telegram[1].au16reg = au16data+4;
// pointer to a memory array in the Arduino
если я правильно понял то это увеличиваем пакет для передачи?
Присвоение адреса первого регистра MODBUS третьему элементу объявленного предварительно массива. Ответ слейва будет писаться с этого элемента массива. На пакет передачи такое присвоение ни как не влияет.
Скажите, где вы такую хрень берёте? В стандартных примерах библиотеки такого нет.
взял чуть выше #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 но толку нет
Можете описать, что вы хотите сделать? Я уже потерялся в ваших хотелках. Коды программ совершенно не соответствуют тому, что вы описываете.
нужно от мастера послать пакет слейву с 1 или 2 значения. Эта часть получилась и значение считывается в слейве.
вторая часть задачи это послать ответный пакет от слейва к мастеру в котором будет к примеру 10 значений. и прочитать их на мастере. - это не выходит.
на данный мамент из мастера включаю и выключаю 13 пин на слейве, а из слейва не могу включить 13 пин мастеру ответ от слейва доходит до мастера проверял так
мастер
слейв
Вот чуть чуть модифицированный код мастера под ваш слэйв(рандом на четвёртую ячейку в слэйве вернуть надо. И уберите
au16data[16] = 1;
такой ячейки не существует, а запись в неё может портить программу). У меня не начем проверить. Работает ли не знаю, но думаю где-то так.Вогнал код в нану и запустил diagslave, тот что по ссылке из шапки скетча. Вот вывод
я это не писал, что за +4?
ничего себе, как же я не замтил вот таких строк // telegram 0: read registers, // telegram 1: write a single register
Чувствую 5 точкой что зработает как надо
nik182 спасибо за Вашу помощ!
я это не писал, что за +4?
Это обращение к третей ячейке MODBUS. По другому это можно записать так ...=&au16data[2]. Так действуют, когда надо отправить слейву не первую ( au16data[0] ) ячейку памяти.