Моя реализации Modbus Slave RTU/ASCII
- Войдите на сайт для отправки комментариев
Сб, 15/04/2017 - 15:09
Когда мы имеем дело с микроконтроллерами нужно экономно подходить к использованию ресурсов, как программных так и данных. По этому я постарался сделать максимально простой обработчик Modbus RTU/ASCII Slave для микроконтроллеров Arduino с минимальным использованием ресурсов.
Обрабатываются функции Modbus:
- Read Holding Registers 03h
- Read Input Registers 04h
- Write Holding Register 06h
- Write Holding Registers 10h
Простой пример:
#include <EEPROM.h> #include "KRRegisters.h" #include "KRModbusRTUSlave.h" class Data : public KRRegisters{ public: uint32_t dw; long lng; float flt; virtual uint16_t read(uint16_t index){ if(index<10){ int n=index*2; uint16_t res=EEPROM.read(n++); res<<=8; return res|EEPROM.read(n); }else{ switch(index){ case 10:return dw; case 11:return dw >> 16; case 12:return *(reinterpret_cast<uint32_t*>(&lng)); case 13:return *(reinterpret_cast<uint32_t*>(&lng)) >> 16; case 14:return *(reinterpret_cast<uint32_t*>(&flt)); case 15:return *(reinterpret_cast<uint32_t*>(&flt)) >> 16; } } } virtual void write(uint16_t index, uint16_t value){ uint32_t dw0; if(index<10){ int n=index*2; EEPROM.write(n++,value >> 8); EEPROM.write(n,value); }else{ switch(index){ case 10:dw=(dw & 0xffff0000) | value; break; case 11:dw=(dw & 0x0000ffff) | ((uint32_t)value << 16); break; case 12: dw0=(*(reinterpret_cast<uint32_t*>(&lng)) & 0xffff0000) | value; lng=*(reinterpret_cast<long*>(&dw0)) ; break; case 13: dw0=(*(reinterpret_cast<uint32_t*>(&lng)) & 0x0000ffff) | ((uint32_t)value << 16); lng=*(reinterpret_cast<long*>(&dw0)) ; break; case 14: dw0=(*(reinterpret_cast<uint32_t*>(&flt)) & 0xffff0000) | value; flt=*(reinterpret_cast<float*>(&dw0)) ; break; case 15: dw0=(*(reinterpret_cast<uint32_t*>(&flt)) & 0x0000ffff) | ((uint32_t)value << 16); flt=*(reinterpret_cast<float*>(&dw0)) ; break; } } } }; Data data; KRModbusRTUSlave mb(Serial,data,1); void setup() { Serial.begin(9600); data.dw=1234; data.lng=-4567; data.flt=12.345; } void loop() { mb._DO(); data.dw+=1; data.lng-=1; data.flt+=0.012; }
В примере первые 10 регистров это чтение/запись напрямую из EEPROM. А далее идут три четырех байтовые переменные разных типов.
Более сложный пример с видео обзором можно посмотреть тут:
Вот мне интересно, зачем мастеру писать в EEprom slave. может все же лучше банально передать пакет. Пусть Slave сам разберется что и куда сувать.
Я решил делать свою реализацию Modbus Slave, после того, как используя стороннюю библиотеку я уперся в ограничение на количество памяти для данных. В той библиотеке приходилос дублировать переменные и данные из EEPROM в массиве регтстров.
В приведенном примере я показал как можно предоставить доступ к данным EEPROM по Modbus вообще не используя промежуточные переменные.