Modbus RTU

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

да это я знаю:) я о том, что в моем посте такого не было. блин скидываешь людям код, где все с комментами, они их не читают

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

James это с Вашего поста #85  

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

и из вашего примера я структуру подправил пакета, и разобрался чтобы мастер писал в 0 ячейку и слейв читал тоже с 0 ( по вашему примеру)

а вот эти строки просмотрел сам поражаюсь как, сори

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

а все, нашел:) извиняюсь, сам просмотрел

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

епсиль мопсиль, не моргает диод на слейве........ слов уже не хватает

что и как можно проверить?

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

Заметте, ваш скетч моргал, когда в телеграмме записи, код 6,начальный адрес слейва был 1. Сейчас  0. Может быть здесь собака зарыта?

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

нет нет слейв работает стабильно, а мастар не моргает

нашел тему разработчика библиотеки, изучаю по немного

http://forum.arduino.cc/index.php?topic=213432.15

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

Вставте в конец скетча вывод массива и следите за значениями при подключении слейва. Если изменятся - то всё в порядке. Ищите номера регистров, где потеря. Если нет то выкиньте из слейва au16data[16] и ещё раз попробуйте.

 

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

au16data[16] выкинул сразу

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

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

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

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

и так вот оно

пример мастера

/**
подключение
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 мс, пролонгировать,

ждет ответа, но если ответ приходит то все равно ждет.... это косяк библиотеки?

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

Нет. Не косяк. Вам отдана вожможность запрограмировать реакцию на ошибки. Можно повторить пакет. Или не обрабатывать регистры. 

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

в случае удачного  ответа как приступить к отпрвке следующего пакета не дожидаясь конца 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;
 }
}

никто не пользуется такой библиотекй?

yden
Offline
Зарегистрирован: 30.01.2016

Подскажите плиз, где я не прав.

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. Если такое число получено\неполучено выполняется аналогичный сценарий с миганием светика.

Итог - ни мастер ни слейв ничего не шлет.

 

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

с этой библиотекой я так и не разобрался, поэтому не подскажу, 

на #include <ModbusRtu.h> смог бы помочь, но тут есть один небольшой косяк библиотеки, уть вышеписал про него

yden
Offline
Зарегистрирован: 30.01.2016

Попробовал соеднить по этой схеме: http://arrduinolab.blogspot.ru/2015/02/arduino-rs485-2.html

Ардуинки заговорили. Но мне нужен modbus.

На буржуйском форуме рекомендовали притянуть 10к резистором rx к vcc. Сделал, все так же, молчат.

В сериал слейва появляется значение 8L, в мастере - ромбики.

yden
Offline
Зарегистрирован: 30.01.2016

Baks пишет:

с этой библиотекой я так и не разобрался, поэтому не подскажу, 

на #include <ModbusRtu.h> смог бы помочь, но тут есть один небольшой косяк библиотеки, уть вышеписал про него

Вы не разобрались с master.setTimeOut( 500 ) ?

yden
Offline
Зарегистрирован: 30.01.2016

nik182 пишет:

Нет. Не косяк. Вам отдана вожможность запрограмировать реакцию на ошибки. Можно повторить пакет. Или не обрабатывать регистры. 

Здравствуйте.

Не подскажите как быть с:

 master.setTimeOut( 500 ); // if there is no answer in 5000 ms, roll over,если нет ответа в 5000 мс, пролонгировать,

 

Благодарю

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

так и оставить, если мало то сделать больше. там вроде коммент есть.

yden
Offline
Зарегистрирован: 30.01.2016

James пишет:

так и оставить, если мало то сделать больше. там вроде коммент есть.

Загрузил скетчи из 110 поста. Слейв моргает 13 пином, мастер не хочет.

Если мастер отключаю, то слейв замолкает. 

не пойму почему.

yden
Offline
Зарегистрирован: 30.01.2016

Вообще в конец запутался.

Пробую все на связке китайских Uno (мастер) и nano (слейв). Скетчи из поста 110.

Мастер не мигает, слейв мигает. Меняю uno на nano. Скетчи те же. Вуаля, и мастер и слейв замигали. 2 раза пробовал так менять - результат один и тот же (на уно не хочет мигать).

Для проверки 13 пина загрузил на уно стандартный скетч blink - мигает.

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

ну вот, у меня на nano все нормально работает. Может в uno косяк какой

yden
Offline
Зарегистрирован: 30.01.2016

James пишет:

ну вот, у меня на nano все нормально работает. Может в uno косяк какой

Блин, мне как раз uno + w5100 нужна была для проекта. Но все же есть прогресс. 

Не подскажите как можно сделать:

- мастер передает информацию (время: часы 24-часовой формат и минуты), слейв забирает эту информацию себе, в свою очередь отсылает мастеру значение температуры (целое число, возможно и отрицательное)

Мне понять бы принцип разговора на примере. 

Благодарю.

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

ну вот вместо ваших "20" и "30" отправляете дату и температуру соответственно. при получении даты, сохраняем её в переменную на слэйве. и после этого отправляет "30"- т.е. температуру которую мастер себе записывает. 

yden
Offline
Зарегистрирован: 30.01.2016

James пишет:

ну вот вместо ваших "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 для отправки в ответе на запос мастера
 }  
}

Не могу понять эти регистры.

James
Offline
Зарегистрирован: 26.02.2016
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

}

 

вот эти куски и отвечают за содержание регистров

yden
Offline
Зарегистрирован: 30.01.2016

Благодарю.

Это я понял.

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

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

 

uint16_t au16data[16]; // массив данных для совместного использования сети Modbus
 

вот ваша строка, там 3 идут служебные

yden
Offline
Зарегистрирован: 30.01.2016

James пишет:

 

uint16_t au16data[16]; // массив данных для совместного использования сети Modbus
 

вот ваша строка, там 3 идут служебные

1. Я могу создать 16 регистров? au16data[0] - au16data[15]

2. каждый регистр может привоить значения 0-255 ?

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

8-10 заняты отладочной информацией, по самому протоколу

  • Discrete Inputs — однобитовый тип, доступен только для чтения.
  • Coils — однобитовый тип, доступен для чтения и записи.
  • Input Registers — 16-битовый знаковый или беззнаковый тип, доступен только для чтения.
  • Holding Registers — 16-битовый знаковый или беззнаковый тип, доступен для чтения и записи.
    но в библиотеке они так не разделены, по этому использовать можно все по максимуму
yden
Offline
Зарегистрирован: 30.01.2016

Честно, я вот это не могу понять:

 

  • Discrete Inputs — однобитовый тип, доступен только для чтения.
  • Coils — однобитовый тип, доступен для чтения и записи.
  • Input Registers — 16-битовый знаковый или беззнаковый тип, доступен только для чтения.
  • Holding Registers — 16-битовый знаковый или беззнаковый тип, доступен для чтения и записи.

В двух словах можно, о чем здесь?

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

ну это описание видов данных в протоколе. На самом деле библиотека реализованна так, что все являются Holding Registers — 16-битовый знаковый или беззнаковый тип, доступен для чтения и записи. Что такое "бит"-ы я думаю объяснять не нужно? 
ну а если в вики лень искать то вот 

16 2 ½ 65535
-32768
+32767

где 16 -количество бит, 2- в байтах, 1/2-в машинных словах, 655535- максимальное значение беззнаковой переменной, -32768 мин значение знаковой переменной и 32768 максимальное значение знаковой переменной

yden
Offline
Зарегистрирован: 30.01.2016

James пишет:

ну это описание видов данных в протоколе. На самом деле библиотека реализованна так, что все являются Holding Registers — 16-битовый знаковый или беззнаковый тип, доступен для чтения и записи. Что такое "бит"-ы я думаю объяснять не нужно? 
ну а если в вики лень искать то вот 

16 2 ½ 65535
-32768
+32767

где 16 -количество бит, 2- в байтах, 1/2-в машинных словах, 655535- максимальное значение беззнаковой переменной, -32768 мин значение знаковой переменной и 32768 максимальное значение знаковой переменной

Спасибо большое.

Именно здесь у меня нестыковочка была. Читаю описание modbus - там есть перечисленные выше регистры, в Modbusrtu.h - нет. Теперь понятно.

Как думаете, стОит с ModbusRtu.h "завязывать отношения" или другую пытать?

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

ну мне в принципе хватает, я её используй в связке с ОРС сервером на компьютере и он прекрасно его понимает

yden
Offline
Зарегистрирован: 30.01.2016

James пишет:

ну мне в принципе хватает, я её используй в связке с ОРС сервером на компьютере и он прекрасно его понимает

Как думаете, для моей задачи она пойдет:

Задача: несколько ардуинок, каждая выполняет свою задачу - слейвы. Но нужно иметь посредника между ними - мастер. Он забирает со слейва\слейвов информацию, обрабатывает кодом и передает другим слейвам или передает вышестоящему устройству. Например, часы реального времени. Время нужно еще паре модулям. Можно конечно поставить на каждый по отдельному модулю часов, но это как то не по феншую будет. Также мастер должен будет передавать эту информацию (температура, включение вентиляции) в majordomo (по MQTT или Modbus TCP).

Поверьте мне, я не хочу делать систему, типа "с любой точки мира могу включить свет в сортире". Мне удобнее будет тыкнуть свет в выключатель. А вот если идет критическое снижение температуры в погребе, тут система должна включить меры поддержания температуры и мне об этом сообщить, чтобы я проконтролировал этот процесс, в свою очередь тоже принял меры. 

С ESP8266 у меня отношения никак не могут сложиться.

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

а почему нет, это всего лишь библиотека, если что-то не устроит, её можно переписать уже под себя. время как по мне лучше записывать один раз, а потом корректировать периодически. есть такая штука, как USB- RS485 переходник. я с помощью него завожу все в комп. витой пары хватает с головой на свять и питание +24 +12 и +5 для устройств

yden
Offline
Зарегистрирован: 30.01.2016

James пишет:

а почему нет, это всего лишь библиотека, если что-то не устроит, её можно переписать уже под себя. время как по мне лучше записывать один раз, а потом корректировать периодически. есть такая штука, как USB- RS485 переходник. я с помощью него завожу все в комп. витой пары хватает с головой на свять и питание +24 +12 и +5 для устройств

благодарю.

MaksVV
Offline
Зарегистрирован: 06.08.2015

Может кому пригодится. Долго мучался, но получилось передавать температуру по 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;
}

 

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

вернулся к старой теме, так как начал собирать все наработки в кучку, вот и пришло время добавить RS485.

еще раз перечитал все и понял что не знаю как передать отрицательное число (-11.5), и флоат (температуру 24.5)

а по поводу master.setTimeOut решил забить на него ( относится к посту № #112)

yden пишет:

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

кто как передает в модбас протоколе?

MaksVV
Offline
Зарегистрирован: 06.08.2015

#137 почитайте. Можно легко и отрицательные передавать

флоат передаётся, используется при этом два регистра Holding Registers модбаса

MaksVV
Offline
Зарегистрирован: 06.08.2015

вот примеры

мастер 

//   MASTER 
struct _savTWstr {uint16_t w1; uint16_t w2;};
_savTWstr _savTWstrTemp;
int _modbusMasterDataTable_4_reg_1[4];
int _modbusMasterAddressTable_4_reg_1[4] = {0, 1, 2, 3};
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[] = {3};
const unsigned char _modbusMaster_fctsupported[] = {3, 6, 16};
float TemperaturaMaster = -10.5;
float TemperaturaSlave;
void setup()
{
Serial.begin(9600);
pinMode(4, OUTPUT);
digitalWrite(4, LOW);
for(int i=0; i<1; i++) {_startTimeMasterRegs[i] =  millis();}
}
void loop()
{float _tempVariable_float;





// Запись температуры float (причём отрицательное значение) в два регистра (2,3) Holding Registers модбаса 
_tempVariable_float = TemperaturaMaster;
if (! (_tempVariable_float == ( (float(_readFloatFromModbus(_modbusMasterDataTable_4_reg_1[2], _modbusMasterDataTable_4_reg_1[3])))))) {_readWriteMasterVars[0] = 16; };
_savTWstrTemp = _saveFloatToModbus(_tempVariable_float);
_modbusMasterDataTable_4_reg_1[2] = _savTWstrTemp.w1;
_modbusMasterDataTable_4_reg_1[3] = _savTWstrTemp.w2;

// Чтение температуры float из двух регистров (0,1) Holding Registers модбаса 

TemperaturaSlave = (float(_readFloatFromModbus(_modbusMasterDataTable_4_reg_1[0], _modbusMasterDataTable_4_reg_1[1])));




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));}
  }
struct  _savTWstr _saveFloatToModbus( float value)
{ _savTWstr result;

byte b;
b=*(((byte*)&value) + 0 );
for(byte i = 0; i < 8; i++) bitWrite(result.w2,i,bitRead(b, i));
b=*(((byte*)&value) + 1 );
 for(byte i = 0; i < 8; i++) bitWrite(result.w2,i+8, bitRead(b, i));
b=*(((byte*)&value) + 2 );
for(byte i = 0; i < 8; i++) bitWrite(result.w1,i,bitRead(b, i));
b=*(((byte*)&value) + 3 );
for(byte i = 0; i < 8; i++) bitWrite(result.w1,i+8,bitRead(b, i));
 return result ;}
float _readFloatFromModbus(uint16_t w1,  uint16_t w2)
{
byte b[4];
for(byte i = 0; i < 8; i++) bitWrite(b[0],i,bitRead(w2, i));
for(byte i = 0; i < 8; i++) bitWrite(b[1],i,bitRead(w2,(i+8)));
for(byte i = 0; i < 8; i++) bitWrite(b[2],i,bitRead(w1, i));
 for(byte i = 0; i < 8; i++) bitWrite(b[3],i,bitRead(w1,(i+8)));
 return  *((float *)&b);
}
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 = 2;
 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 = 3;
_modbusTelegramm.startAddres = 0;
_modbusTelegramm.numbeRegs = 2;
_modbusTelegramm.valueIndex = 0;
break;
case 2:
_modbusTelegramm.function = _readWriteMasterVars[0];
_modbusTelegramm.startAddres = 2;
_modbusTelegramm.numbeRegs = 2;
_modbusTelegramm.valueIndex = 2;
_readWriteMasterVars[0] = 3;
break;
}
break;
}
}
void _modbusMasterSendQuery()
{
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 3:
 _modbusMasterBuffer[4] = highByte(_modbusTelegramm.numbeRegs );
      _modbusMasterBuffer[5] = lowByte( _modbusTelegramm.numbeRegs );
      _modbusMasterBufferSize = 6;
      break;
 case 16:
      _modbusMasterBuffer[4]      = highByte(_modbusTelegramm.numbeRegs );
      _modbusMasterBuffer[5]      = lowByte( _modbusTelegramm.numbeRegs );
      _modbusMasterBuffer[6]    = (uint8_t) ( _modbusTelegramm.numbeRegs * 2 );
      _modbusMasterBufferSize = 7;
      for (byte i = 0; i < _modbusTelegramm.numbeRegs; i++) {
      switch ( _modbusMasterCurrentReg ) {
case 1 :
intTemp = _modbusMasterDataTable_4_reg_1[currentIndex];
break;
}
        _modbusMasterBuffer[ _modbusMasterBufferSize ] = highByte( intTemp);
        _modbusMasterBufferSize++;
        _modbusMasterBuffer[ _modbusMasterBufferSize ] = lowByte(intTemp);
        _modbusMasterBufferSize++;
        currentIndex++;
      }
      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 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_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;
  } 
}

 

слейв 

// Slave 


struct _savTWstr {uint16_t w1; uint16_t w2;};
_savTWstr _savTWstrTemp;
int _modbusSlaveDataTable_4[4];
int _modbusSlaveAddresTable_4[4] = {0, 1, 2, 3};
byte _modbusSlaveBufferSize = 0;
byte _modbusSlaveLastRec = 0;
long _modbusSlaveTime;
byte _modbusSlaveBuffer[64];
const unsigned char _modbusSlave_fctsupported[] = {3, 6, 16};
float TemperaturaMaster;
float TemperaturaSlave = -5.4;
void setup()
{
Serial.begin(9600);
pinMode(4, OUTPUT);
digitalWrite(4, LOW);
}
void loop()
{_modbusSlavePoll();





//запись температуры слейва в регистры 0,1 Holding Registers модбаса 
_savTWstrTemp = _saveFloatToModbus(TemperaturaSlave);
_modbusSlaveDataTable_4[0] = _savTWstrTemp.w1;
_modbusSlaveDataTable_4[1] = _savTWstrTemp.w2;



//чтение в переменную TemperaturaMaster из регистров 2,3 Holding Registers модбаса 
TemperaturaMaster = (float(_readFloatFromModbus(_modbusSlaveDataTable_4[2], _modbusSlaveDataTable_4[3])));




}
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));}
  }
struct  _savTWstr _saveFloatToModbus( float value)
{ _savTWstr result;

byte b;
b=*(((byte*)&value) + 0 );
for(byte i = 0; i < 8; i++) bitWrite(result.w2,i,bitRead(b, i));
b=*(((byte*)&value) + 1 );
 for(byte i = 0; i < 8; i++) bitWrite(result.w2,i+8, bitRead(b, i));
b=*(((byte*)&value) + 2 );
for(byte i = 0; i < 8; i++) bitWrite(result.w1,i,bitRead(b, i));
b=*(((byte*)&value) + 3 );
for(byte i = 0; i < 8; i++) bitWrite(result.w1,i+8,bitRead(b, i));
 return result ;}
float _readFloatFromModbus(uint16_t w1,  uint16_t w2)
{
byte b[4];
for(byte i = 0; i < 8; i++) bitWrite(b[0],i,bitRead(w2, i));
for(byte i = 0; i < 8; i++) bitWrite(b[1],i,bitRead(w2,(i+8)));
for(byte i = 0; i < 8; i++) bitWrite(b[2],i,bitRead(w1, i));
 for(byte i = 0; i < 8; i++) bitWrite(b[3],i,bitRead(w1,(i+8)));
 return  *((float *)&b);
}
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 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 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 4:
tableSize = 4;
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 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_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_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;
}

 

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

если на пальцах то в первом регистре до запятой(целое число) а во втором после запятой?

тут в принципи есть еще один способ, умножить на 100 или на 10 а потом делить на это же число, только вот не помню там значение можно сохранить до 256... надо перечитать

а как быть с отрицательными?

 

Logik
Offline
Зарегистрирован: 05.08.2014

Ну для минуса третий регистр заведите )))

ПС. продолжаем жрать кактус...

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

ммммм вкусно ))) но колится зараза  __--))))

и так их жалко ( 15 штук всего)

MaksVV
Offline
Зарегистрирован: 06.08.2015

Baks пишет:

если на пальцах то в первом регистре до запятой(целое число) а во втором после запятой?

тут в принципи есть еще один способ, умножить на 100 или на 10 а потом делить на это же число, только вот не помню там значение можно сохранить до 256... надо перечитать

а как быть с отрицательными?

 


Вы задаете глупые вопросы. Берите и передавайте как показано в примере. Там ОТРИЦАТЕЛЬНЫЕ флоат передаются.

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

MaksVV пишет:
Baks пишет:

если на пальцах то в первом регистре до запятой(целое число) а во втором после запятой?

тут в принципи есть еще один способ, умножить на 100 или на 10 а потом делить на это же число, только вот не помню там значение можно сохранить до 256... надо перечитать

а как быть с отрицательными?

 

Вы задаете глупые вопросы. Берите и передавайте как показано в примере. Там ОТРИЦАТЕЛЬНЫЕ флоат передаются.

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

stboris
Offline
Зарегистрирован: 12.04.2015

Так как ,все же, передать отрицательное число  в примере #110

pwal
Offline
Зарегистрирован: 17.04.2016

Добрый день!

А есть пример работы с несколькими слейвами?

misterno
Offline
Зарегистрирован: 13.06.2018

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


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

 

Voodoo Doll
Voodoo Doll аватар
Offline
Зарегистрирован: 18.09.2016

misterno, Modbus IS a kind of serial communication, you can't either transfer and debug via Serial simultaneously. Use SoftwareSerial instead.

misterno
Offline
Зарегистрирован: 13.06.2018

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.