#c #arduino #modbus #rs485
#c #arduino #modbus #rs485
Вопрос:
Существует проблема при написании кода MODBUS RTU с использованием Arduino.
Во-первых, связь прошла успешно. Однако обмен данными выполняется в порядке запрос -> запрос -> ответ -> запрос -> запрос -> ответ.
Пожалуйста, обратитесь к видео ниже. https://youtu.be/Z8tkmY7l-oo
Я не знаю, что не так с моим кодом.
помогите мне..
мой код…
#include <Crc16.h>
Crc16 crc;
#define EN0 2
uint8_t n8ID = 1;
uint8_t FunctionCode = 3;
const int DIP_1 = 6;
const int DIP_2 = 7;
const int DIP_3 = 8;
const int DIP_4 = 9;
uint8_t MODBUS_Request[10];
uint8_t Data[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
void setup()
{
pinMode(EN0, OUTPUT);
pinMode(DIP_1, INPUT_PULLUP);
pinMode(DIP_2, INPUT_PULLUP);
pinMode(DIP_3, INPUT_PULLUP);
pinMode(DIP_4, INPUT_PULLUP);
digitalWrite(EN0, LOW);
Serial.begin(9600);
}
void loop()
{
digitalWrite(EN0, LOW);
n8ID = 0;
n8ID = (!digitalRead(DIP_1)) << 0;
n8ID = (!digitalRead(DIP_2)) << 1;
n8ID = (!digitalRead(DIP_3)) << 2;
n8ID = (!digitalRead(DIP_4)) << 3;
if (Serial.available())
{
uint8_t leng = Serial.readBytes(MODBUS_Request, 8);
if(MODBUS_Request[0] == n8ID amp;amp; MODBUS_Request[1] == FunctionCode amp;amp; MODBUS_Request[2] == 0 amp;amp; MODBUS_Request[3] == 0)
{
uint8_t Request_dataBuff[6];
for (int i = 0; i < 6; i )
{
Request_dataBuff[i] = MODBUS_Request[i];
}
unsigned short RequestCRC = (unsigned short)(MODBUS_Request[7] << 8 | MODBUS_Request[6]);
crc.clearCrc();
for (uint8_t i = 0; i < 6; i )
crc.updateCrc(Request_dataBuff[i]);
unsigned short CRC_Check = crc.getCrc();
CRC_Check = crc.Modbus(Request_dataBuff, 0, 6);
if(RequestCRC == CRC_Check)
{
uint8_t send_dataBuff[15] = {n8ID, FunctionCode, 12, Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9], Data[10], Data[11]};
crc.clearCrc();
for (uint8_t i = 0; i < 15; i )
crc.updateCrc(send_dataBuff[i]);
unsigned short ResponseCRC = crc.getCrc();
ResponseCRC = crc.Modbus(send_dataBuff, 0, 15);
uint8_t Response_CRC_H = ResponseCRC >> 8;
uint8_t Response_CRC_L = ResponseCRC amp; 0xFF;
uint8_t MODBUS_Response[17] = {n8ID, FunctionCode, 12, Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9], Data[10], Data[11], Response_CRC_L, Response_CRC_H};
digitalWrite(EN0, HIGH);
for(int i = 0; i < 17; i )
{
Serial.write(MODBUS_Response[i]);
Serial.flush();
}
digitalWrite(EN0, LOW);
}
}
}
}
Ответ №1:
Ваш код добавляет большую часть задержки. Вы вводите огромные накладные расходы, записывая в порт по одному байту за раз.
Может быть, вы можете попробовать заменить эту часть:
for(int i = 0; i < 17; i )
{
Serial.write(MODBUS_Response[i]);
Serial.flush();
}
С чем-то более простым:
Serial.write(MODBUS_Response,17);
Serial.flush();
который просто записывает весь кадр Modbus за один раз.
Если это изменение само по себе не устраняет ваши проблемы, вам может потребоваться предоставить более подробную информацию по вашему вопросу о другой стороне ссылки.
Комментарии:
1. Спасибо за ваши ответы. Однако, даже если вы измените его, как вы сказали, симптомы те же. В настоящее время подключение моего устройства — Master: 1, Slave: 1, а программное обеспечение ПК выступает в качестве ведущего. Программное обеспечение для ПК — это симулятор, который может служить в качестве ведущего устройства MODBUS RTU. Если вы выполните поиск по запросу «MODSCAN64» в Google, вы сможете получить информацию о программном обеспечении. Так что где-то должна быть проблема с моим кодом.
Ответ №2:
Вы не можете отправить два запроса подряд.
Что произойдет, если вы отправите два запроса двум подчиненным устройствам, и они оба ответят одновременно?
Последовательная связь не имеет никакого механизма, позволяющего избежать столкновений.
Это должен быть мастер, который синхронизируется в строгом порядке: запрос -> ответ -> запрос -> ответ … и т.д.
Вы не можете отправить новый запрос, пока не получите ответ от предыдущего.
Комментарии:
1. Я не понимаю, что есть два запроса. В настоящее время подключение моего устройства — Master: 1, Slave: 1, а программное обеспечение ПК выступает в качестве ведущего. Программное обеспечение для ПК — это симулятор, который может служить в качестве ведущего устройства MODBUS RTU. Если вы выполните поиск «MODSCAN64» в Google, вы сможете получить информацию о программном обеспечении.
Ответ №3:
Причина, похоже, найдена, но, похоже, это не фундаментальное решение.
значение тайм-аута arduino по умолчанию составляет 1000 мс, и ведущий запрашивал данные у ведомого устройства каждые 1000 мс.
Я думал, что перейду к следующему коду, когда из приведенного ниже кода поступит буфер приема объемом 8 байт, но, думаю, я жду тайм-аута. Serial.readBytes(MODBUS_Request, 8);
я использовал Serial.setTimeout()
функцию в качестве решения для сокращения времени ожидания, но это, похоже, не является фундаментальным решением.
даже если вы используете эту функцию, код будет останавливаться до тех пор, пока я его установлю. Я хочу использовать Serial.readBytesUntil()
функцию, но последними получаемыми данными являются CRC, поэтому последние данные не могут быть предсказаны.
Когда данные получены, как я могу перейти к следующему коду?
Ответ №4:
Первый
Попробуйте добавить небольшую задержку, прежде чем линия TXEN опустится,
digitalWrite(EN0, HIGH);
for(int i = 0; i < 17; i )
{
Serial.write(MODBUS_Response[i]);
Serial.flush();
}
delay(1) # <-- add a little delay to allow transmission finish
digitalWrite(EN0, LOW);
Возможно, потребуется увеличить задержку, если скорость передачи данных действительно низкая.
Второй
Могут быть некоторые значения «0» или случайные / шумовые значения, предшествующие фактическим байтам запроса, полученным вашим кодом, поэтому вы не можете просто прочитать 8 байт в одном пакете и принять его за фактический запрос. Вместо этого вам, возможно, придется читать один за другим и выяснять, где находится начальный байт запроса.
Смотрите следующий пример,
0 0 0 0 0 1 3 x x x x c c ... 1 3 x x x x c c
^ first read ^ ^ second read ^ third read ^
| (discard) | | (timeout) | (success) |
Комментарии:
1. То же самое касается добавления «задержки». Изменение скорости передачи данных на 115200 не решает проблему….