2021年5月31日 星期一

HX711重量寫入PLC

目的:Load Cell HX711數值寫入PLC

利用Arduino 與PLC通訊,將重量感測器 HX711數值寫入PLC D0,使用RS485 Modbus RTU  F16。

使用CP值高的感測器 HX711,透過Arduino 與PLC協同合作來提升附加價值。

系統架構



線路

Load Cell Amplifier - HX711


5KG  Load Cell



HX711模組與Load Cell接線:

l   E+  => AVDD Analog supply: 2.6 ~ 5.5 V

l   E-   => GNGAnalog ground

l   => (INA- Analog InputChannel A negative input

l   A+  => (INA+ Analog InputChannel A positive input

HX711模組與Arduino接線:

l   GND => GND

l   DT => PIN 6 (Serial data output)

l   SCK => PIN 5 (Power down control (high active) and serial clock input)

l   VCC => VCC (2.6 ~ 5.5 V)

RS485配線参考Arduino與PLC RS485通訊

程式 

// Load Cell HX711 重量寫入 DVP PLC D0 RS485 RTU Mode 

// Include the libraries we need

#include <HX711.h> 

#define MB_IDEL 0

#define MB_SEND 1

#define MB_RECV 2

byte mb_state = 0;

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

// HX711 接線設定

const int DT_PIN = 6;

const int SCK_PIN = 5;

const int scale_factor = 440; //比例參數,從校正程式中取得 433 根據實際測量做為調 433->440

HX711 loadcell;

bool X2 = false;

bool last_X2 = false;

bool M0 = false;

void setup() {

  pinMode(2,INPUT_PULLUP);

  Serial.begin(115200);  

  Serial1.begin(9600,SERIAL_8E1);  // Modbus RTU 9600,8,E,1

  loadcell.begin(DT_PIN, SCK_PIN);

  Serial.println("load cell initial........."); 

  loadcell.get_units(10);  //未設定比例參數前的數值 

  loadcell.set_scale(scale_factor);       // 設定比例參數

  loadcell.tare();               // 歸零  

  Serial.println("put load and press PB start weight:");  //在這個訊息之前都不要放東西在電子稱上

  loadcell.power_down();    

}

void loop() {

 X2 = !digitalRead(2); 

  M0 = !last_X2 && X2 ;

  last_X2 = X2;

 switch(mb_state) {

  case MB_IDEL: if(M0){

                loadcell.power_up();               // 結束睡眠模式

                float weight =loadcell.get_units(10);

                mb_data[0]=(word)weight;

                Serial.print("weight-->");

                Serial.print((word)weight);

                Serial.println("g");

                loadcell.power_down();             // 進入睡眠模式

                  mb_state = MB_SEND;

                }

                else{

                  mb_state = MB_IDEL; // do nothing

                 }               

                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;

}

結果











2021年5月30日 星期日

DS18B20溫度寫入PLC

目的:溫度感測器 DS18B20數值寫入PLC

利用Arduino 與PLC通訊,將溫度感測器 DS18B20數值寫入PLC D0,使用RS485 Modbus RTU  F16。

使用CP值高的感測器(DS18B20價格NT100元有找),透過Arduino 與PLC協同合作來提升附加價值。

系統架構




線路

DS18B20黃色線接到Arduino PIN2,並加上4.7K歐姆提升電阻。 


RS485配線参考Arduino與PLC RS485通訊


程式 

// 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;

}

結果

Modbus通訊資料不能有小數點,所以溫度33.50,傳遞數值為3350。




2021年5月29日 星期六

Arduino與PLC RS485通訊

 目的:測試Arduino 與PLC RS485通訊

系統架構



線路


程式 

/*

  Arduino and DVP  PLC COM2 RS485  

 */

char CR = 0x0D;

char LF = 0x0A;

String cmd = String();

byte inByte[50] ; // 用來儲存收進來的 data byte

int i=0;

boolean once = false;

void setup()                    // run once, when the sketch starts

  Serial.begin(9600);

 Serial1.begin(9600,SERIAL_7E1);     // DVP PLC Modbus ASCII 9600,7,e,1 

 // force Y0 ON ":01050500FF00F6\r\n" 

  cmd= cmd + ":01050500FF00F6" + CR + LF;

}

void loop() { 

  if(!once){  

   Serial.println("Arduino --> DVP PLC");

   Serial.print(cmd);  //print string 

   for(int i=0; i<cmd.length(); i++) { //print ascii code

    Serial.print(cmd.charAt(i),HEX);

    Serial.print(" ");

  }  

    Serial1.print(cmd); //Arduino 2 PLC 

    delay(100); 

    Serial.println(" ");

   Serial.println(" ");

 // PLC Response

 i=0;

 while (Serial1.available()) { //PLC 2 Arduino

    inByte[i++] = Serial1.read();      

  } 

  Serial.println("DVP PLC --> Arduino");  

  for(int j=0; j< i;j++)   

    Serial.print((char) inByte[j]);

  for(int j=0; j< i;j++){

    Serial.print(inByte[j],HEX);

    Serial.print(" ");

  }  

 i=0;

 once = true;

  }//end once 

}

結果





2021年5月23日 星期日

ESP32與PLC RS485 通訊

目的: 測試ESP32與PLC RS485通訊

系統架構



接線




開發板設定


程式

//NodeMCU_32S UART2 -- DVP COM2 RS485 RTU F03 

#include <HardwareSerial.h>

#define RXD2 16

#define TXD2 17

byte inByte[50] ; // 用來儲存收進來的 data byte

//read D0,D1 command : "010310000002C0CB"

byte cmd[]={0x01,0x03,0x10,0x00,0x00,0x02,0xC0,0xCB};

int i=0;

boolean once = false;

void setup() {  

  Serial.begin(115200); 

  // Serial2.begin(baud-rate, protocol, RX pin, TX pin);      

  Serial2.begin(9600, SERIAL_8E1, RXD2, TXD2); //Modbus RTU 9600,8,E,1   

}

void loop(){ 

  if(!once){  

   Serial.println("ESP32 --> DVP PLC");

   for(i=0;i<sizeof(cmd);i++){   //for PC Monitor

    Serial.print(cmd[i],HEX);

    Serial.print(" ");

  } 

   Serial2.write(cmd,sizeof(cmd)); //ESP32 2 PLC

   delay(100); 

   Serial.println(" ");

   Serial.println(" ");

 // PLC Response

 i=0;

 while (Serial2.available()) { //PLC 2 ESP32

    inByte[i++] = Serial2.read();      

  } 

  int len = i; 

  Serial.println("DVP PLC --> ESP32");  

  for(i=0;i<len;i++){   //for PC Monitor

    Serial.print(inByte[i],HEX);

    Serial.print(" ");

 } 

  Serial.println(" ");  

 i=0;

 once = true;

  }//end once 

}

結果




2021年5月16日 星期日

Arduino與PLC通訊

目的:測試Arduino RS232與PLC通訊

系統架構


線路

DB9腳位定義: pin2(RX),  pin3(TX),  pin5(GND) 


程式 

/*

  Arduino RS232(RS485) and DVP EH2 PLC  

 */

char CR = 0x0D;

char LF = 0x0A;

String cmd = String();

byte inByte[50] ; // 用來儲存收進來的 data byte

int i=0;

boolean once = false;

void setup()                    // run once, when the sketch starts

  Serial.begin(9600);

 Serial1.begin(9600,SERIAL_7E1);     // DVP PLC Modbus ASCII 9600,7,e,1 

 // force Y0 ON ":01050500FF00F6\r\n" 

  cmd= cmd + ":01050500FF00F6" + CR + LF;

}

void loop() { 

  if(!once){  

   Serial.println("Arduino --> DVP PLC");

   Serial.print(cmd);  //print string 

   for(int i=0; i<cmd.length(); i++) { //print ascii code

    Serial.print(cmd.charAt(i),HEX);

    Serial.print(" ");

  }  

    Serial1.print(cmd); //Arduino 2 PLC 

    delay(100); 

    Serial.println(" ");

   Serial.println(" ");

 // PLC Response

 i=0;

 while (Serial1.available()) { //PLC 2 Arduino

    inByte[i++] = Serial1.read();      

  } 

  Serial.println("DVP PLC --> Arduino");  

  for(int j=0; j< i;j++)   

    Serial.print((char) inByte[j]);

  for(int j=0; j< i;j++){

    Serial.print(inByte[j],HEX);

    Serial.print(" ");

  }  

 i=0;

 once = true;

  }//end once 

}

結果



2021年5月8日 星期六

ESP32與PLC通訊

目的: 測試ESP32硬體RS232與PLC通訊

系統架構


接線


開發板設定


程式

//NodeMCU_32S UART2 and DVP-32EH COM1   

#include <HardwareSerial.h> 

#define RXD2 16

#define TXD2 17 

char CR = 0x0D;

char LF = 0x0A;

String cmd = String();

byte inByte[50] ; // 用來儲存收進來的 data byte

int i=0;

boolean once = false; 

void setup() { 

  Serial.begin(115200);

  // Serial2.begin(baud-rate, protocol, RX pin, TX pin);     

  Serial2.begin(9600, SERIAL_7E1, RXD2, TXD2); // DVP PLC Modbus ASCII 9600,7,e,1

  // force Y0 ON ":01050500FF00F6\r\n"

  cmd= cmd + ":01050500FF00F6" + CR + LF;

}

void loop(){

  if(!once){

   Serial.println(" ");

   Serial.println("ESP32 --> DVP PLC");

   Serial.print(cmd);  //print string

   for(int i=0; i<cmd.length(); i++) { //print ascii code

    Serial.print(cmd.charAt(i),HEX);

    Serial.print(" ");

  } 

    Serial2.print(cmd); //ESP32 2 PLC

    delay(100);

    Serial.println(" ");

   Serial.println(" ");

 // PLC Response

 i=0;

 while (Serial2.available()) { //PLC 2 ESP32

    inByte[i++] = Serial2.read();     

  } 

  Serial.println("DVP PLC --> ESP32"); 

  for(int j=0; j< i;j++)  

    Serial.print((char) inByte[j]);   

  for(int j=0; j< i;j++){

    Serial.print(inByte[j],HEX);

    Serial.print(" ");

  }

  Serial.println(" "); 

 i=0;

 once = true;

  }//end once

}

結果