Modbus Tester

FormerMazda
Inlägg: 5010
Blev medlem: 27 februari 2006, 14:59:36
Ort: Tranås (Jönköping)

Modbus Tester

Inlägg av FormerMazda »

Det fanns ett behov av en så enkel Modbus-pryl som möjligt där man ska kunna läsa och skriva några adresser.
Har man en enkel pryl där man vet hur man kommunicerar mot den och kan enkelt verifiera dess funktion så är det lättare att sätta upp kommunikation med andra enheter, man behöver inte fundera på om man frågar efter rätt adresser på rätt sätt, enkelt uttryckt.

Jag byggde då en första utgåva av nåt som kan komma att byggas lite seriösare om den uppfyller det vi önskar.

Den baseras på en arduino pro mini, valde en utan USB-port för att kunna växla mellan just ett USB-gränssnitt och ett RS485-gränssnitt.
Som USB gränssnitt använder jag en noname-modul som bara ansluts till arduinons RX/TX, samt GND.
Som RS485-gränssnitt används även där ett noname, men baserat på en MAX485. Dess DI/RO ansluts till arduidnons RX/TX. DE/RE ansluts till arduinons pinne 2, sedan hanteras denna enable av ArduinoRS485-biblioteket. VCC och GND ansluts till arduinons VCC och GND.
Man väljer vilket gränssnitt man ska prata genom med en enkel brygga i en DIL-sockel, men visst, en omkopplare hade varit snyggare såklart.
Allt spänningsmatas till arduinons RAW med en adapter som ger runt 7VDC. Arduinons 5VDC matar sen RS485-modulen. USB-modulen matas av USB-porten.

Det är den enda egentliga inkopplingen i projektet som behövs, jag har satt en annan DIL-sockel till de digitala portarna så att man kan välja olika modbus ID och hastigheter genom att dra ingångarna låga vid uppstart. Men låter man allt vara så pratar man på ID1 i 9600bps, 8 databitar, 1 stopbit, ingen paritet.
Dessa ingångar kan man sänka för att se statusändring på coilsen när man är uppkopplad mot testern.

Vid uppstart definieras lite I/O, och beroende på om nån ingång är låg eller inte så sätts vilken kommunikationshastighet man vill ha, samt modbus ID.
Sen hamnar vi i programloopen som startar en polling för Modbus, där läser vi status på första coil och sätter en knippe coils till vad ingångarna är satta till, samt skriver värden till en knippe holding registers. Allt för att kunna se att värden lever och ändras.
Den coil vi pollar replikerar sin status på den inbyggda LEDen, för vem gillar inte att se en lysdiod tändas och släckas? :)

De adresser som är upplagda är:
0x0001 = Sätt 1/0, se status på LED
0x0002 = 1 fast värde
0x0003 = Replikerar status IO 3 (normalt 1)
0x0004 = Replikerar status IO 4 (normalt 1)
0x0005 = Replikerar status IO 5 (normalt 1)
0x0006 = Replikerar status IO 6 (normalt 1)
0x0007 = Replikerar status IO 7 (normalt 1)
0x0008 = Replikerar status IO 8 (normalt 1)
0x0009 = Replikerar status IO 9 (normalt 1)
0X0010 = Ingen funktion

4x0001 = Replikerar status IO A0 (analog in, 0-5v = 0-1024)
4x0002 = Replikerar status IO A1 (analog in, 0-5v = 0-1024)
4x0003 = Replikerar status IO A2 (analog in, 0-5v = 0-1024)
4x0004 = Replikerar status IO A3 (analog in, 0-5v = 0-1024)
4x0005 = Fast värde 11
4x0006 = Fast värde 111
4x0007 = Fast värde 1111
4x0008 = Aktuell baudrate / 10
4x0009 = Ingen funktion
4x0010 = Ingen funktion

Koden är väldigt simpel, men det är ju också hela ledordet i bygget.

Kod: Markera allt

#include <ArduinoRS485.h> 
#include <ArduinoModbus.h>
int   iMBID = 1;    //Default om ingen ingång sänkt
long  lBPS  = 9600; //Default om ingen ingång sänkt
int   iAI1;
int   iAI2;
int   iAI3;

void setup() {
 
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  pinMode(2, INPUT_PULLUP); //ID 2
  pinMode(3, INPUT_PULLUP); //ID 3
  pinMode(4, INPUT_PULLUP); //1200bps
  pinMode(5, INPUT_PULLUP); //19200bps
  pinMode(6, INPUT_PULLUP); //115200bps
  pinMode(7, INPUT_PULLUP); //input
  pinMode(8, INPUT_PULLUP); //input
  pinMode(9, INPUT_PULLUP); //input
  
  if (!digitalRead(2)){ iMBID = 2; }
  if (!digitalRead(3)){ iMBID = 3; }

  if (!digitalRead(4)){ lBPS = 1200; }
  if (!digitalRead(5)){ lBPS = 19200; }
  if (!digitalRead(6)){ lBPS = 115200; }
  
  Serial.begin(lBPS);

  // start the Modbus RTU server
  ModbusRTUServer.begin(iMBID, lBPS);

  // Sätt upp Coils, start adress 0x00, 10 coils
  ModbusRTUServer.configureCoils(0x00, 10);
  // Sätt upp HoldingRegisters, start adress 0x00, 10 coils
  ModbusRTUServer.configureHoldingRegisters(0x00, 10);

}

void loop() {
  // polla för Modbus RTU requests
  ModbusRTUServer.poll();

 
  int coilValue = ModbusRTUServer.coilRead(0x00);  // Läs coil 0x00
   ModbusRTUServer.coilWrite(0x01, 1);
   ModbusRTUServer.coilWrite(0x02, digitalRead(3));
   ModbusRTUServer.coilWrite(0x03, digitalRead(4));
   ModbusRTUServer.coilWrite(0x04, digitalRead(5));
   ModbusRTUServer.coilWrite(0x05, digitalRead(6));
   ModbusRTUServer.coilWrite(0x06, digitalRead(7));
   ModbusRTUServer.coilWrite(0x07, digitalRead(8));
   ModbusRTUServer.coilWrite(0x08, digitalRead(9));

   ModbusRTUServer.holdingRegisterWrite(0x00, analogRead(A0));
   ModbusRTUServer.holdingRegisterWrite(0x01, analogRead(A1));
   ModbusRTUServer.holdingRegisterWrite(0x02, analogRead(A2));
   ModbusRTUServer.holdingRegisterWrite(0x03, analogRead(A3));
   ModbusRTUServer.holdingRegisterWrite(0x04, 11);
   ModbusRTUServer.holdingRegisterWrite(0x05, 111);
   ModbusRTUServer.holdingRegisterWrite(0x06, 1111);
   ModbusRTUServer.holdingRegisterWrite(0x07, lBPS/10);
   
  //Enkel if-sats för att tända/släcka LED beroende på status
  if (coilValue) {
    digitalWrite(LED_BUILTIN, HIGH);
  } else {
    digitalWrite(LED_BUILTIN, LOW);
  }
}

Sedan ett principiellt schema, observera att exakt inkoppling beror på den modul som väljs.
Modbus tester.png
Och en bild på den fungerande byggda prototypen.
Modbus tester proto.PNG
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.