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?
![Smile :)](./images/smilies/icon_smile.gif)
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);
}
}