Arduino Modbus RTU

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
Добрый день!
Помогите разобраться в проблеме получения ответа от устройства:
Устройство принимает и обрабатывает полученные данные, в ответ шлет тоже (смотрел ноутом при помощи USB-RS485 преобразователем)

Проблем в том, что я не пойму как мне получить ответ на ардуино и его обработать

C++:
#include <SoftwareSerial.h>

SoftwareSerial RS485(36, 34); // RX, TX

uint8_t crc16storage[2];
char rs485_buffer[8];

void CRC16ModbusCalc(uint8_t  frame[], uint8_t len, uint8_t  crc16stor[]){
  uint16_t crcReg = 0xFFFF;
  for (uint8_t i = 0; i < len; i++){
    crcReg ^= frame[i];
    for (uint8_t j=0; j<8; j++){
      if (crcReg & 0x01) {
        crcReg = (crcReg >>=1) ^ 0xA001;    
        }
      else crcReg >>= 1;
   }
}
  *crc16stor = crcReg & 0x00FF;
  crc16stor ++;
  *crc16stor = crcReg >> 8;
};

void rx(){
  if(RS485.available()) {
    int numberOfBytes = RS485.readBytes(rs485_buffer, 7);
    Serial.println("--------------------------");
    Serial.println("numberOfBytes: " + String(numberOfBytes));
    Serial.println("data: ");
    for(uint8_t i = 0; i < numberOfBytes; i++){
      Serial.print(rs485_buffer[i], HEX);
    }
    Serial.println("--------------------------");
  }
}

void setup() {
    Serial.begin(9600);
    RS485.begin(9600);
    delay(1000);
    uint8_t query[6] = {0x01, 0x03, 0x70, 0x01, 0x00, 0x01};
    CRC16ModbusCalc(query, 6, crc16storage);
    delay(10);
    RS485.write(query, 6);
    RS485.write(crc16storage, 2);  
}

void loop() {
  rx();
}
 
Изменено:

Bruzzer

★★★✩✩✩✩
23 Май 2020
474
136
@koreets61,
Я не понял ваш вопрос. "как мне получить ответ на ардуино" - от кого получить ответ, что за код приведен. Вы упоминаете "Устройство" и "Ардуино".
Но в любом случае в вашем коде нет Serial.begin(9600); // 9600 просто как пример
 

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
@Bruzzer,

Прошу прощения это часть кода программы приведена, разумеется там есть в setup Serial.begin(9600);

К ардуино подключен TTL-RS485 на базе max3485, к нему шина RS485 на другом конце висит преобразователь частоты, используется стандарт Modbus-RTU.

Так вот при отправке из ардуины скажем {0x01, 0x03, 0x70, 0x01, 0x00, 0x01} и вдогонку контрольную сумму, частотный преобразователь отвечает, какая частота у него сейчас задана, но у меня всегда RS485.available() равен 0, хотя видно что лампочка rx на TTL-RS485 загорается, то есть загорается сначала tx, а затем rx. В эту шину я подключил ноутбук с USB-RS485 и начал слать данные, я вижу как моргает на TTL-RS485 лампочка rx, но RS485.available() всегда равен 0.

Я попробовал отправить {0x01, 0x06, 0x20, 0x00, 0x00, 0x01} и вдогонку контрольную сумму, и преобразователь частоты запустил электродвигатель, это говорит о том, что физически шина исправна и контрольная сумма рассчитывается верно

Помехи в шине отсутствуют (можно предположить, что после запуска начинается процесс модуляции и вся шина просто умирает), так как после запуска послав {0x01, 0x06, 0x20, 0x00, 0x00, 0x05} и вдогонку контрольную сумму, электродвигатель останавливается.

Я что то делаю не так
 
Изменено:

Zuker

★✩✩✩✩✩✩
10 Янв 2024
56
12
  • Какая ардуина, Uno\Nano?
  • На max3485 стоит перемычка между контактами DE-RE?
У меня встречался затык с получением данных при переносе скетча с UNO -> NANO. Методом тыка определил, что для UNO у меня работает D6 (на гугловской картинке ниже это D5), на NANO работал только D10.
Arduino-UNO-rs458-max485-module-connection_bb.jpg
 

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
Там типа другая версия платы, и нет пинов DE-RE

8f34fe58-fea7-11ec-80fe-e0d55e81e32a_8f34fe5a-fea7-11ec-80fe-e0d55e81e32a.jpeg
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
474
136
@koreets61,
какая ардуина у вас?
На 36 ноге точно есть прерывания?
 
Изменено:

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
@Bruzzer,
Mega 2560, пошел смотреть распиновку. То есть прерывания должны быть обязательно на пине RX?
Это моя первая ардуино просто

@Bruzzer,
Нет там прерываний даже PCINT нет, то есть мне RX подцепить на пин у которого есть прерывание INT?
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
474
136
@koreets61,
Нужен пин на котором есть PCINT и обратите внимание, что номера пинов могут быть разные для 100 и 64 пиновых версий 2560 2561
 
Изменено:

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
@Bruzzer,
А случайно RS485.listen(); меня не спасет?
Просто плата разведена на эти пины 🤦🏻‍♂️
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
474
136
@koreets61,
Не спасет. listen() переключает текущий активный вход SoftwareSerial, если используется несколько
SoftwareSerial.
Если вы используете MegaCore, то там вроде можно использовать и PCINT и INT. Но лучше проверить.
 
  • Лойс +1
Реакции: koreets61

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
@Bruzzer,
Действительно, подключил на "Serial1" и в порт стали поступать данные, спасибо огромное за подсказку на счет "прерываний"
Но вот незадача, я получаю то, что отправляю, а ответа не видно от частотника

C++:
if(Serial1.available()){
    char rs485_buffer[Serial1.available()];
    for (uint8_t i = 0; i < (Serial1.available(); i++){
      rs485_buffer[i] = Serial1.read();
      Serial.println(rs485_buffer[i], HEX);
    }
 }
 

bort707

★★★★★★✩
21 Сен 2020
3,064
912
При таком коде у вас будет выход за границы массива, потому что значение "Serial1.available();" в третьей строке легко может быть больше, чем во второй.

Просто плата разведена на эти пины
плохая идея разводить плату, еще не отладив код.
 

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
@bort707,
Хорошо, пойдем просто

C++:
while(Serial1.available()){
    Serial.println(Serial1.read(), HEX);
}
Я вижу в мониторе порта, только отправленные данные. В чем проблема я не понимаю?

Кстати на преобразователе частоты есть такая настройка The MODBUS response was delayed сейчас стоит 2мс, я менял в диапазоне 0-20мс, результат одинаковый

Host sends 1 - Ардуино отправила данные
Slave response 1 - Преобразователь отправил данные

1725080896948.png

Актуальный код без функций взаимодействия с интерфейсом пользователя, вызывая функции RUN(), STOP() преобразователь частоты запускает или останавливает электродвигатель, но функция rx() печатает в монитор порта только отправленные данные, например вызвав RUN() в мониторе порта увидим

Код:
1 - адрес частотника
6 - Запись одного AO
20 - Адрес регистра
0  - Адрес регистра
0 - Данные для записи
1 - Данные для записи
43 - Контрольная сумма
CA - Контрольная сумма

1 - адрес частотника
3 - Чтение AO
30 - Адрес регистра
0  - Адрес регистра
0 - Данные для записи
1 - Данные для записи
8B - Контрольная сумма
A - Контрольная сумма

Код:
uint8_t crc16storage[2];

void CRC16ModbusCalc(uint8_t  frame[], uint8_t len, uint8_t  crc16stor[]){
  uint16_t crcReg = 0xFFFF;
  for (uint8_t i = 0; i < len; i++){
  crcReg ^= frame[i];
    for (uint8_t j=0; j<8; j++){
      if (crcReg & 0x01) { 
        crcReg = (crcReg >>=1) ^ 0xA001;     
      } else {
        crcReg >>= 1;
      }
    }
  }
  *crc16stor = crcReg & 0x00FF; 
  crc16stor ++;
  *crc16stor = crcReg >> 8; 
}

void rx(){
  while(Serial1.available()){
    Serial.println(Serial1.read(), HEX);
  }
}

void STATUS_FC(){
  uint8_t query[6] = {0x01, 0x03, 0x30, 0x00, 0x00, 0x01};
  CRC16ModbusCalc(query, 6, crc16storage);
  delay(10);
  Serial1.write(query, 6);
  Serial1.write(crc16storage, 2);
  Serial1.flush();
  rx();
}

void STOP(){
  uint8_t query[6] = {0x01, 0x06, 0x20, 0x00, 0x00, 0x05};
  CRC16ModbusCalc(query, 6, crc16storage);
  delay(10);
  Serial1.write(query, 6);
  Serial1.write(crc16storage, 2);
  Serial1.flush();
  STATUS_FC();
}

void RUN(){
  uint8_t query[6] = {0x01, 0x06, 0x20, 0x00, 0x00, 0x01};
  CRC16ModbusCalc(query, 6, crc16storage);
  delay(10);
  Serial1.write(query, 6);
  Serial1.write(crc16storage, 2);
  Serial1.flush();
  STATUS_FC();
}

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
}

void loop() {
    rx();
}
В общем ясно одно, проблем с кодом нет точно, сейчас подключил к шине ноутбук с USB-RS485 и начал слать данные, TTL-RS485 подключенный к Arduino не мигает лампочками ни Tx ни Rx
 

bort707

★★★★★★✩
21 Сен 2020
3,064
912
Ссылку на свою плату преобразователя можете дать?
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
474
136
The MODBUS response was delayed сейчас стоит 2мс,
Я не работал с RS485. Так что решения у меня нет.
Но для скорости 9600, значение явно должно быть больше 2 мс. (Я бы поставил максимальное, т.к. мне не известно, какая это величина у вашего модуля RS485)
"Актуальный Код" - не помогает понять проблему, т.к вы запускаете вы явно не его.
<<но функция rx() печатает в монитор порта только отправленные данные, например вызвав RUN() в мониторе порта увидим>>
Не понял, откуда в мониторе порта появляется
1 - адрес частотника
6 - Запись одного AO
.
.
.
Если rx() печатает только отправляемые данные.
 

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
@Bruzzer,

Я разобрался, в момент пайки проводов от TTL-RS485 к Arduino витая пара закоротилась :)))

Провод заменил, данные стали поступать в порт. Ох уж эта спешка.

Прошу прощения за вынос мозга на ровном месте

@bort707,
Он просто очень большой, в нем описаны функции работы с преобразователем, функции REST-API