Вставте в конец скетча вывод массива и следите за значениями при подключении слейва. Если изменятся - то всё в порядке. Ищите номера регистров, где потеря. Если нет то выкиньте из слейва au16data[16] и ещё раз попробуйте.
/**
подключение
DE & Re перемычкой и к ардуино к 4 пину(установить в #define TXEN 4)
DI - TX_0
RO - RX_0
VCC - 5вольт
GND - GND
A - A Сеть между модулями
B - B Сеть между модулями
*/
#include <ModbusRtu.h>
uint16_t au16data[16]; //!< data array for modbus network sharing, массив данных для совместного использования сети Modbus
uint8_t u8state; //!< machine state
uint8_t u8query; //!< pointer to message query. указатель на запрос сообщения
int speedSend = 300;//ms между отправками
int pin = 13;// 13 пин(встроенный светодеод) который включается по команде от слейва
int raz = 0;
int8_t packet = 0;// тут сохраняем информацию о входящем пакете
int state = LOW;
#define TXEN 4 // ПИН АРДУИНО DE + RE(перемычка) Для переключения модуля прием или передача
unsigned long u32wait; // тут храним милис для паузы между последним ответом от слейва и новой отправкой пакета
//устанавливается в speedSend
/**
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
u8id : node id = 0, если мастер то первый параметр = 0
u8serno : второй параметр это сериал порт (ТХ_0 RX_0 знасит параметр = 0)
u8txenpin : третий это пин для переключения прием и передача
*/
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]; // 2 телеграммы (отправка и прием)
void setup() {
// telegram 0: read registers
telegram[0].u8id = 1; // slave address,№ слейва с кем общаемся
telegram[0].u8fct = 3; // function code (this one is registers read), пераметр 3 - включает чтение пакета от слейва
telegram[0].u16RegAdd = 0; // start address in slave. Начинается отсчет из 0 регистра
telegram[0].u16CoilsNo = 16; // number of elements (coils or registers) to read, прочитать 16 регистров
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), пераметр 6 - включает запись для передачи инфы слейву
telegram[1].u16RegAdd = 0; // start address in slave. Начинается отсчет из 0 регистра
telegram[1].u16CoilsNo = 1; // number of elements (coils or registers) to read, прочитать 1 регистр
telegram[1].au16reg = au16data; // pointer to a memory array in the Arduino, структура которая передается между модулями
master.begin( 19200 ); // baud-rate at 19200,скорасть общения между модулями
master.setTimeOut( 500 ); // if there is no answer in 5000 ms, roll over,если нет ответа в 5000 мс, пролонгировать,
u32wait = millis() + 1000; //
u8state = u8query = 0;
pinMode(pin, OUTPUT);// декларируем как ВЫВОД пин 13 со светодеодом
pinMode(TXEN, OUTPUT);// декларируем как ВЫВОД пин модуля (прием или передача)
}
void loop() {
switch ( u8state ) {
case 0:
if (millis() > u32wait) u8state++; // wait state, ждем пока не пройдем speedSend,
break;
case 1:
master.query( telegram[u8query] ); // send query (only once), отправим телеграмму
u8state++;
u8query++;
if (u8query > 2) u8query = 0;
break;
case 2:
/**
*если пришел правeльный пакет то ответ будет больше 4
* int8_t packet = 0;
*/
packet = master.poll(); // check incoming messages
if (master.getState() == COM_IDLE) {//если есть входящее сообщение
u8state = 0;
u32wait = millis() + speedSend;
//-------------------------
raz = au16data[3];// пытаюсь прочитать ответ от слейва из 3 регистра от слейва
if ( raz == 0) state = LOW ; else state = HIGH;
digitalWrite(pin, state);// если что то больше 0 то включить 13 пин
// digitalWrite(pin, au16dataR[3]);// тек как у нас приходит или 0 или 1 , можно и так моргать светодеодом на 13 пине
au16data[0] = random(2); // запишим в 0 регистр пакета или 0 или 1 для отправки слейву
//-------------------------
}
break;
}
}
слейв
/**
подключение модуля на чипе max485
DE & Re перемычкой и к ардуино к 4 пину(установить в #define TXEN 4)
DI - TX_0
RO - RX_0
VCC - 5 вольт
GND - GND
A - A Сеть между модулями
B - B Сеть между модулями
*/
#include <Arduino.h>
#include <ModbusRtu.h>
int vP1 = 0;
int8_t packet = 0; // если пришел правeльный пакет то будет больше 4
#define TXEN 4 // ПИН АРДУИНО DE + RE(перемычка) Для переключения модуля прием или передача
int pin = 13; // встроенный светодеод
volatile int state = LOW;
// data array for modbus network sharing
uint16_t au16data[16]; // массив данных для совместного использования сети Modbus
/**
* 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);
}
void loop() {
packet = slave.poll( au16data, 16 );// эта функция принимает пакет
/**
*если пришел правeльный пакет то ответ будет больше 4
* int8_t packet = 0;
*/
if (packet > 4) {
vP1 = au16data[0];// читаем 0 регистр телеграммы и пишим в переменную
if( vP1 ==0) state = LOW; else state= HIGH;// если переменная равна 0 то запишим в переменную state выключить 13 пин иначи включим
digitalWrite(pin, state);// вкл или выкл
// заполним все регисты для отправки мастеру в ответ на запрос
// au16data[1] = 0;
// au16data[2] = 256;
au16data[3] = random(2); // запишем в регистр телеграммы №4 или 0 или 1 для отправки в ответе на запос мастера
}
}
работает так...
мастер посылает пакет слейву с рандомным значением или 0 или 1 и записано оно в au16data[0] = random(2);
слейв получает телеграмму и читает 0 регистр и включает и отключает 13 пин, а в ответом сообщении отправляет мастеру au16data[3] = random(2); (или 0 или 1)
и мастер читает ответ слейва и включает или отключает свой 13 пин
но есть одна проблемка
master.setTimeOut( 500 ); // if there is no answer in 5000 ms, roll over,если нет ответа в 5000 мс, пролонгировать,
ждет ответа, но если ответ приходит то все равно ждет.... это косяк библиотеки?
в случае удачного ответа как приступить к отпрвке следующего пакета не дожидаясь конца setTimeOut()
пробовал так но не работает
void loop() {
switch ( u8state ) {
case 0:
if (millis() > u32wait) u8state++; // wait state, ждем пока не пройдем speedSend,
master.setTimeOut( 50000 ); // <<<<<<<<<<<<<<______________________________________________________________________________
break;
case 1:
master.query( telegram[u8query] ); // send query (only once), отправим телеграмму
u8state++;
u8query++;
if (u8query > 2) u8query = 0;
break;
case 2:
/**
*если пришел правeльный пакет то ответ будет больше 4
* int8_t packet = 0;
*/
packet = master.poll(); // check incoming messages
if (master.getState() == COM_IDLE) {//если есть входящее сообщение
master.setTimeOut( 10 );// <<<<<<<<<<<<<<______________________________________________________________________________
u8state = 0;
u32wait = millis() + speedSend;
//-------------------------
raz = au16data[3];// пытаюсь прочитать ответ от слейва из 3 регистра от слейва
if ( raz == 0) state = LOW ; else state = HIGH;
digitalWrite(pin, state);// если что то больше 0 то включить 13 пин
// digitalWrite(pin, au16dataR[3]);// тек как у нас приходит или 0 или 1 , можно и так моргать светодеодом на 13 пине
au16data[0] = random(2); // запишим в 0 регистр пакета или 0 или 1 для отправки слейву
//-------------------------
}
break;
}
}
Суть: мастер передает число 20 слейву. Если это число получено, то мигаем 13 пином раз в секунду, если нет такого числа - мигает в 4 раза чаще. И в свою очередь слейв должен ответить мастеру, послав число 30. Если такое число получено\неполучено выполняется аналогичный сценарий с миганием светика.
Пробую все на связке китайских Uno (мастер) и nano (слейв). Скетчи из поста 110.
Мастер не мигает, слейв мигает. Меняю uno на nano. Скетчи те же. Вуаля, и мастер и слейв замигали. 2 раза пробовал так менять - результат один и тот же (на уно не хочет мигать).
Для проверки 13 пина загрузил на уно стандартный скетч blink - мигает.
ну вот, у меня на nano все нормально работает. Может в uno косяк какой
Блин, мне как раз uno + w5100 нужна была для проекта. Но все же есть прогресс.
Не подскажите как можно сделать:
- мастер передает информацию (время: часы 24-часовой формат и минуты), слейв забирает эту информацию себе, в свою очередь отсылает мастеру значение температуры (целое число, возможно и отрицательное)
ну вот вместо ваших "20" и "30" отправляете дату и температуру соответственно. при получении даты, сохраняем её в переменную на слэйве. и после этого отправляет "30"- т.е. температуру которую мастер себе записывает.
ну вот вместо ваших "20" и "30" отправляете дату и температуру соответственно. при получении даты, сохраняем её в переменную на слэйве. и после этого отправляет "30"- т.е. температуру которую мастер себе записывает.
У меня код как в 110 посте:
мастер
/**
подключение
DE & Re перемычкой и к ардуино к 4 пину(установить в #define TXEN 4)
DI - TX_0
RO - RX_0
VCC - 5вольт
GND - GND
A - A Сеть между модулями
B - B Сеть между модулями
*/
#include <ModbusRtu.h>
uint16_t au16data[16]; //!< data array for modbus network sharing, массив данных для совместного использования сети Modbus
uint8_t u8state; //!< machine state
uint8_t u8query; //!< pointer to message query. указатель на запрос сообщения
int speedSend = 300;//ms между отправками
int pin = 13;// 13 пин(встроенный светодеод) который включается по команде от слейва
int raz = 0;
int8_t packet = 0;// тут сохраняем информацию о входящем пакете
int state = LOW;
#define TXEN 2 // ПИН АРДУИНО DE + RE(перемычка) Для переключения модуля прием или передача
unsigned long u32wait; // тут храним милис для паузы между последним ответом от слейва и новой отправкой пакета
//устанавливается в speedSend
/**
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
u8id : node id = 0, если мастер то первый параметр = 0
u8serno : второй параметр это сериал порт (ТХ_0 RX_0 знасит параметр = 0)
u8txenpin : третий это пин для переключения прием и передача
*/
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]; // 2 телеграммы (отправка и прием)
void setup() {
// telegram 0: read registers
telegram[0].u8id = 1; // slave address,№ слейва с кем общаемся
telegram[0].u8fct = 3; // function code (this one is registers read), пераметр 3 - включает чтение пакета от слейва
telegram[0].u16RegAdd = 0; // start address in slave. Начинается отсчет из 0 регистра
telegram[0].u16CoilsNo = 16; // number of elements (coils or registers) to read, прочитать 16 регистров
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), пераметр 6 - включает запись для передачи инфы слейву
telegram[1].u16RegAdd = 0; // start address in slave. Начинается отсчет из 0 регистра
telegram[1].u16CoilsNo = 1; // number of elements (coils or registers) to read, прочитать 1 регистр
telegram[1].au16reg = au16data; // pointer to a memory array in the Arduino, структура которая передается между модулями
master.begin( 19200 ); // baud-rate at 19200,скорасть общения между модулями
master.setTimeOut( 500 ); // if there is no answer in 5000 ms, roll over,если нет ответа в 5000 мс, пролонгировать,
u32wait = millis() + 1000; //
u8state = u8query = 0;
pinMode(pin, OUTPUT);// декларируем как ВЫВОД пин 13 со светодеодом
pinMode(TXEN, OUTPUT);// декларируем как ВЫВОД пин модуля (прием или передача)
}
void loop() {
switch ( u8state ) {
case 0:
if (millis() > u32wait) u8state++; // wait state, ждем пока не пройдем speedSend,
break;
case 1:
master.query( telegram[u8query] ); // send query (only once), отправим телеграмму
u8state++;
u8query++;
if (u8query > 2) u8query = 0;
break;
case 2:
/**
*если пришел правeльный пакет то ответ будет больше 4
* int8_t packet = 0;
*/
packet = master.poll(); // check incoming messages
if (master.getState() == COM_IDLE) {//если есть входящее сообщение
u8state = 0;
u32wait = millis() + speedSend;
//-------------------------
raz = au16data[3];// пытаюсь прочитать ответ от слейва из 3 регистра от слейва
if ( raz == 0) state = LOW ; else state = HIGH;
digitalWrite(pin, state);// если что то больше 0 то включить 13 пин
// digitalWrite(pin, au16dataR[3]);// тек как у нас приходит или 0 или 1 , можно и так моргать светодеодом на 13 пине
au16data[0] = random(2); // запишим в 0 регистр пакета или 0 или 1 для отправки слейву
//-------------------------
}
break;
}
}
Слейв
/**
подключение модуля на чипе max485
DE & Re перемычкой и к ардуино к 4 пину(установить в #define TXEN 4)
DI - TX_0
RO - RX_0
VCC - 5 вольт
GND - GND
A - A Сеть между модулями
B - B Сеть между модулями
*/
#include <Arduino.h>
#include <ModbusRtu.h>
int vP1 = 0;
int8_t packet = 0; // если пришел правeльный пакет то будет больше 4
#define TXEN 2 // ПИН АРДУИНО DE + RE(перемычка) Для переключения модуля прием или передача
int pin = 13; // встроенный светодеод
volatile int state = LOW;
// data array for modbus network sharing
uint16_t au16data[16]; // массив данных для совместного использования сети Modbus
/**
* 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);
}
void loop() {
packet = slave.poll( au16data, 16 );// эта функция принимает пакет
/**
*если пришел правeльный пакет то ответ будет больше 4
* int8_t packet = 0;
*/
if (packet > 4) {
vP1 = au16data[0];// читаем 0 регистр телеграммы и пишим в переменную
if( vP1 ==0) state = LOW; else state= HIGH;// если переменная равна 0 то запишим в переменную state выключить 13 пин иначи включим
digitalWrite(pin, state);// вкл или выкл
// заполним все регисты для отправки мастеру в ответ на запрос
// au16data[1] = 0;
// au16data[2] = 256;
au16data[3] = random(2); // запишем в регистр телеграммы №4 или 0 или 1 для отправки в ответе на запос мастера
}
}
8-10 заняты отладочной информацией, по самому протоколу
Discrete Inputs — однобитовый тип, доступен только для чтения.
Coils — однобитовый тип, доступен для чтения и записи.
Input Registers — 16-битовый знаковый или беззнаковый тип, доступен только для чтения.
Holding Registers — 16-битовый знаковый или беззнаковый тип, доступен для чтения и записи.
но в библиотеке они так не разделены, по этому использовать можно все по максимуму
ну это описание видов данных в протоколе. На самом деле библиотека реализованна так, что все являются Holding Registers — 16-битовый знаковый или беззнаковый тип, доступен для чтения и записи. Что такое "бит"-ы я думаю объяснять не нужно?
ну а если в вики лень искать то вот
16
2
½
65535
-32768
+32767
где 16 -количество бит, 2- в байтах, 1/2-в машинных словах, 655535- максимальное значение беззнаковой переменной, -32768 мин значение знаковой переменной и 32768 максимальное значение знаковой переменной
ну это описание видов данных в протоколе. На самом деле библиотека реализованна так, что все являются Holding Registers — 16-битовый знаковый или беззнаковый тип, доступен для чтения и записи. Что такое "бит"-ы я думаю объяснять не нужно?
ну а если в вики лень искать то вот
16
2
½
65535
-32768
+32767
где 16 -количество бит, 2- в байтах, 1/2-в машинных словах, 655535- максимальное значение беззнаковой переменной, -32768 мин значение знаковой переменной и 32768 максимальное значение знаковой переменной
Спасибо большое.
Именно здесь у меня нестыковочка была. Читаю описание modbus - там есть перечисленные выше регистры, в Modbusrtu.h - нет. Теперь понятно.
Как думаете, стОит с ModbusRtu.h "завязывать отношения" или другую пытать?
ну мне в принципе хватает, я её используй в связке с ОРС сервером на компьютере и он прекрасно его понимает
Как думаете, для моей задачи она пойдет:
Задача: несколько ардуинок, каждая выполняет свою задачу - слейвы. Но нужно иметь посредника между ними - мастер. Он забирает со слейва\слейвов информацию, обрабатывает кодом и передает другим слейвам или передает вышестоящему устройству. Например, часы реального времени. Время нужно еще паре модулям. Можно конечно поставить на каждый по отдельному модулю часов, но это как то не по феншую будет. Также мастер должен будет передавать эту информацию (температура, включение вентиляции) в majordomo (по MQTT или Modbus TCP).
Поверьте мне, я не хочу делать систему, типа "с любой точки мира могу включить свет в сортире". Мне удобнее будет тыкнуть свет в выключатель. А вот если идет критическое снижение температуры в погребе, тут система должна включить меры поддержания температуры и мне об этом сообщить, чтобы я проконтролировал этот процесс, в свою очередь тоже принял меры.
С ESP8266 у меня отношения никак не могут сложиться.
а почему нет, это всего лишь библиотека, если что-то не устроит, её можно переписать уже под себя. время как по мне лучше записывать один раз, а потом корректировать периодически. есть такая штука, как USB- RS485 переходник. я с помощью него завожу все в комп. витой пары хватает с головой на свять и питание +24 +12 и +5 для устройств
а почему нет, это всего лишь библиотека, если что-то не устроит, её можно переписать уже под себя. время как по мне лучше записывать один раз, а потом корректировать периодически. есть такая штука, как USB- RS485 переходник. я с помощью него завожу все в комп. витой пары хватает с головой на свять и питание +24 +12 и +5 для устройств
Может кому пригодится. Долго мучался, но получилось передавать температуру по rs485. Создал мастер и слейв.
Библиотека никакая не используется. Вернее сделал свою библиотеку чел, который создал FLprog. С помощью этой программы и создается модбас в моих скетчах. Здесь идет правильное разделение по регистрам модбаса (Coils, Holding registers и т.д.).
Мастер
-опрашивает от слейва 4 температуры
- отдает слейву две переменные (состояние кнопки (boolean) на мастере и просто int переменную с числом, так для ознакомелния, что можно передавать integer).
-Светит встроенным диодом в зависимости от состояния кнопки на слейве.
Слейв
-замеряет 4 температуры датчиками DS18B20 и отправляет мастеру
- Светит встроенным диодом в зависимости от состояния кнопки на мастере.
-Получает число от мастера (просто переменную integer).
-Также отдаёт мастеру данные о своей кнопке.
Код мастера
///// Скетч для МАСТЕРА с одним слейвом ID-1
///// Ниже переменные для функционировайния модбаса
bool _modbusMasterDataTable_0_reg_1[2];
int _modbusMasterAddressTable_0_reg_1[2] = {0, 1};
int _modbusMasterDataTable_4_reg_1[5];
int _modbusMasterAddressTable_4_reg_1[5] = {0, 1, 2, 3, 4};
byte _modbusMasterBufferSize = 0;
byte _modbusMasterState = 1;
long _modbusMasterSendTime;
byte _modbusMasterLastRec = 0;
long _modbusMasterStartT35;
byte _modbusMasterBuffer[64];
byte _modbusMasterCurrentReg = 0;
byte _modbusMasterCurrentVariable = 0;
struct _modbusMasterTelegramm {
byte slaveId;
byte function;
int startAddres;
int numbeRegs;
int valueIndex;
};
_modbusMasterTelegramm _modbusTelegramm;
long _startTimeMasterRegs[1];
long _updateTimeMasterRegsArray[] = {1000};
byte _readWriteMasterVars[] = {1,3};
const unsigned char _modbusMaster_fctsupported[] = {1, 5, 3, 6, 16};
//////переменные мастера (для пользователя)
bool masterButton = 0; // состояние кнопки на мастере
bool slaveButton = 0; // состояние кнопки на слейве
int Temperatura1 = 0;
int Temperatura2 = 0;
int Temperatura3 = 0;
int Temperatura4 = 0;
int toSlave = 3586;
#define masterButton_pin 6 // пин кнопки на мастере (замыкает "массу")
////// СТАРТОВЫЙ ЦИКЛ
void setup()
{
Serial.begin(9600); // сериал порт, который использует модбас
pinMode(4, OUTPUT); digitalWrite(4, LOW); // на этом пине DE RE модуля RS485, НЕЛЬЗЯ! менять
pinMode(masterButton_pin, INPUT); digitalWrite(masterButton_pin, HIGH);
pinMode (13, OUTPUT); digitalWrite(13, LOW);
for(int i=0; i<1; i++) {_startTimeMasterRegs[i] = millis();}
}
void loop() {
bool _tempVariable_bool; // временные переменные,
int _tempVariable_int; // используются только у мастера именно при записи в регистры
masterButton = !digitalRead (masterButton_pin); // заносим состояние кнопки мастера в переменную
digitalWrite (13,slaveButton); // индикация встроенным светодиодом на масетере в зависимости от сост кнопки на слейве
_tempVariable_bool = masterButton; // записываем состояние кнопки мастера в регистр модбаса (Coils адрес 0)
if (! (_tempVariable_bool == _modbusMasterDataTable_0_reg_1[0])) {_readWriteMasterVars[0] = 5;};
_modbusMasterDataTable_0_reg_1[0] = _tempVariable_bool;
slaveButton = (_modbusMasterDataTable_0_reg_1[1]); // считываем состояние кнопки слейва (из регистра coils адрес 1 )
Temperatura1 = (_modbusMasterDataTable_4_reg_1[1]); // считываем температуру1 из переменной модбаса (Holding Registers адрес 1)
Temperatura2 = (_modbusMasterDataTable_4_reg_1[2]); // считываем температуру2 из переменной модбаса (Holding Registers адрес 2)
Temperatura3 = (_modbusMasterDataTable_4_reg_1[3]); // считываем температуру3 из переменной модбаса (Holding Registers адрес 3)
Temperatura4 = (_modbusMasterDataTable_4_reg_1[4]); // считываем температуру4 из переменной модбаса (Holding Registers адрес 4)
_tempVariable_int = toSlave; // записываем переменную от мастера к слейву в регистр модбаса (Holding Registers адрес 0)
if (! (_tempVariable_int == _modbusMasterDataTable_4_reg_1[0])) {_readWriteMasterVars[1] = 6;};
_modbusMasterDataTable_4_reg_1[0] = _tempVariable_int;
/////далее какая то фигня для функционирования модбаса
switch ( _modbusMasterState ) {
case 1:
_nextModbusMasterQuery();
break;
case 2:
pollModbusMaster();
break;
}
}
///////////// Ниже требуха для функционирования модбаса
bool _isTimer(unsigned long startTime, unsigned long period )
{
unsigned long currentTime;
currentTime = millis();
if (currentTime>= startTime) {return (currentTime>=(startTime + period));} else {return (currentTime >=(4294967295-startTime+period));}
}
int modbusCalcCRC(byte length, byte bufferArray[])
{
unsigned int temp, temp2, flag;
temp = 0xFFFF;
for (unsigned char i = 0; i < length; i++) {
temp = temp ^ bufferArray[i];
for (unsigned char j = 1; j <= 8; j++) {
flag = temp & 0x0001;
temp >>= 1;
if (flag) temp ^= 0xA001;
}
}
temp2 = temp >> 8;
temp = (temp << 8) | temp2;
temp &= 0xFFFF;
return temp;
}
void _nextModbusMasterQuery()
{
_selectNewModbusMasterCurrentReg(_modbusMasterCurrentReg, _modbusMasterCurrentVariable);
if (_modbusMasterCurrentReg == 0) return;
_createMasterTelegramm();
_modbusMasterSendQuery();
}
void _selectNewModbusMasterCurrentReg(byte oldReg, byte oldVar)
{
bool isNeeded = 1;
if (oldReg == 0) {_selectNewModbusMasterCurrentReg(1, 0); return;}
if (!(_isTimer ((_startTimeMasterRegs[oldReg - 1]),(_updateTimeMasterRegsArray[oldReg -1])))) {isNeeded = 0;}
if( ! isNeeded ) {if(oldReg < 1) {_selectNewModbusMasterCurrentReg(oldReg+1, 0); return;} else {_modbusMasterCurrentReg = 0; _modbusMasterCurrentVariable = 0; return;}}
if (oldVar == 0) {_modbusMasterCurrentReg = oldReg; _modbusMasterCurrentVariable = 1; return;}
byte temp;
switch (oldReg) {
case 1:
temp = 7;
break;
}
if (oldVar < temp) {_modbusMasterCurrentReg = oldReg; _modbusMasterCurrentVariable = oldVar +1; return;}
_startTimeMasterRegs[oldReg -1] = millis();
if(oldReg < 1) { _selectNewModbusMasterCurrentReg(oldReg+1, 0); return;}
_modbusMasterCurrentReg = 0; _modbusMasterCurrentVariable = 0; return;
}
void _createMasterTelegramm()
{
switch (_modbusMasterCurrentReg) {
case 1:
_modbusTelegramm.slaveId = 1;
switch (_modbusMasterCurrentVariable) {
case 1:
_modbusTelegramm.function = _readWriteMasterVars[1];
_modbusTelegramm.startAddres = 0;
_modbusTelegramm.numbeRegs = 1;
_modbusTelegramm.valueIndex = 0;
_readWriteMasterVars[1] = 3;
break;
case 2:
_modbusTelegramm.function = _readWriteMasterVars[0];
_modbusTelegramm.startAddres = 0;
_modbusTelegramm.numbeRegs = 1;
_modbusTelegramm.valueIndex = 0;
_readWriteMasterVars[0] = 1;
break;
case 3:
_modbusTelegramm.function = 3;
_modbusTelegramm.startAddres = 1;
_modbusTelegramm.numbeRegs = 1;
_modbusTelegramm.valueIndex = 1;
break;
case 4:
_modbusTelegramm.function = 1;
_modbusTelegramm.startAddres = 1;
_modbusTelegramm.numbeRegs = 1;
_modbusTelegramm.valueIndex = 1;
break;
case 5:
_modbusTelegramm.function = 3;
_modbusTelegramm.startAddres = 2;
_modbusTelegramm.numbeRegs = 1;
_modbusTelegramm.valueIndex = 2;
break;
case 6:
_modbusTelegramm.function = 3;
_modbusTelegramm.startAddres = 3;
_modbusTelegramm.numbeRegs = 1;
_modbusTelegramm.valueIndex = 3;
break;
case 7:
_modbusTelegramm.function = 3;
_modbusTelegramm.startAddres = 4;
_modbusTelegramm.numbeRegs = 1;
_modbusTelegramm.valueIndex = 4;
break;
}
break;
}
}
void _modbusMasterSendQuery()
{
bool boolTemp;
int intTemp;
byte currentIndex = _modbusTelegramm.valueIndex;
_modbusMasterBuffer[0] = _modbusTelegramm.slaveId;
_modbusMasterBuffer[1] = _modbusTelegramm.function;
_modbusMasterBuffer[2] = highByte(_modbusTelegramm.startAddres );
_modbusMasterBuffer[3] = lowByte( _modbusTelegramm.startAddres );
switch ( _modbusTelegramm.function ) {
case 1:
case 3:
_modbusMasterBuffer[4] = highByte(_modbusTelegramm.numbeRegs );
_modbusMasterBuffer[5] = lowByte( _modbusTelegramm.numbeRegs );
_modbusMasterBufferSize = 6;
break;
case 5:
switch ( _modbusMasterCurrentReg ) {
case 1 :
boolTemp = _modbusMasterDataTable_0_reg_1[currentIndex];
break;
}
if (boolTemp) {
_modbusMasterBuffer[4] = 0xff;
} else {
_modbusMasterBuffer[4] = 0;
};
_modbusMasterBuffer[5] = 0;
_modbusMasterBufferSize = 6;
break;
case 6:
switch ( _modbusMasterCurrentReg ) {
case 1 :
intTemp = _modbusMasterDataTable_4_reg_1[currentIndex];
break;
}
_modbusMasterBuffer[4] = highByte(intTemp);
_modbusMasterBuffer[5] = lowByte(intTemp);
_modbusMasterBufferSize = 6;
break;
}
_modbusMasterSendTxBuffer();
_modbusMasterState = 2;
}
void _modbusMasterSendTxBuffer()
{
byte i = 0;
int crc = modbusCalcCRC( _modbusMasterBufferSize, _modbusMasterBuffer );
_modbusMasterBuffer[ _modbusMasterBufferSize ] = crc >> 8;
_modbusMasterBufferSize++;
_modbusMasterBuffer[ _modbusMasterBufferSize ] = crc & 0x00ff;
_modbusMasterBufferSize++;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(4, 1 );
delay(5);
Serial.write( _modbusMasterBuffer, _modbusMasterBufferSize );
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(4, 0 );
Serial.flush();
_modbusMasterBufferSize = 0;
_modbusMasterSendTime = millis();
}
void pollModbusMaster()
{
if (_modbusTelegramm.slaveId == 0) { _modbusMasterState = 1; return;}
if (_isTimer(_modbusMasterSendTime, 1000)) {
_modbusMasterState = 1;
return;
}
byte avalibleBytes = Serial.available();
if (avalibleBytes == 0) return;
if (avalibleBytes != _modbusMasterLastRec) {
_modbusMasterLastRec = avalibleBytes;
_modbusMasterStartT35 = millis();
return;
}
if (!(_isTimer(_modbusMasterStartT35, 5 ))) return;
_modbusMasterLastRec = 0;
byte readingBytes = _modbusMasterGetRxBuffer();
if (readingBytes < 5) {
_modbusMasterState = 1;
return ;
}
byte exeption = validateAnswer();
if (exeption != 0) {
_modbusMasterState = 1;
return;
}
switch ( _modbusMasterBuffer[1] ) {
case 1:
get_FC1(0);
break;
case 3:
get_FC3(4);
break;
}
_modbusMasterState = 1;
return;
}
byte _modbusMasterGetRxBuffer()
{
boolean bBuffOverflow = false;digitalWrite(4, LOW );
_modbusMasterBufferSize = 0;
while (Serial.available() ) {
_modbusMasterBuffer[ _modbusMasterBufferSize ] = Serial.read();
_modbusMasterBufferSize ++;
if (_modbusMasterBufferSize >= 64) bBuffOverflow = true;
}
if (bBuffOverflow) {return -3;}
return _modbusMasterBufferSize;
}
byte validateAnswer()
{
uint16_t u16MsgCRC = ((_modbusMasterBuffer[_modbusMasterBufferSize - 2] << 8) | _modbusMasterBuffer[_modbusMasterBufferSize - 1]);
if ( modbusCalcCRC( _modbusMasterBufferSize - 2,_modbusMasterBuffer ) != u16MsgCRC ) { return 255; }
if ((_modbusMasterBuffer[1] & 0x80) != 0) {return _modbusMasterBuffer[2] ;}
boolean isSupported = false;
for (byte i = 0; i < sizeof( _modbusMaster_fctsupported ); i++) {
if (_modbusMaster_fctsupported[i] == _modbusMasterBuffer[1]) {
isSupported = 1;
break;
}
}
if (!isSupported) {return 1;}
return 0;
}
void get_FC1(byte table)
{
byte currentByte = 3;
byte currentBit = 0;
bool value;
byte i;
int currentIndex = _modbusTelegramm.valueIndex;
for (i = 0; i < _modbusTelegramm.numbeRegs; i++) {
value= bitRead(_modbusMasterBuffer[currentByte], currentBit);
switch ( _modbusMasterCurrentReg ) {
case 1 :
if(table == 0) {_modbusMasterDataTable_0_reg_1[currentIndex] =value;}
break;
}
currentIndex ++;
currentBit ++;
if (currentBit > 7) {
currentBit = 0;
currentByte ++;
}
}
_modbusMasterState = 1;
}
void get_FC3(byte table)
{
int currentIndex = _modbusTelegramm.valueIndex;
byte currentByte = 3;
int value;
for (int i = 0; i < _modbusTelegramm.numbeRegs; i++) {
value = word( _modbusMasterBuffer[ currentByte], _modbusMasterBuffer[ currentByte + 1 ]);
switch ( _modbusMasterCurrentReg ) {
case 1 :
if(table == 3) {} else {_modbusMasterDataTable_4_reg_1[currentIndex + i] =value;}
break;
}
currentByte += 2;
}
}
Код слейва
///// Скетч для СЛЕЙВА ID-1.
///// Ниже переменные для функционировайния модбаса
bool _modbusSlaveDataTable_0[2];
int _modbusSlaveAddresTable_0[2] = {0, 1};
int _modbusSlaveDataTable_4[5];
int _modbusSlaveAddresTable_4[5] = {0, 1, 2, 3, 4};
byte _modbusSlaveBufferSize = 0;
byte _modbusSlaveLastRec = 0;
long _modbusSlaveTime;
byte _modbusSlaveBuffer[64];
const unsigned char _modbusSlave_fctsupported[] = {1, 5, 15, 3, 6, 16};
/////// для шины 1-wire и датчиков DS18B20
#include <OneWire.h> // библиотека для DS18B20
OneWire ds(7); // датчики DS18B20 на 7 пин
byte Datchik1[8] ={0x28, 0xFF, 0xB1, 0x43, 0x52, 0x15, 0x01, 0xDB};
byte Datchik2[8] ={0x28, 0xFF, 0xBA, 0x6C, 0x52, 0x15, 0x01, 0x41};
byte Datchik3[8] ={0x28, 0xFF, 0xE8, 0x3C, 0x03, 0x15, 0x03, 0xE3};
byte Datchik4[8] ={0x28, 0x9D, 0xE5, 0x70, 0x01, 0x00, 0x00, 0xEE};// Сетевые адреса датчиков DS18B20
//////переменные слейва (для пользователя)
bool masterButton = 0; // состояние кнопки на мастере
bool slaveButton = 0; // состояние кнопки на слейве
volatile int Temperatura1 = 20;
volatile int Temperatura2 = 20; // температуры измеренный слейвом
volatile int Temperatura3 = 20;
volatile int Temperatura4 = 20;
int FromMaster = 0; // переменная в которую данные пойдут отмастера
#define slaveButton_pin 6 // пин кнопки на слейве (замыкает "массу")
////// СТАРТОВЫЙ ЦИКЛ
void setup()
{
WDTCSR=(1<<WDCE)|(1<<WDE); //для датчиков DS18B20
WDTCSR=(1<<WDIE)| (1<<WDP2)|(1<<WDP1); // для датчиков DS18B20 (разрешение прерывания + выдержка 1 секунда)
Serial.begin(9600); // сериал порт, который использует модбас
pinMode(4, OUTPUT); digitalWrite(4, LOW); // на этом пине DE RE модуля RS485, НЕЛЬЗЯ! менять
pinMode(slaveButton_pin, INPUT); digitalWrite(slaveButton_pin, HIGH);
pinMode (13, OUTPUT); digitalWrite(13, LOW);
}
void loop() {
_modbusSlavePoll();
slaveButton = !digitalRead (slaveButton_pin);
digitalWrite (13, masterButton);
masterButton = (_modbusSlaveDataTable_0[0]); // считываем состояние кнопки мастера (из регистра coils адрес 0 )
_modbusSlaveDataTable_0[1] = slaveButton; // записываем состояние кнопки на слеве в переменную модбаса (регистр coils адрес 1)
_modbusSlaveDataTable_4[1] = Temperatura1; // записываем температуру1 в переменную модбаса (Holding Registers адрес 1)
_modbusSlaveDataTable_4[2] = Temperatura2; // записываем температуру2 в переменную модбаса (Holding Registers адрес 2)
_modbusSlaveDataTable_4[3] = Temperatura3; // записываем температуру3 в переменную модбаса (Holding Registers адрес 3)
_modbusSlaveDataTable_4[4] = Temperatura4; // записываем температуру4 в переменную модбаса (Holding Registers адрес 4)
FromMaster = _modbusSlaveDataTable_4[0]; // считываем переменную от модбаса (Holding Registers адрес 0)
}
///////////// Ниже требуха для измерения датчиками DS18B20
ISR (WDT_vect){ //вектор прерывания WD
static boolean n=0; // флаг работы: запрос температуры или её чтение
n=!n;
if (n) {ds.reset(); // сброс шины
ds.write(0xCC);//обращение ко всем датчикам
ds.write(0x44);// начать преобразование (без паразитного питания)
}
else {ds.reset();
ds.select(Datchik1);
ds.write(0xBE); // Read Scratchpad (чтение регистров)
Temperatura1 = ds.read() | (ds.read()<<8); //прочитаны 2 байта
Temperatura1 = Temperatura1 / 16;
// получение с 2-го датчика
ds.reset();
ds.select(Datchik2);
ds.write(0xBE); // Read Scratchpad (чтение регистров)
Temperatura2 = ds.read() | (ds.read()<<8); //прочитаны 2 байта
Temperatura2 = Temperatura2/16;
ds.reset();
ds.select(Datchik3);
ds.write(0xBE); // Read Scratchpad (чтение регистров)
Temperatura3 = ds.read() | (ds.read()<<8); //прочитаны 2 байта
Temperatura3 = Temperatura3 / 16;
// получение с 2-го датчика
ds.reset();
ds.select(Datchik4);
ds.write(0xBE); // Read Scratchpad (чтение регистров)
Temperatura4 = ds.read() | (ds.read()<<8); //прочитаны 2 байта
Temperatura4 = Temperatura4/16 ;
}}
///////////// Ниже требуха для функционирования модбаса
bool _isTimer(unsigned long startTime, unsigned long period )
{
unsigned long currentTime;
currentTime = millis();
if (currentTime>= startTime) {return (currentTime>=(startTime + period));} else {return (currentTime >=(4294967295-startTime+period));}
}
int modbusCalcCRC(byte length, byte bufferArray[])
{
unsigned int temp, temp2, flag;
temp = 0xFFFF;
for (unsigned char i = 0; i < length; i++) {
temp = temp ^ bufferArray[i];
for (unsigned char j = 1; j <= 8; j++) {
flag = temp & 0x0001;
temp >>= 1;
if (flag) temp ^= 0xA001;
}
}
temp2 = temp >> 8;
temp = (temp << 8) | temp2;
temp &= 0xFFFF;
return temp;
}
byte _modbusSlavePoll()
{
byte avalibleBytes = Serial.available();
if (avalibleBytes == 0) return 0;
if (avalibleBytes != _modbusSlaveLastRec) {
_modbusSlaveLastRec = avalibleBytes;
_modbusSlaveTime = millis();
return 0;
}
if (!(_isTimer(_modbusSlaveTime, 5))) return 0;
_modbusSlaveLastRec = 0;
byte state = _modbusGetSlaveRxBuffer();
if (state < 7) {
return state;
}
if ((_modbusSlaveBuffer[0] != 1) && (_modbusSlaveBuffer[0] != 0)) return 0;
byte exception = _modbusValidateRequest();
if (exception > 0) {
if (exception != 255) { _modbusSlaveBuildException( exception );
_modbusSlaveSendTxBuffer();
}
return exception;
}
switch ( _modbusSlaveBuffer[1] ) {
case 1 :
return process_modbus_FC1(0);
break;
case 5:
return process_modbus_FC5();
break;
case 15:
return process_modbus_FC15();
break;
case 3 :
return process_modbus_FC3(4);
break;
case 6 :
return process_modbus_FC6();
break;
case 16 :
return process_modbus_FC16();
break;
default:
break;
}
return 25;
}
byte _modbusValidateRequest() {
int msgCRC =
((_modbusSlaveBuffer[_modbusSlaveBufferSize - 2] << 8)
| _modbusSlaveBuffer[_modbusSlaveBufferSize - 1]);
if ( modbusCalcCRC( _modbusSlaveBufferSize - 2, _modbusSlaveBuffer ) != msgCRC ) { return 255;}
boolean isSupported = false;
for (uint8_t i = 0; i < sizeof( _modbusSlave_fctsupported ); i++) {
if (_modbusSlave_fctsupported[i] == _modbusSlaveBuffer[1]) {
isSupported = 1;
break;
}
}
if (!isSupported) { return 1;}
int intRegs = 0;
byte byteRegs;
switch ( _modbusSlaveBuffer[1] ) {
case 1:
if(!(checkModbusRange( word( _modbusSlaveBuffer[2], _modbusSlaveBuffer[3]) , word( _modbusSlaveBuffer[4], _modbusSlaveBuffer[5]) ,0))){return 2;}
break;
case 5:
if(!(checkModbusAddres( word( _modbusSlaveBuffer[2], _modbusSlaveBuffer[3]),0))){return 2;}
break;
case 15 :
if(!(checkModbusRange(word( _modbusSlaveBuffer[2], _modbusSlaveBuffer[3]) , word( _modbusSlaveBuffer[4], _modbusSlaveBuffer[5]) ,0))){return 2;}
break;
case 6 :
if(!(checkModbusAddres(( word( _modbusSlaveBuffer[2], _modbusSlaveBuffer[3]) ),4))){return 2;}
break;
case 3 :
case 16 :
if(!(checkModbusRange((word( _modbusSlaveBuffer[2], _modbusSlaveBuffer[3])), (word( _modbusSlaveBuffer[4], _modbusSlaveBuffer[5])),4))){return 2;}
break;
}
return 0; // OK, no exception code thrown
}
bool checkModbusAddres(int addr, byte table)
{
return (!(( modbusSlaveIndexForAddres(addr,table)) == -1));
}
int modbusSlaveIndexForAddres(int addr, byte table)
{
int tableSize = 0;
switch (table) {
case 0:
tableSize = 2;
break;
case 4:
tableSize = 5;
break;
}
for (byte i = 0; i < tableSize; i++) {if((modbusSlaveAddresFromIndex(i,table)) == addr){return i;}}
return -1;
}
int modbusSlaveAddresFromIndex(byte index, byte table)
{
switch (table) {
case 0:
return _modbusSlaveAddresTable_0[index];
break;
case 4:
return _modbusSlaveAddresTable_4[index];
break;
}
return -1;
}
bool checkModbusRange(int startAddr, int addrNumber, byte table)
{
for (int i=0; i < addrNumber; i++) {if(!(checkModbusAddres((startAddr+i),table))){return false;}}
return true;
}
void _modbusSlaveBuildException( byte exception ) {
byte func = _modbusSlaveBuffer[1];
_modbusSlaveBuffer[0] = 1;
_modbusSlaveBuffer[1] = func + 0x80;
_modbusSlaveBuffer[ 2 ] = exception;
_modbusSlaveBufferSize = 3;}
void _modbusSlaveSendTxBuffer()
{
if(_modbusSlaveBuffer[0] == 0) {return;}
byte i = 0;
int crc = modbusCalcCRC( _modbusSlaveBufferSize,_modbusSlaveBuffer );
_modbusSlaveBuffer[ _modbusSlaveBufferSize ] = crc >> 8;
_modbusSlaveBufferSize++;
_modbusSlaveBuffer[ _modbusSlaveBufferSize ] = crc & 0x00ff;
_modbusSlaveBufferSize++;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(4, HIGH );
delay (5);
Serial.write( _modbusSlaveBuffer, _modbusSlaveBufferSize );
while (!(UCSR0A & (1 << TXC0)));
delay (5);
digitalWrite(4, LOW );
Serial.flush();
_modbusSlaveBufferSize = 0;
}
byte _modbusGetSlaveRxBuffer()
{
boolean bBuffOverflow = false;
digitalWrite(4, LOW );
_modbusSlaveBufferSize = 0;
while (Serial.available() ) {
_modbusSlaveBuffer[ _modbusSlaveBufferSize ] = Serial.read();
_modbusSlaveBufferSize ++;
if (_modbusSlaveBufferSize >= 64) bBuffOverflow = true;
}
if (bBuffOverflow) {return -3; }
return _modbusSlaveBufferSize;
}
byte process_modbus_FC1(byte table)
{
byte bytesNo, bitsNo;
int currentCoil, coil;
bool value;
byte index;
int startCoil = word( _modbusSlaveBuffer[2], _modbusSlaveBuffer[ 3] );
int coilNo = word( _modbusSlaveBuffer[4], _modbusSlaveBuffer[5] );
bytesNo = byte(coilNo / 8);
if (coilNo % 8 != 0) bytesNo ++;
_modbusSlaveBuffer[2] = bytesNo;
_modbusSlaveBufferSize = 3;
bitsNo = 0;
for (currentCoil = 0; currentCoil < coilNo; currentCoil++) {
coil = startCoil + currentCoil;
index = modbusSlaveIndexForAddres(coil, table);
if (table == 0) {value = _modbusSlaveDataTable_0[index]; }
bitWrite(
_modbusSlaveBuffer[ _modbusSlaveBufferSize ],
bitsNo,
value);
bitsNo ++;
if (bitsNo > 7) {
bitsNo = 0;
_modbusSlaveBufferSize++;
}
}
if (coilNo % 8 != 0) _modbusSlaveBufferSize ++;
_modbusSlaveSendTxBuffer();
return _modbusSlaveBufferSize + 2;
}
byte process_modbus_FC3(byte table)
{
int startAddr = word( _modbusSlaveBuffer[2], _modbusSlaveBuffer[3] );
int byteRegsno = word( _modbusSlaveBuffer[4], _modbusSlaveBuffer[5] );
int i;
int value;
byte index;
_modbusSlaveBuffer[ 2 ] = byteRegsno * 2;
_modbusSlaveBufferSize = 3;
for (i = startAddr; i < startAddr + byteRegsno; i++) {
index = modbusSlaveIndexForAddres(i, table);
if (table == 4) {value = _modbusSlaveDataTable_4[index]; }
_modbusSlaveBuffer[ _modbusSlaveBufferSize ] = highByte(value);
_modbusSlaveBufferSize++;
_modbusSlaveBuffer[ _modbusSlaveBufferSize ] = lowByte(value);
_modbusSlaveBufferSize++;
}
_modbusSlaveSendTxBuffer();
return _modbusSlaveBufferSize + 2;
}
byte process_modbus_FC5()
{
byte index;
int coil = word( _modbusSlaveBuffer[2], _modbusSlaveBuffer[3] );
index = modbusSlaveIndexForAddres(coil, 0);
_modbusSlaveDataTable_0[index] = (_modbusSlaveBuffer[4] == 0xff );
_modbusSlaveBufferSize = 6;
_modbusSlaveSendTxBuffer();
return _modbusSlaveBufferSize + 2;
}
byte process_modbus_FC15( )
{
byte frameByte, bitsNo;
byte currentCoil, coil;
byte index;
int startCoil = word( _modbusSlaveBuffer[2], _modbusSlaveBuffer[3] );
int coilNo = word( _modbusSlaveBuffer[4], _modbusSlaveBuffer[5] );
bitsNo = 0;
frameByte = 7;
for (currentCoil = 0; currentCoil < coilNo; currentCoil++) {
coil = startCoil + currentCoil;
index = modbusSlaveIndexForAddres(coil, 0);
_modbusSlaveDataTable_0[index] = bitRead( _modbusSlaveBuffer[ frameByte ], bitsNo );
bitsNo ++;
if (bitsNo > 7) {
bitsNo = 0;
frameByte++;
}
}
_modbusSlaveBufferSize = 6;
_modbusSlaveSendTxBuffer();
return _modbusSlaveBufferSize + 2;
}
byte process_modbus_FC6()
{
int addres = word( _modbusSlaveBuffer[2], _modbusSlaveBuffer[3] );
int index;
index = modbusSlaveIndexForAddres(addres, 4);
_modbusSlaveDataTable_4[index] =word( _modbusSlaveBuffer[4], _modbusSlaveBuffer[5] );
_modbusSlaveBufferSize = 6;
_modbusSlaveSendTxBuffer();
return _modbusSlaveBufferSize + 2;
}
byte process_modbus_FC16( )
{
byte func = _modbusSlaveBuffer[1];
int startAddr = _modbusSlaveBuffer[2] << 8 | _modbusSlaveBuffer[3];
int byteRegsno = _modbusSlaveBuffer[4] << 8 | _modbusSlaveBuffer[5];
int i;
int index;
_modbusSlaveBuffer[4] = 0;
_modbusSlaveBuffer[5] = byteRegsno;
_modbusSlaveBufferSize = 6;
for (i = 0; i < byteRegsno; i++) {
index = modbusSlaveIndexForAddres((startAddr+i), 4);
_modbusSlaveDataTable_4[index] =word( _modbusSlaveBuffer[ 7 + i * 2 ], _modbusSlaveBuffer[8 + i * 2 ]);
}
_modbusSlaveSendTxBuffer();
return _modbusSlaveBufferSize +2;
}
если на пальцах то в первом регистре до запятой(целое число) а во втором после запятой?
тут в принципи есть еще один способ, умножить на 100 или на 10 а потом делить на это же число, только вот не помню там значение можно сохранить до 256... надо перечитать
если на пальцах то в первом регистре до запятой(целое число) а во втором после запятой?
тут в принципи есть еще один способ, умножить на 100 или на 10 а потом делить на это же число, только вот не помню там значение можно сохранить до 256... надо перечитать
а как быть с отрицательными?
Вы задаете глупые вопросы. Берите и передавайте как показано в примере. Там ОТРИЦАТЕЛЬНЫЕ флоат передаются.
если на пальцах то в первом регистре до запятой(целое число) а во втором после запятой?
тут в принципи есть еще один способ, умножить на 100 или на 10 а потом делить на это же число, только вот не помню там значение можно сохранить до 256... надо перечитать
а как быть с отрицательными?
Вы задаете глупые вопросы. Берите и передавайте как показано в примере. Там ОТРИЦАТЕЛЬНЫЕ флоат передаются.
очень много кода которого не понятно, если вы писали или понимаете все что там делается коментариев наставьте пожалуйсто или принцип расскажите
I would like to help me with my code. If i compile it without "master.query( telegram[0] ); // send query (only once)"
it works corectly. If i compile with it, it doesnt work and the serial print function not working at all.
TIA
#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 master(0,0,2); // 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;
const int switchOnePin = 2; // digital in 2 (pin the switch one is attached to)
const int switchTwoPin = 3; // digital in 3 (pin the switch two is attached to)
const int switchThreePin = 4; // digital in 4 (pin the switch three is attached to)
int switchOneState = 0; // current state of the switch
int lastSwitchOneState = 0; // previous state of the switch
int switchTwoState = 0;
int lastSwitchTwoState = 0;
int switchThreeState = 0;
int lastSwitchThreeState = 0;
void setup() {
//initialize serial communication at 9600 bits per second:
Serial.begin(9600);
// telegram[0].u8id = 1; // slave address
// telegram[0].u8fct = 5; // function code (this one is registers read)
// telegram[0].u16RegAdd = 0; // start address in slave
// telegram[0].u16CoilsNo = 2; // number of elements (coils or registers) to read
// telegram[0].au16reg = au16data; // pointer to a memory array in the Arduino
int switchOneState = 0; // current state of the switch
int lastSwitchOneState = 0; // previous state of the switch switch pins as an input
pinMode(switchOnePin, INPUT);
pinMode(switchTwoPin, INPUT);
pinMode(switchThreePin, INPUT);
}
void loop() {
master.poll(); // check incoming messages
if (master.getState() == COM_IDLE) {
u8state = 0;
u32wait = millis() + 1000; }
// read the switch input pins:
switchOneState = digitalRead(switchOnePin);
switchTwoState = digitalRead(switchTwoPin);
switchThreeState = digitalRead(switchThreePin);
// compare the switchState to its previous state
if (switchOneState != lastSwitchOneState) {
// if the state has changed, increment the counter
if (switchOneState == HIGH) {
// if the current state is HIGH then the button
// went from off to on:
master.query( telegram[0] ); // send query (only once)
Serial.println("Switch one is on");
} else {
// if the current state is LOW then the button
// went from on to off:
Serial.println("Switch one is off");
}
}
if (switchTwoState != lastSwitchTwoState) {
if (switchTwoState == HIGH) {
Serial.println("Switch two is on");
} else {
Serial.println("Switch two is off");
}
}
if (switchThreeState != lastSwitchThreeState) {
if (switchThreeState == HIGH) {
Serial.println("Switch three is on");
} else {
Serial.println("Switch thre is off");
}
}
// Delay a little bit to avoid bouncing
delay(50);
// save the current state as the last state,
//for next time through the loop
lastSwitchOneState = switchOneState;
lastSwitchTwoState = switchTwoState;
lastSwitchThreeState = switchThreeState;
}
да это я знаю:) я о том, что в моем посте такого не было. блин скидываешь людям код, где все с комментами, они их не читают
James это с Вашего поста #85
36
telegram[1].au16reg = au16data+4;
// pointer to a memory array in the Arduino
и из вашего примера я структуру подправил пакета, и разобрался чтобы мастер писал в 0 ячейку и слейв читал тоже с 0 ( по вашему примеру)
а вот эти строки просмотрел сам поражаюсь как, сори
а все, нашел:) извиняюсь, сам просмотрел
епсиль мопсиль, не моргает диод на слейве........ слов уже не хватает
что и как можно проверить?
Заметте, ваш скетч моргал, когда в телеграмме записи, код 6,начальный адрес слейва был 1. Сейчас 0. Может быть здесь собака зарыта?
нет нет слейв работает стабильно, а мастар не моргает
нашел тему разработчика библиотеки, изучаю по немного
http://forum.arduino.cc/index.php?topic=213432.15
Вставте в конец скетча вывод массива и следите за значениями при подключении слейва. Если изменятся - то всё в порядке. Ищите номера регистров, где потеря. Если нет то выкиньте из слейва au16data[16] и ещё раз попробуйте.
au16data[16] выкинул сразу
урааа, заработало!!!!!! незнаю точной причины но похоже помогло то что модули 485 местами поменял, возможно контакт был гдето не плотный
подровняю скетч, уберу все лишнее и выложу с коментариями для следующих кто будет мучаться с модбус
и так вот оно
пример мастера
слейв
работает так...
мастер посылает пакет слейву с рандомным значением или 0 или 1 и записано оно в au16data[0] = random(2);
слейв получает телеграмму и читает 0 регистр и включает и отключает 13 пин, а в ответом сообщении отправляет мастеру au16data[3] = random(2); (или 0 или 1)
и мастер читает ответ слейва и включает или отключает свой 13 пин
но есть одна проблемка
ждет ответа, но если ответ приходит то все равно ждет.... это косяк библиотеки?
Нет. Не косяк. Вам отдана вожможность запрограмировать реакцию на ошибки. Можно повторить пакет. Или не обрабатывать регистры.
в случае удачного ответа как приступить к отпрвке следующего пакета не дожидаясь конца setTimeOut()
пробовал так но не работает
никто не пользуется такой библиотекй?
Подскажите плиз, где я не прав.
2 нано соединены через конвертер rs485, схема соединения стандартная, взята с сети.
Мастер:
01
#include <SimpleModbusMaster.h>
02
//////////////////// Макроопределения портов и настройки программы ///////////////////
03
#define baud 9600 // скоростьобмена по последовательному интерфейсу. (UART)
04
#define timeout 1000 // Длительность ожидание ответа (таймаут modbus)
05
#define polling 300 // скорость опроса по modbus
06
#define retry_count 10 // количесво запросов modbus до ошибки и останова обмена
07
#define TxEnablePin 2 // Tx/Rx пин RS485
08
#define LED1 13 // светодиод 1
09
10
// Общая сумма доступной памяти на master устройстве, для хранения данных
11
// не забудьте изменить макроопределение TOTAL_NO_OF_REGISTERS. Если из слейва
12
// запрашиваешь 4 регистра, то тогда в массиве reg должно быть не меньше 4х ячеек
13
// для хранения полученных данных.
14
#define TOTAL_NO_OF_REGISTERS 4
15
16
// Масив пакетов modbus
17
// Для добавления новых пакетов просто добавте ихсюда
18
// сколько вам нужно.
19
enum
20
{
21
PACKET1,
22
PACKET2,
23
PACKET3,
24
PACKET4,
25
TOTAL_NO_OF_PACKETS
// эту строку неменять
26
};
27
28
// Масив пакетов модбус
29
Packet packets[TOTAL_NO_OF_PACKETS];
30
31
// Массив хранения содержимого принятых и передающихся регистров
32
unsigned
int
regs[TOTAL_NO_OF_REGISTERS];
33
34
void
setup
()
35
{
36
Serial
.begin(9600);
37
// Настраиваем пакеты
38
// Шестой параметр - это индекс ячейки в массиве, размещенном в памяти ведущего устройства, в которую будет
39
// помещен результат или из которой будут браться данные для передачи в подчиненное устройство. В нашем коде - это массив reg
40
41
// Пакет,SLAVE адрес,функция модбус,адрес регистра,количесво запрашиваемых регистров,локальный адрес регистра.
42
modbus_construct(&packets[PACKET1], 1, READ_HOLDING_REGISTERS, 0, 1, 0);
// чтение данных slave-master (slave адрес 1, регистр 0)
43
modbus_construct(&packets[PACKET2], 1, READ_HOLDING_REGISTERS, 1, 1, 1);
// чтение данных slave-master (slave адрес 1, регистр 1)
44
// Пакет,SLAVE адрес,функция модбус,адрес регистра,данные,локальный адрес регистра.
45
modbus_construct(&packets[PACKET3], 1, PRESET_MULTIPLE_REGISTERS, 2, 1, 2);
// запись данных master-slave (slave адрес 1, регистр 2)
46
modbus_construct(&packets[PACKET4], 1, PRESET_MULTIPLE_REGISTERS, 3, 1, 3);
// запись данных master-slave (slave адрес 1, регистр 3)
47
// инициализируем протокол модбус
48
modbus_configure(&
Serial
, baud, SERIAL_8N1, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs);
49
50
pinMode(LED1, OUTPUT);
51
52
}
// конец void setup()
53
54
void
loop
()
55
{
56
modbus_update();
// запуск обмена по Modbus
57
58
//Serial.println(regs[0]);
59
60
regs[2] = 20;
// запись данных master-slave (slave адрес 1, регистр 2), запись константы
61
regs[3] = 20;
62
63
if
(regs[0] == 30)
64
{
65
digitalWrite(LED1, HIGH);
// turn the LED on (HIGH is the voltage level)
66
delay(1000);
// wait for a second
67
digitalWrite(LED1, LOW);
// turn the LED off by making the voltage LOW
68
delay(1000);
// wait for a second
69
}
70
else
71
{
72
digitalWrite(LED1, HIGH);
// turn the LED on (HIGH is the voltage level)
73
delay(250);
// wait for a second
74
digitalWrite(LED1, LOW);
// turn the LED off by making the voltage LOW
75
delay(250);
76
}
77
78
}
// конец void loop()/*
Слейв:
01
#include <SimpleModbusSlave.h>
02
//////////////////// Макроопределения портов и настройки программы ///////////////////
03
#define TxEnablePin 2 // Tx/Rx пин RS485
04
#define baud 9600 // скоростьобмена по последовательному интерфейсу. (UART)
05
#define timeout 1000 // Длительность ожидание ответа (таймаут modbus)
06
#define polling 300 // скорость опроса по modbus
07
#define retry_count 10 // количесво запросов modbus до ошибки и останова обмена
08
#define Slave_ID 1 // Адрес Slave устройсва
09
#define LED1 13 // светодиод 1
10
//const int buttonPin = 3; // номер входа, подключенный к кнопке
11
// переменные
12
int
buttonState = 0;
// переменная для хранения состояния кнопки
13
14
15
//////////////// Регистры вашего Slave ///////////////////
16
enum
17
{
18
//Просто добавьте или удалите регистры. Первый регистр начинается по адресу 0
19
slave_to_master_val_1,
// с адресом массива 0
20
slave_to_master_val_2,
// с адресом массива 1
21
master_to_slave_val_1,
// с адресом массива 2
22
master_to_slave_val_2,
// с адресом массива 3
23
HOLDING_REGS_SIZE
// Это не удалять размер массива HOLDING_REGS.
24
//общее количество регистров для функции 3 и 16 разделяет тотже самый массив регистров
25
//т.е. то же самое адресное пространство
26
};
27
unsigned
int
holdingRegs[HOLDING_REGS_SIZE];
// функции 3 и 16 массив регистров
28
////////////////////////////////////////////////////////////
29
30
void
setup
()
31
{
32
/* parameters(HardwareSerial* SerialPort,long baudrate,unsigned char byteFormat,unsigned char ID,
33
unsigned char transmit enable pin,unsigned int holding registers size,unsigned int* holding register array)
34
SERIAL_8N2: 1 start bit, 8 data bits, 2 stop bits
35
SERIAL_8E1: 1 start bit, 8 data bits, 1 Even parity bit, 1 stop bit
36
SERIAL_8O1: 1 start bit, 8 data bits, 1 Odd parity bit, 1 stop bit
37
SERIAL_8N1 option
38
*/
39
40
Serial
.begin(9600);
41
modbus_configure(&
Serial
, baud, SERIAL_8N1, Slave_ID, TxEnablePin, HOLDING_REGS_SIZE, holdingRegs);
42
modbus_update_comms(baud, SERIAL_8N1, 1);
43
pinMode(LED1, OUTPUT);
44
digitalWrite(LED1, LOW);
45
46
}
// конец void setup()
47
48
void
loop
()
49
{
50
int
temp;
51
52
temp=30;
53
54
modbus_update();
// запуск обмена по Modbus
55
56
holdingRegs[slave_to_master_val_1] = temp;
// запись данных slave-master
57
// (регистр 0), значение из аналогового входа 0.
58
holdingRegs[slave_to_master_val_2] = temp;
// запись данных slave-master
59
// (регистр 1), запись значения переменной temp. по нажатию кнопки.
60
61
if
(holdingRegs[master_to_slave_val_2] == 20)
62
{
63
digitalWrite(LED1, HIGH);
// turn the LED on (HIGH is the voltage level)
64
delay(1000);
// wait for a second
65
digitalWrite(LED1, LOW);
// turn the LED off by making the voltage LOW
66
delay(1000);
// wait for a second
67
}
68
else
69
{
70
digitalWrite(LED1, HIGH);
// turn the LED on (HIGH is the voltage level)
71
delay(250);
// wait for a second
72
digitalWrite(LED1, LOW);
// turn the LED off by making the voltage LOW
73
delay(250);
74
}
75
//Serial.println(holdingRegs[master_to_slave_val_2]);
76
}
// конец void loop()
Суть: мастер передает число 20 слейву. Если это число получено, то мигаем 13 пином раз в секунду, если нет такого числа - мигает в 4 раза чаще. И в свою очередь слейв должен ответить мастеру, послав число 30. Если такое число получено\неполучено выполняется аналогичный сценарий с миганием светика.
Итог - ни мастер ни слейв ничего не шлет.
с этой библиотекой я так и не разобрался, поэтому не подскажу,
на #include <ModbusRtu.h> смог бы помочь, но тут есть один небольшой косяк библиотеки, уть вышеписал про него
Попробовал соеднить по этой схеме: http://arrduinolab.blogspot.ru/2015/02/arduino-rs485-2.html
Ардуинки заговорили. Но мне нужен modbus.
На буржуйском форуме рекомендовали притянуть 10к резистором rx к vcc. Сделал, все так же, молчат.
В сериал слейва появляется значение 8L, в мастере - ромбики.
с этой библиотекой я так и не разобрался, поэтому не подскажу,
на #include <ModbusRtu.h> смог бы помочь, но тут есть один небольшой косяк библиотеки, уть вышеписал про него
Вы не разобрались с master.setTimeOut( 500 ) ?
Нет. Не косяк. Вам отдана вожможность запрограмировать реакцию на ошибки. Можно повторить пакет. Или не обрабатывать регистры.
Здравствуйте.
Не подскажите как быть с:
Благодарю
так и оставить, если мало то сделать больше. там вроде коммент есть.
так и оставить, если мало то сделать больше. там вроде коммент есть.
Загрузил скетчи из 110 поста. Слейв моргает 13 пином, мастер не хочет.
Если мастер отключаю, то слейв замолкает.
не пойму почему.
Вообще в конец запутался.
Пробую все на связке китайских Uno (мастер) и nano (слейв). Скетчи из поста 110.
Мастер не мигает, слейв мигает. Меняю uno на nano. Скетчи те же. Вуаля, и мастер и слейв замигали. 2 раза пробовал так менять - результат один и тот же (на уно не хочет мигать).
Для проверки 13 пина загрузил на уно стандартный скетч blink - мигает.
ну вот, у меня на nano все нормально работает. Может в uno косяк какой
ну вот, у меня на nano все нормально работает. Может в uno косяк какой
Блин, мне как раз uno + w5100 нужна была для проекта. Но все же есть прогресс.
Не подскажите как можно сделать:
- мастер передает информацию (время: часы 24-часовой формат и минуты), слейв забирает эту информацию себе, в свою очередь отсылает мастеру значение температуры (целое число, возможно и отрицательное)
Мне понять бы принцип разговора на примере.
Благодарю.
ну вот вместо ваших "20" и "30" отправляете дату и температуру соответственно. при получении даты, сохраняем её в переменную на слэйве. и после этого отправляет "30"- т.е. температуру которую мастер себе записывает.
ну вот вместо ваших "20" и "30" отправляете дату и температуру соответственно. при получении даты, сохраняем её в переменную на слэйве. и после этого отправляет "30"- т.е. температуру которую мастер себе записывает.
У меня код как в 110 посте:
мастер
Слейв
Не могу понять эти регистры.
87
raz = au16data[3];
// пытаюсь прочитать ответ от слейва из 3 регистра от слейва
88
if
( raz == 0) state = LOW ;
else
state = HIGH;
89
digitalWrite(pin, state);
// если что то больше 0 то включить 13 пин
90
// digitalWrite(pin, au16dataR[3]);// тек как у нас приходит или 0 или 1 , можно и так моргать светодеодом на 13 пине
91
au16data[0] = random(2);
// запишим в 0 регистр пакета или 0 или 1 для отправки слейву
92
//-------------------------
93
}
94
break
;
95
}
96
}
и
46
vP1 = au16data[0];
// читаем 0 регистр телеграммы и пишим в переменную
47
if
( vP1 ==0) state = LOW;
else
state= HIGH;
// если переменная равна 0 то запишим в переменную state выключить 13 пин иначи включим
48
digitalWrite(pin, state);
// вкл или выкл
49
// заполним все регисты для отправки мастеру в ответ на запрос
50
// au16data[1] = 0;
51
// au16data[2] = 256;
52
au16data[3] = random(2);
// запишем в регистр телеграммы №4 или 0 или 1 для отправки в ответе на запос мастера
53
}
54
}
вот эти куски и отвечают за содержание регистров
Благодарю.
Это я понял.
А как указать количество используемых регистров, сколько их может быть, какой диапазон присваиваемых значений и как быть с отрицательными значениями?
uint16_t au16data[16];
// массив данных для совместного использования сети Modbus
вот ваша строка, там 3 идут служебные
uint16_t au16data[16];
// массив данных для совместного использования сети Modbus
вот ваша строка, там 3 идут служебные
1. Я могу создать 16 регистров? au16data[0] - au16data[15]
2. каждый регистр может привоить значения 0-255 ?
8-10 заняты отладочной информацией, по самому протоколу
но в библиотеке они так не разделены, по этому использовать можно все по максимуму
Честно, я вот это не могу понять:
В двух словах можно, о чем здесь?
ну это описание видов данных в протоколе. На самом деле библиотека реализованна так, что все являются Holding Registers — 16-битовый знаковый или беззнаковый тип, доступен для чтения и записи. Что такое "бит"-ы я думаю объяснять не нужно?
ну а если в вики лень искать то вот
-32768
+32767
где 16 -количество бит, 2- в байтах, 1/2-в машинных словах, 655535- максимальное значение беззнаковой переменной, -32768 мин значение знаковой переменной и 32768 максимальное значение знаковой переменной
ну это описание видов данных в протоколе. На самом деле библиотека реализованна так, что все являются Holding Registers — 16-битовый знаковый или беззнаковый тип, доступен для чтения и записи. Что такое "бит"-ы я думаю объяснять не нужно?
ну а если в вики лень искать то вот
-32768
+32767
где 16 -количество бит, 2- в байтах, 1/2-в машинных словах, 655535- максимальное значение беззнаковой переменной, -32768 мин значение знаковой переменной и 32768 максимальное значение знаковой переменной
Спасибо большое.
Именно здесь у меня нестыковочка была. Читаю описание modbus - там есть перечисленные выше регистры, в Modbusrtu.h - нет. Теперь понятно.
Как думаете, стОит с ModbusRtu.h "завязывать отношения" или другую пытать?
ну мне в принципе хватает, я её используй в связке с ОРС сервером на компьютере и он прекрасно его понимает
ну мне в принципе хватает, я её используй в связке с ОРС сервером на компьютере и он прекрасно его понимает
Как думаете, для моей задачи она пойдет:
Задача: несколько ардуинок, каждая выполняет свою задачу - слейвы. Но нужно иметь посредника между ними - мастер. Он забирает со слейва\слейвов информацию, обрабатывает кодом и передает другим слейвам или передает вышестоящему устройству. Например, часы реального времени. Время нужно еще паре модулям. Можно конечно поставить на каждый по отдельному модулю часов, но это как то не по феншую будет. Также мастер должен будет передавать эту информацию (температура, включение вентиляции) в majordomo (по MQTT или Modbus TCP).
Поверьте мне, я не хочу делать систему, типа "с любой точки мира могу включить свет в сортире". Мне удобнее будет тыкнуть свет в выключатель. А вот если идет критическое снижение температуры в погребе, тут система должна включить меры поддержания температуры и мне об этом сообщить, чтобы я проконтролировал этот процесс, в свою очередь тоже принял меры.
С ESP8266 у меня отношения никак не могут сложиться.
а почему нет, это всего лишь библиотека, если что-то не устроит, её можно переписать уже под себя. время как по мне лучше записывать один раз, а потом корректировать периодически. есть такая штука, как USB- RS485 переходник. я с помощью него завожу все в комп. витой пары хватает с головой на свять и питание +24 +12 и +5 для устройств
а почему нет, это всего лишь библиотека, если что-то не устроит, её можно переписать уже под себя. время как по мне лучше записывать один раз, а потом корректировать периодически. есть такая штука, как USB- RS485 переходник. я с помощью него завожу все в комп. витой пары хватает с головой на свять и питание +24 +12 и +5 для устройств
благодарю.
Может кому пригодится. Долго мучался, но получилось передавать температуру по rs485. Создал мастер и слейв.
Библиотека никакая не используется. Вернее сделал свою библиотеку чел, который создал FLprog. С помощью этой программы и создается модбас в моих скетчах. Здесь идет правильное разделение по регистрам модбаса (Coils, Holding registers и т.д.).
Мастер
-опрашивает от слейва 4 температуры
- отдает слейву две переменные (состояние кнопки (boolean) на мастере и просто int переменную с числом, так для ознакомелния, что можно передавать integer).
-Светит встроенным диодом в зависимости от состояния кнопки на слейве.
Слейв
-замеряет 4 температуры датчиками DS18B20 и отправляет мастеру
- Светит встроенным диодом в зависимости от состояния кнопки на мастере.
-Получает число от мастера (просто переменную integer).
-Также отдаёт мастеру данные о своей кнопке.
Код мастера
Код слейва
вернулся к старой теме, так как начал собирать все наработки в кучку, вот и пришло время добавить RS485.
еще раз перечитал все и понял что не знаю как передать отрицательное число (-11.5), и флоат (температуру 24.5)
а по поводу master.setTimeOut решил забить на него ( относится к посту № #112)
А как указать количество используемых регистров, сколько их может быть, какой диапазон присваиваемых значений и как быть с отрицательными значениями?
кто как передает в модбас протоколе?
#137 почитайте. Можно легко и отрицательные передавать
флоат передаётся, используется при этом два регистра Holding Registers модбаса
вот примеры
мастер
слейв
если на пальцах то в первом регистре до запятой(целое число) а во втором после запятой?
тут в принципи есть еще один способ, умножить на 100 или на 10 а потом делить на это же число, только вот не помню там значение можно сохранить до 256... надо перечитать
а как быть с отрицательными?
Ну для минуса третий регистр заведите )))
ПС. продолжаем жрать кактус...
ммммм вкусно ))) но колится зараза __--))))
и так их жалко ( 15 штук всего)
если на пальцах то в первом регистре до запятой(целое число) а во втором после запятой?
тут в принципи есть еще один способ, умножить на 100 или на 10 а потом делить на это же число, только вот не помню там значение можно сохранить до 256... надо перечитать
а как быть с отрицательными?
Вы задаете глупые вопросы. Берите и передавайте как показано в примере. Там ОТРИЦАТЕЛЬНЫЕ флоат передаются.
если на пальцах то в первом регистре до запятой(целое число) а во втором после запятой?
тут в принципи есть еще один способ, умножить на 100 или на 10 а потом делить на это же число, только вот не помню там значение можно сохранить до 256... надо перечитать
а как быть с отрицательными?
очень много кода которого не понятно, если вы писали или понимаете все что там делается коментариев наставьте пожалуйсто или принцип расскажите
Так как ,все же, передать отрицательное число в примере #110
Добрый день!
А есть пример работы с несколькими слейвами?
Dear friend, Greetings from Hellas.
I would like to help me with my code. If i compile it without "master.query( telegram[0] ); // send query (only once)"
it works corectly. If i compile with it, it doesnt work and the serial print function not working at all.
TIA
misterno, Modbus IS a kind of serial communication, you can't either transfer and debug via Serial simultaneously. Use SoftwareSerial instead.
Dear friend @Voodoo Doll, thank you for reply.
I used LED outputs instead of serial messages with the DigitalWrite(pin HIGH); command with the same results.
Is there anyway to control the modbus commands (Run, Stop, etc) to my VFD with toggle switches? An example code would be appreciated.