Как заставить библиотеки MQTT и ArduinoModbus работать на одном порту Ethernet?
У меня есть Arduino PLC на базе SAMD51P20 с Ethernet-шилдом на базе WIZnet W5500. Я использую следующие библиотеки:
#include <Ethernet.h>
#include <MQTT.h>
#include <ArduinoModbus.h>
Клиенты MQTT и Modbus-TCP работают нормально по отдельности, но их одновременный запуск создает проблемы для обоих.
Есть ли программное решение этой проблемы, например, использование отдельных сокетов для MQTT и Modbus-TCP. WIZnet W5500 имеет 8 доступных сокетов, но я не вижу API для выбора сокета для клиента MQTT и Modbus-TCP.
Если нет программного обеспечения, есть ли аппаратное решение?
Вот фрагмент кода:
#include <fmt.h>
#include <P1AM.h>
#include <Ethernet.h>
#include <MQTT.h>
#include <ArduinoModbus.h>
using namespace std;
#define HOST_NAME "WIZnet"
uint8_t macPLC[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
uint8_t ipPLC[] = {192, 168, 0, 41};
uint8_t ipModbus[] = {192, 168, 0, 43};
char ipMQTT[] = "192.168.0.42";
int unitID = 98;
EthernetClient ethernet;
MQTTClient mqtt;
ModbusTCPClient modbus(ethernet);
int n = 0;
void messageReceived(MQTTClient *client, char topic[], char bytes[], int length) {
if (length == 8) {
int32_t commandID;
float commandArg;
memcpy(&commandID, &bytes[0], sizeof(commandID));
memcpy(&commandArg, &bytes[4], sizeof(commandArg));
Serial.println(fmt::format("{} {}", commandID, commandArg).c_str());
}
else
Serial.println("wrong length!!!");
}
void servoSetup() {
modbus.coilWrite(unitID, 0x00C, 1);
}
void setup(){ // процедура настройки выполняется один раз:
P1.configWD(10000, 1);
P1.startWD();
Serial.begin(115200); //инициализация последовательной связи на скорости 115200 бит в секунду
while (!P1.init())
delay(1); //Ждать, пока модули подпишутся
Ethernet.begin(macPLC, ipPLC);
mqtt.begin(ipMQTT, ethernet);
modbus.setTimeout(500);
if (!modbus.begin(ipModbus, 502))
Serial.println("Failed to start Modbus TCP client!");
else
Serial.println("Connected to Modbus TCP client.");
P1.petWD();
while (!mqtt.connect(ipMQTT)) {
Serial.print(".");
delay(1000);
}
Serial.println("\nConnected to MQTT broker.");
mqtt.subscribe("plc", 2);
mqtt.onMessageAdvanced(messageReceived);
servoSetup();
delay(2000);
}
void loop() {
P1.petWD();
Serial.println(mqtt.loop());
Serial.println(n++);
int addr = 0x2407;
if (!modbus.holdingRegisterWrite(unitID, addr, n))
Serial.println(fmt::format("Modbus write failed: {}", modbus.lastError()).c_str());
delay(1000);
if (auto result = modbus.holdingRegisterRead(unitID, addr); result < 0)
Serial.println(fmt::format("Modbus read failed: {}", modbus.lastError()).c_str());
else
Serial.println(fmt::format("holdingRegisterRead: {}", result).c_str());
delay(1000);
}
В этом случае записи и чтения Modbus-TCP не имеют никакого эффекта, mqtt.loop()
возвращает 0
и обратный вызов messageReceived()
не вызывается. Если я закомментирую клиент MQTT или Modbus-TCP, код ведет себя так, как и ожидалось.
@Paul Jurczak, 👍0
Обсуждение1 ответ
Лучший ответ:
API для установки количества сокетов, используемых в библиотеке Ethernet, отсутствует.
MAX_SOCK_NUM устанавливается в Ethernet.h на основе доступной оперативной памяти.
#if defined(RAMEND) && defined(RAMSTART) && ((RAMEND - RAMSTART) <= 2048)
#define MAX_SOCK_NUM 4
#else
#define MAX_SOCK_NUM 8
#endif
Итак, на SAMD51 у вас есть 8 доступных сокетов. Ваша проблема с MQTT и Modbus TCP в другом месте.
Кстати, W5100 может работать только с 4 сокетами, но это ограничение на время выполнения.
EDIT: В вашем скетче вы используете один и тот же EthernetClient для обеих библиотек. Используйте два отдельных объекта EthernetClient.
EthernetClient ethernet;
EthernetClient modbusClient;
MQTTClient mqtt;
ModbusTCPClient modbus(modbusClient);
- Modbus TCP вместе с MQTT по тому же ethernet
- MQTT на nano с Ethernet Shield не работает
- Modbus IP с Simply Modbus TCP
- Разбор HTTP с аутентификацией в Arduino + Ethernet Shield
- связь между двумя arduino с помощью ENC28J60?
- Arduino не подключается к локальному брокеру MQTT
- Ethernet Shield не работает с TFT-экраном
- ARDUINO MODBUS TCP СОЕДИНЕНИЕ
Что за проблема? Три строки кода нам ничего не говорят. Вам нужно подробнее рассказать, как вы создаете клиента для каждого соединения?, @hcheung
@hcheung Я опубликовал полный тестовый код., @Paul Jurczak
ModbusTCPClient modbus(ethernet);
иmqtt.begin(ipMQTT, ethernet);
, вы используете один и тот же клиент Ethernet для двух служб. Создайте отдельный экземпляр клиента для каждой службы., @hcheung@hcheung Спасибо, что обратили на это внимание., @Paul Jurczak