目的:溫度感測器 DS18B20數值寫入PLC
利用Arduino 與PLC通訊,將溫度感測器 DS18B20數值寫入PLC D0,使用RS485 Modbus RTU F16。
使用CP值高的感測器(DS18B20價格NT100元有找),透過Arduino 與PLC協同合作來提升附加價值。
系統架構
線路
程式
// 將DS18B20溫度寫入 DVP PLC D0 RS485 RTU Mode
// Include the libraries we need
#include <OneWire.h>
#include <DallasTemperature.h>
#define MB_IDEL 0
#define MB_SEND 1
#define MB_RECV 2
byte mb_state;
int result = -1;
void rtuRequest(byte id, byte fc, word address, word len, HardwareSerial& port );
byte rtuResopnse(byte id, HardwareSerial& port);
word CRC(byte* buf, byte len);
byte mb_frame[50]; //request / response messages
word mb_data[20]={32,20}; //request / response datas
#define POLLING_TIME 4000 // ms
unsigned long last_polling = 0;
bool polling = false;
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void setup() {
Serial.begin(115200);
Serial1.begin(9600,SERIAL_8E1); // Modbus RTU 9600,8,E,1
sensors.begin();
delay(100);
}
void loop() {
if(millis() - last_polling > 4000) {
polling = true;
last_polling = millis();
}
switch(mb_state) {
case MB_IDEL: if(polling) {
sensors.requestTemperatures();
float tempC = sensors.getTempCByIndex(0);
// Check if reading was successful
if(tempC != DEVICE_DISCONNECTED_C){
Serial.print("Temperature for the device 1 (index 0) is: ");
Serial.println(tempC);
mb_data[0] = tempC *100;
Serial.println(mb_data[0]);
mb_state = MB_SEND;
}
else{
Serial.println("Error: Could not read temperature data");
mb_state = MB_IDEL; // do nothing
}
}
polling = false;
break;
case MB_SEND:
rtuRequest(1,16,0x1000,1,Serial1);
delay(50); //wait 50ms
mb_state = MB_RECV;
break;
case MB_RECV: result = rtuResponse(1,Serial1);
if(result != -1) { //receive message finished
if(result == 0) { //response message correct
//do somthing
}
else if(result > 0) { //error occure
Serial.print("error code -->"); // print error code
Serial.println(result);
}
mb_state = MB_IDEL; //reset
result = -1; //reset
}
break;
}
}
//slave response parse
byte rtuResponse(byte id, HardwareSerial& port) {
if(port.available()) {
byte len = 0;
while (port.available())
mb_frame[len++] = port.read();
if(len > 7){ // message ok
if(mb_frame[0] == id){ //step 1: check id
if(word(mb_frame[len-1],mb_frame[len-2]) == CRC(mb_frame,len-2)) { //step 2: check crc
switch(mb_frame[1]) { //step 3: get datas or comfirm
case 3: for(int i=0 , j=0 ; i<mb_frame[2]; i+=2)
mb_data[j++] = word(mb_frame[3+i],mb_frame[4+i]);
return 0;
break;
case 16: return 0; // write success
break;
deafult:break;
}//end switch //step 3: parse mb_frame message
} //crc
else {
; //Serial.println(" crc error ");
}
} //if(mb_frame[0] == id)
else {
; //Serial.println(" id error ");
}
}
else {
return mb_frame[3];
}
}
}
void rtuRequest(byte id, byte fc, word address, word reg_len, HardwareSerial& port) {
word crc=0;
byte len=0;
mb_frame[0] = id; //unit id
mb_frame[1] = fc; //function code
mb_frame[2] = highByte(address); //start address high byte
mb_frame[3] = lowByte(address); //start address low byte
mb_frame[4] = highByte(reg_len); //register length high byte
mb_frame[5] = lowByte(reg_len); //register length low byte
switch(fc) {
case 3: crc = CRC(mb_frame,6);
// Serial.print("CRC :");
// Serial.println(crc,HEX);
mb_frame[6] = lowByte(crc); //crc low byte
mb_frame[7] = highByte(crc); //crc high byte
len = 8;
break;
case 16:len = reg_len*2; //data byte count = register length*2
mb_frame[6] = len; //data byte count = register length*2
for(int i = 0 ; i < reg_len ; i++) {
mb_frame[7+i*2] = highByte(mb_data[i]); //data[0+i*2] high byte
mb_frame[7+i*2+1] = lowByte(mb_data[i]); //data[1+i*2] low byte
}
crc = CRC(mb_frame,len+7);
// Serial.print("CRC :");
// Serial.println(crc,HEX);
mb_frame[len+7] = lowByte(crc); //crc low byte
mb_frame[len+8] = highByte(crc); //crc high byte
len = len+9;
break;
deafult:break;
}
port.write(mb_frame,len);
// return len;
}
word CRC(byte* buf, byte len) {
word crc = 0xFFFF;
for (byte i = 0; i < len; i++) {
crc = crc ^ (word) buf[i];
for (byte j = 0; j < 8; j++)
crc = (crc & 0x0001)?(crc >> 1) ^ 0xA001:(crc >> 1);
}
return crc;
}
沒有留言:
張貼留言