Modbus dan PLC baik dalam komunikasi jadulnya yg berbasis serial RS 485/ RS 232 maupun kini sudah merambah ke komunikasi TCP/IP, menjadi pilihan yang menurut penulis sudah "Final" dikalangan dunia kontrol industrial. Pengalaman penulis ketika menawarkan otomasi berbasis mikrokontroller 8 bit yg saya rancang dengan fungsi yang hampir sama, tetap mendapatkan tantangan dan pertanyaan seputar kehandalannya. Jadi saya yang pecinta hardware dasar pun di sangsikan apalagi mereka yg ingin menawarkan kemudahan dari sisi dunia IT. Sehingga menurut rekan dosen otomasi di UK-Petra Surabaya, Node-Red menjadi jembatan yang ampuh untuk menyatukan perangkat jadul dengan sistem IOT-Industri 4.0
Seperti yang pernah saya bahas di tahun sebelumnya, saat saya belajar dan berhasil merancang Modbus-RTU bridging ke MQTT (silahkan mulai disini , dibaca dan dipahami terlebih dahulu), mutlak diperlukan pemahaman sistem pengiriman data, register I/O , error checking dan sebagainya. Untuk itu perlu diulang kembali praktek awal belajar modbus yaitu menjadikan arduino sebagai perangkat Modbus-slave, dengan penyesuaian rangkaian yg sudah saya buat di praktek node-red sebelumnya, sebagai berikut :
Dengan Input berupa pembacaan suhu dan kelembaban, maka saya menempatkan data pada Input / Analog Register berupa :
- 30001 : Angka didepan koma / Puluhan suhu
- 30002 : Angka desimal / di belekang koma suhu
- 30003 : Angka pengukukuran kelembaban
Sedangkan untuk Output berupa 7 segmen, register yg digunakan adalah Holding Register dengan alamat 40001. Register ini juga dapat diubah mengunakan Function 0x06. Jadi script untuk merubah rangkaian arduino diatas menjadi berbasis MODBUS-RTU sebagai berikut :
//Silahkan unduh Library modbus slave:
//https://code.google.com/archive/p/arduino-modbus-slave/downloads
#include <modbus.h>
#include <modbusDevice.h>
#include <modbusRegBank.h>
#include <modbusSlave.h>
#include "DHT.h"
//7seg
#define SEGA 5
#define SEGB 6
#define SEGC 7
#define SEGD 8
#define SEGE 9
#define SEGF 10
#define SEGG 11
#define dhtPin 4
#define DHTTYPE DHT22
DHT dht(dhtPin, DHTTYPE);
unsigned long previousMillis = 0;
const long interval = 5000;
modbusDevice regBank;
modbusSlave slave;
void setup()
{ //7 seg
pinMode(SEGA, OUTPUT);
pinMode(SEGB, OUTPUT);
pinMode(SEGC, OUTPUT);
pinMode(SEGD, OUTPUT);
pinMode(SEGE, OUTPUT);
pinMode(SEGF, OUTPUT);
pinMode(SEGG, OUTPUT);
//Ubah modbus device ID.
regBank.setId(6);
dht.begin();
/*
register modbus mengikuti format berikut
00001-09999 Output Digital, Perangkat master dapat membaca dan menulis ke register ini
10001-19999 Input Digital, Perangkat master hanya dapat membaca nilai dari register ini
30001-39999 Input Analog, Perangkat master hanya dapat membaca nilai dari register ini
40001-49999 Output Analog/ Holding register,
Perangkat master dapat membaca dan menulis ke register ini
Nilai analog adalah kata unsigned 16 bit yang disimpan dengan kisaran 0-32767
Nilai digital disimpan sebagai byte, nilai nol OFF dan nilai nonzer ON
Cara terbaik adalah mengkonfigurasi register tipe serupa ke dalam blok yang bersebelahan. ini
memungkinkan pencarian register yang lebih efisien dan dan mengurangi jumlah pesan
dibutuhkan oleh master untuk mengambil data
*/
//Pesan alamat Register Analog input di register bank 30001-10010
regBank.add(30001); //DHT11 - suhu puluhan
regBank.add(30002); //DHT11 - suhu desimal
regBank.add(30003); //DHT11 - kelembaban
//Pesan alamat Holding Register 40001
regBank.add(40001); // 7 SEGMEN
//Isi nilai awal dari 7 segmen
regBank.set(40001,8);
slave._device = ®Bank;
// Serial 9600 baud
slave.setBaud(9600);
}
void segmen(int angka)
{
switch(angka) {
case 0 : { digitalWrite(SEGA, HIGH);
digitalWrite(SEGB, HIGH);
digitalWrite(SEGC, HIGH);
digitalWrite(SEGD, HIGH);
digitalWrite(SEGE, HIGH);
digitalWrite(SEGF, HIGH);
digitalWrite(SEGG, LOW);
break;
}
case 1 : { digitalWrite(SEGA, LOW);
digitalWrite(SEGB, HIGH);
digitalWrite(SEGC, HIGH);
digitalWrite(SEGD, LOW);
digitalWrite(SEGE, LOW);
digitalWrite(SEGF, LOW);
digitalWrite(SEGG, LOW);
break;
}
case 2 : { digitalWrite(SEGA, HIGH);
digitalWrite(SEGB, HIGH);
digitalWrite(SEGC, LOW);
digitalWrite(SEGD, HIGH);
digitalWrite(SEGE, HIGH);
digitalWrite(SEGF, LOW);
digitalWrite(SEGG, HIGH);
break;
}
case 3 : { digitalWrite(SEGA, HIGH);
digitalWrite(SEGB, HIGH);
digitalWrite(SEGC, HIGH);
digitalWrite(SEGD, HIGH);
digitalWrite(SEGE, LOW);
digitalWrite(SEGF, LOW);
digitalWrite(SEGG, HIGH);
break;
}
case 4 : { digitalWrite(SEGA, LOW);
digitalWrite(SEGB, HIGH);
digitalWrite(SEGC, HIGH);
digitalWrite(SEGD, LOW);
digitalWrite(SEGE, LOW);
digitalWrite(SEGF, HIGH);
digitalWrite(SEGG, HIGH);
break;
}
case 5 : { digitalWrite(SEGA, HIGH);
digitalWrite(SEGB, LOW);
digitalWrite(SEGC, HIGH);
digitalWrite(SEGD, HIGH);
digitalWrite(SEGE, LOW);
digitalWrite(SEGF, HIGH);
digitalWrite(SEGG, HIGH);
break;
}
case 6 : { digitalWrite(SEGA, HIGH);
digitalWrite(SEGB, LOW);
digitalWrite(SEGC, HIGH);
digitalWrite(SEGD, HIGH);
digitalWrite(SEGE, HIGH);
digitalWrite(SEGF, HIGH);
digitalWrite(SEGG, HIGH);
break;
}
case 7 : { digitalWrite(SEGA, HIGH);
digitalWrite(SEGB, HIGH);
digitalWrite(SEGC, HIGH);
digitalWrite(SEGD, LOW);
digitalWrite(SEGE, LOW);
digitalWrite(SEGF, LOW);
digitalWrite(SEGG, LOW);
break;
}
case 8 : { digitalWrite(SEGA, HIGH);
digitalWrite(SEGB, HIGH);
digitalWrite(SEGC, HIGH);
digitalWrite(SEGD, HIGH);
digitalWrite(SEGE, HIGH);
digitalWrite(SEGF, HIGH);
digitalWrite(SEGG, HIGH);
break;
}
case 9 : { digitalWrite(SEGA, HIGH);
digitalWrite(SEGB, HIGH);
digitalWrite(SEGC, HIGH);
digitalWrite(SEGD, HIGH);
digitalWrite(SEGE, LOW);
digitalWrite(SEGF, HIGH);
digitalWrite(SEGG, HIGH);
break;
}
}
}
// mengubah koma
int ExtractDecimalPart(float Value, int numberOfDecimals)
{
float temp = Value - (long)(Value);
long p = 1;
for (int i=0; i< numberOfDecimals; i++) p*=10;
long DecimalPart = p * temp;
return DecimalPart;
}
void loop()
{
//Tulis 7 segmen sesuai nilai pada register
segmen(regBank.get(40001));
//Baca suhu 5 detikan
unsigned long currentMillis = millis();
if(currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
int h = dht.readHumidity();
float t= dht.readTemperature();
int t1 = t;
int t2 = ExtractDecimalPart(t,2);
//tulis ke register 30001 -30003
if (isnan(h) || isnan(t)) {
regBank.set(30001,1000);
regBank.set(30002,1000);
regBank.set(30003,1000);
}
regBank.set(30001,t1);
regBank.set(30002,t2);
regBank.set(30003,h);
}
//jalan terus berulang sebagai slave
slave.run();
}
Kejadian lagi deh kesalahan saat awal belajar modbus dulu ...jadi alamat register bukan dimulai dari 30001 melainkan cukup ditulis 0 (karena aturan offset jadi 1), ingat deh dulu seperti ini nih seharusnya :
[{"id":"a8d0e1d9.32142","type":"tab","label":"Flow 5","disabled":false,"info":""},{"id":"d299086b.f08a88","type":"modbus-read","z":"a8d0e1d9.32142","name":"","topic":"","showStatusActivities":false,"logIOActivities":false,"showErrors":false,"unitid":"6","dataType":"InputRegister","adr":"0","quantity":"3","rate":"5","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"824b1538.161228","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"x":279.32994079589844,"y":205.96183681488037,"wires":[["7967f3c9.3415bc","5cfa62af.b1f89c","e0c9cab0.13e948"],[]]},{"id":"7967f3c9.3415bc","type":"debug","z":"a8d0e1d9.32142","name":"read_modbus","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":526.3299407958984,"y":55.16672134399414,"wires":[]},{"id":"341bb8e1.0d3b38","type":"modbus-write","z":"a8d0e1d9.32142","name":"","showStatusActivities":false,"showErrors":false,"unitid":"6","dataType":"HoldingRegister","adr":"0","quantity":"1","server":"824b1538.161228","emptyMsgOnFail":false,"keepMsgProperties":false,"x":685.3369064331055,"y":450.8092050552368,"wires":[[],[]]},{"id":"b0f6eeca.9fc8f","type":"debug","z":"a8d0e1d9.32142","name":"out_modbus","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":681.3334045410156,"y":365.1701936721802,"wires":[]},{"id":"36302ceb.d3b7b4","type":"inject","z":"a8d0e1d9.32142","name":"decrement","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":"","topic":"","payload":"2","payloadType":"num","x":272.8958435058594,"y":403.8888854980469,"wires":[["44bf1fc9.8d7fd"]]},{"id":"96e67c14.b9386","type":"inject","z":"a8d0e1d9.32142","name":"increment","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":"","topic":"","payload":"1","payloadType":"num","x":272.8958435058594,"y":363.8888854980469,"wires":[["44bf1fc9.8d7fd"]]},{"id":"44bf1fc9.8d7fd","type":"function","z":"a8d0e1d9.32142","name":"7 segmen","func":"var count=flow.get('count') || 0;\n\nvar temp = msg.payload\n\nif(temp == 1) count+=1;\nelse if(temp == 2) count-=1;\n\nif(count > 9) count =0;\nif(count < 0) count =9;\n\nflow.set('count',count);\n\nvar result = {payload:count};\nreturn[result];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":473.89587783813477,"y":379.8889045715332,"wires":[["b0f6eeca.9fc8f","341bb8e1.0d3b38","8ca591c3.507c8"]]},{"id":"39680ef0.a0ec02","type":"ui_gauge","z":"a8d0e1d9.32142","name":"SUHU DHT 11","group":"fc14d827.fe2ea8","order":1,"width":0,"height":0,"gtype":"gage","title":"Suhu Celcius","label":"Celcius","format":"{{value}}","min":0,"max":"50","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":746.8958358764648,"y":147.88887405395508,"wires":[]},{"id":"fc85d4ce.fbaa78","type":"ui_chart","z":"a8d0e1d9.32142","name":"","group":"fc14d827.fe2ea8","order":2,"width":0,"height":0,"label":"Kelembaban %Rh","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"40","ymax":"100","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"60","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"outputs":1,"useDifferentColor":false,"x":756.8958511352539,"y":260.88890075683594,"wires":[[]]},{"id":"5cfa62af.b1f89c","type":"function","z":"a8d0e1d9.32142","name":"ubah suhu","func":"var temp = msg.payload;\nvar puluhan = temp[0]\nvar desimal = temp[1]\n\nvar ongko = (parseInt(puluhan) * 100) + desimal;\nvar suhu = parseFloat(ongko /100);\nvar result = {payload:suhu};\nreturn[result];\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":532.3402481079102,"y":154.70834350585938,"wires":[["39680ef0.a0ec02"]]},{"id":"e0c9cab0.13e948","type":"function","z":"a8d0e1d9.32142","name":"ubah humi","func":"var temp = msg.payload\nvar humi = parseInt( temp[2] )\n\nvar result = {payload:humi};\nreturn[result];\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":527.8958129882812,"y":237.88888549804688,"wires":[["fc85d4ce.fbaa78","f739dfd5.58126"]]},{"id":"f739dfd5.58126","type":"debug","z":"a8d0e1d9.32142","name":"ubah suhu","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":755.3402862548828,"y":202.18057250976562,"wires":[]},{"id":"8ca591c3.507c8","type":"ui_text","z":"a8d0e1d9.32142","group":"fc14d827.fe2ea8","order":4,"width":0,"height":0,"name":"","label":"7 Segmen","format":"{{msg.payload}}","layout":"row-spread","x":681.3299102783203,"y":407.0590515136719,"wires":[]},{"id":"5b185e1a.af2f7","type":"ui_button","z":"a8d0e1d9.32142","name":"Tambah","group":"fc14d827.fe2ea8","order":8,"width":"3","height":"2","passthru":false,"label":"Tambah ","tooltip":"","color":"","bgcolor":"","icon":"","payload":"1","payloadType":"num","topic":"payload","topicType":"msg","x":269.32643127441406,"y":313.2986240386963,"wires":[["44bf1fc9.8d7fd"]]},{"id":"a4c4a5d.a88cc58","type":"ui_button","z":"a8d0e1d9.32142","name":"Kurang","group":"fc14d827.fe2ea8","order":8,"width":"3","height":"2","passthru":false,"label":"Kurang","tooltip":"","color":"","bgcolor":"","icon":"","payload":"2","payloadType":"num","topic":"payload","topicType":"msg","x":273.8958435058594,"y":454.8888854980469,"wires":[["44bf1fc9.8d7fd"]]},{"id":"824b1538.161228","type":"modbus-client","name":"","clienttype":"simpleser","bufferCommands":true,"stateLogEnabled":false,"queueLogEnabled":false,"tcpHost":"127.0.0.1","tcpPort":"502","tcpType":"DEFAULT","serialPort":"COM7","serialType":"RTU-BUFFERD","serialBaudrate":"9600","serialDatabits":"8","serialStopbits":"1","serialParity":"none","serialConnectionDelay":"100","unit_id":"1","commandDelay":"1","clientTimeout":"1000","reconnectOnTimeout":true,"reconnectTimeout":"2000","parallelUnitIdsAllowed":true},{"id":"fc14d827.fe2ea8","type":"ui_group","name":"modbus RTU ui testing","tab":"53c1826d.1539dc","order":2,"disp":true,"width":"6","collapse":false},{"id":"53c1826d.1539dc","type":"ui_tab","name":"HumiTemp Node Red","icon":"dashboard","order":1,"disabled":false,"hidden":false}]
SELAMAT MENCOBA ....
0 komentar:
Posting Komentar