การใช้งาน S7-1200 เป็น Modbus TCP Client

การใช้งาน S7-1200 เป็น Modbus TCP Client

S7-1200 โดยปกติแล้วจะมีพอร์ท Profinet ไว้ให้ทุกรุ่นอยู่แล้ว ซึ่งเราสามารถนำพอร์ท Profinet นี้มาใช้งานเป็น Modbus TCP Client หรือ Modbus TCP Server ก็ได้ โดยการกำหนดให้พอร์ท Profinet นี้เป็น Modbus แบบไหน ไม่ได้ขึ้นอยู่กับการตั้งค่า hardware แต่ขึ้นอยู่กับการเลือกใช้งาน Block ที่ตัวโปรแกรมของเราเอง

ในหัวข้อนี้ เราจะทำการใช้งานให้ S7-1200 ทำตัวเป็น Modbus TCP Client เพื่อไปอ่าน/เขียนค่าตัวอุปกรณ์ใดๆก็ได้ที่ทำตัวเป็น Modbus TCP Server นั่นเอง ซึ่งจะทำการสั่งงานผ่าน Block “MB_CLIENT” นั่นเอง

MCClientTCP_00.png

ขั้นตอนการใช้งาน S7-1200 ให้เป็น Modbus TCP Client

1. ทำการสร้าง Data block ขึ้นมาใหม่ เพื่อใช้เป็นตัวตั้ง Modbus parameter (เช่น IP address ของตัว Modbus TCP Server ที่ต้องการไปอ่าน, Modbus port เป็นต้น)
MCClientTCP_01.png

2. ตั้งตัวแปร Parameter ใน Data block ที่เราเพิ่งสร้างจากขั้นตอนก่อนหน้า เป็นชนิด TCON_IP_v4 (หมายเหตุ Data type TCON_IP_v4 นี้ เราต้องทำการพิมพ์เอาเอง หากเลือกโดยการ drop down จะหาไม่เจอ)
MCClientTCP_02.png

เมื่อได้กำหนดชนิดตัวแปรเป็น TCON_IP_v4 แล้ว เราสามารถทำการขยายข้อมูลภายในตัวแปรนี้มาดูได้ ดังตัวอย่างดังรูป ซึ่งข้อมูลทั้งหมดนี้คือ parameter ของการสื่อสาร Modbus ที่เราต้องตั้งค่า
MCClientTCP_03

3. ทำการตั้งค่าให้ Start value ให้กับ parameter ของ Modbus
MCClientTCP_04.png

โดย

  • InterfaceId คือหมายเลข Hardware identifier ของพอร์ท Profinet ซึ่งสามารถตรวจสอบได้จาก Device configuration ของตัว PLC เราดังรูปด้านล่าง
  • ID คือหมายเลขอะไรก็ได้ตั้งแต่ 1-4095 ซึ่งคำสั่ง MB_Client แต่ละตัว จะต้องมี ID เฉพาะตัวที่ไม่ซ้ำกัน
  • ConnectionType กำหนดเป็น 11 เท่านั้นเพื่อตั้งให้เป็นการสื่อสารแบบ TCP ( Block MB_Client ไม่รองรับการสื่อสารแบบ UDP)
  • ActiveEstablished หากมีค่าเป็นจริง จะทำการสื่อสารผ่าน Block MB_Client
  • RemoteAddress เป็นการกำหนด IP ของอุปกรณ์ server ที่เราจะไปอ่าน/เขียนค่า
  • RemotePort ใช้กำหนด port ของการอ่าน/เขียน modbus ซึ่งค่าปกติจะเป็น 502 ซึ่งเป็น port มาตรฐานของ Modbus อยู่แล้ว
  • LocalPort ค่าปกติเป็น 0 จากการทดสอบพบว่าจะใช้ 0 หรือ 502 ก็ทำงานได้เหมือนกัน
MCClientTCP_05.png
วิธีการตรวจสอบ Hardware identifier ของ port Ethernet

4. ทำการสร้าง Data block ขึ้นมาใหม่อีก 1 ตัว เพื่อใช้เป็นตัวพักข้อมูลที่อ่าน/เขียน จากอุปกรณ์ Modbus Server
MCClientTCP_06

5. สร้างตัวแปร Array เพื่อใช้เป็น buffer ในการเก็บข้อมูลของการสื่อสาร Modbus (จากการทดสอบพบว่า หากต้องการอ่าน/เขียนข้อมูลแบบ Integer ต้องสร้างเป็น Array เท่านั้น ไม่สามารถสร้างตัวแปรแยกเดี่ยวๆได้ ค่าจะไม่ทำการอ่านเขียนให้)
MCClientTCP_07.png

6. ที่ตัวโปรแกรม ทำการวาง block MB_CLIENT  โดย block นี้จะอยู่ในหัวข้อ Communication -> Others -> MODBUS TCP
MCClientTCP_08.png

7. กำหนดค่าต่างๆให้กับ block MB_CLIENT
MCClientTCP_09

  • REQ จะสั่งให้ทำงาน Modbus query โดยจะทำการตลอดเวลาที่สัญญาณนี้ ON
  • DISCONNECT ใช้เพื่อสร้างหรือยกเลิก connection กับตัว Modbus server โดยหากค่าเป็น
    • 0 จะทำการสร้าง connection กับอุปกรณ์ที่ได้ตั้งค่าไว้ใน parameter CONNECT (ซึ่งก็คือ Modbus parameter ที่เราได้ทำไว้ก่อนหน้านั่นเอง)
    • 1 จะทำการยกเลิก Communication connection กับอุปกรณ์ใน parameter CONNECT
  • MB_Mode ใช้เพื่อเลือก mode ของ Modbus request (ดูรายละเอียดท้ายเรื่อง)
  • MB_DATA_ADDR ใช้เพื่อเลือก address เริ่มต้นของอุปกรณ์ Modbus server ที่ต้องการไปอ่าน/เขียน
  • MB_DATA_LEN ใช้เพื่อตั้งจำนวนข้อมูลจาก address เริ่มต้นว่าต้องการไปอ่าน/เขียนเป็นจำนวนกี่ address
  • MB_DATA_PTR เป็นตัว pointer ที่ชี้ไปยัง buffer ที่ใช้เก็บข้อมูลของการสื่อสาร Modbus
  • CONNECT เป็นตัว pointer ที่ชี้ไปยัง parameter ในการสื่อสาร Modbus

8. ทำการ download โปรแกรมลง PLC จากการทำสอบดังรูปจะเห็นว่าเมื่อเราทำการ on สัญญาณ REQ ตัว PLC ก็จะทำการอ่านค่า address 40001 – 40005 จากอุปกรณ์ Modbus TCP Server ทันที และนำค่าไปเก็บไว้ที่ตัวแปร array ของ Data block ที่เราได้สร้างมาเพื่อเก็บค่า
MCClientTCP_10

MCClientTCP_11.png

การทดสอบเพิ่มเติม

1. หากต้องการอ่านค่าแบบ bit จากอุปกรณ์ Modbus TCP Server เราสามารถกำหนดตัวแปรตรงๆ (direct pointer) ในรูปแบบของ “P#bit address” “data type” “length” เช่น P#M10.0 BOOL 8 คือการสั่งให้อ่าน/เขียนค่าไปที่ %M10.0 เป็นจำนวน 8 bit

2. จากการทดสอบพบว่า หากเราสร้าง Data block ขึ้นมาเพื่อใช้อ่าน/เขียนค่า BOOL จาก Modbus Server แทนการใช้ direct pointer ในรูปแบบ “P#bit address” “data type” “length”  เราจะไม่สามารถสร้าง Array ของ BOOL เพื่อใช้อ่านเขียนตัวแปร BOOL ได้ ดังรูป

MCClientTCP_15.png
การกำหนด array BOOL ไม่สามารถอ่าน BOOL จาก block MB_CLIENT ได้

แต่หากเราสร้าง Array ที่เป็นแบบ Word แทน จะสามารถทำการอ่านเขียนตัวแปร BOOL ได้ (แต่ต้องไม่ลืมว่าการกำหนดค่าเป็น word แล้วอ่านเป็น bit นั้น รูปแบบการเรียงใน word จะเป็นแบบ LH format เช่นถ้า bit0 ON ตัวเดียวค่าจะอ่านได้เท่ากับ 16#0100 หรือถ้า bit ที่ 16 ON ตัวเดียวค่าจะอ่านได้เท่ากับ 16#0001 เป็นต้น)

MCClientTCP_16.png
เราจะตั้ง Array เป็น word สำหรับการอ่าน BOOL
MCClientTCP_13.png
ผลจากการอ่าน bit จาก Modbus server ไปเก็บไว้ที่ %M10.0 เป็นต้นไป (ด้วย pointer P#M10.0 BOOL 8)

 

3. กรณีที่เราต้องการอ่านค่า address หลายๆตัวที่ไม่ได้เรียงกันจากอุปกรณ์ Modbus Server ตัวเดียวกัน เราสามารถสร้าง block MB_CLIENT ขึ้นมาอีก โดยใช้ Instance DB, ConnectionID และ PortID ร่วมกันได้เลย ดังรูป

แต่เงื่อนไขคือ ขา REQ นั้นจะต้องทำงานไม่พร้อมกัน คือเราต้องสร้างจังหวะของขา REQ ในแต่ละ block ให้ไม่ ON พร้อมกันนั่นเอง (ในการใช้งานจริงๆ แนะนำให้เอาสัญญาณ DONE ของแต่ละ block มาทำการ enable block ถัดไป ซึ่งสามารถดูได้ในขั้นตอนที่ 5)

MCClientTCP_21.png
ทั้งสอง block วิ่งไปอ่านค่าจากอุปกรณ์เดียวกัน แต่คนละ address กัน สังเกตว่าเราจะใช้ Instance DB ตัวเดียวกันได้เลย รวมถึงตัว parameter CONNECT ด้วย แต่ขา REQ ต้องไม่ ON พร้อมกัน
MCClientTCP_20.png
ทั้งสอง block วิ่งไปอ่านค่าจากอุปกรณ์เดียวกัน แต่คนละ address กัน สังเกตว่าเราจะใช้ Instance DB ตัวเดียวกันได้เลย รวมถึงตัว parameter CONNECT ด้วย แต่ขา REQ ต้องไม่ ON พร้อมกัน

ในกรณีที่ขา REQ ของทั้ง 2 block ทำงานพร้อมกัน จะเกิด error ขึ้นมา

MCClientTCP_22.png
ไม่ควรให้ขา REQ ของทั้ง 2 block ที่ไปอ่านจากอุปกรณ์เดียวกัน ON พร้อมกัน เพราะจะทำให้เกิด Error ขึ้น

 

4. อีกวิธีหนึ่งที่สามารถทำได้ ในกรณีที่เราต้องการอ่าน/เขียนค่าไปยังอุปกรณ์ Modbus Server ตัวเดียวกันแต่ทำการอ่านเขียนหลาย address แยกกันคือ สร้าง MB_CLIENT แบบแยก Instance DB กัน แต่ยังคงใช้ parameter CONNECT ชี้ไปยัง parameter ตัวเดิมได้ แต่เราต้องควบคุมขา DISCONNECT ให้ตัวนึงตัดการเชื่อมต่อเสียก่อน คือ Block หนึ่งต้องให้ DISCONNECT=1 เพื่อตัดการสื่อสารและอีก Block หนึ่งให้ DISCONNECT=0 เพื่อทำการเชื่อมต่อกับ Modbus Server

วิธีนี้ทำให้ดูเป็นตัวอย่างเท่านั้น แต่จริงๆแล้วไม่แนะนำให้ทำ เพราะวิธีก่อนหน้าใช้งานได้ง่ายกว่ามากและไม่ยุ่งยากเท่า
MCClientTCP_12.png

หาก DISCONNECT ของทั้ง 2 block ทำงานพร้อมกัน คือเท่ากับ 0 ทั้งคู่ จะส่งผลให้ block หนึ่งมี error เกิดขึ้น แม้ว่าเราจะยังไม่ทำการ ON ขอ REQ ก็ตามMCClientTCP_14.png

5. สำหรับการอ่านค่าอย่างต่อเนื่องจากอุปกรณ์ Modbus Server แบบสมบูรณ์นั้น เราจะนำประโยชน์ของขา Done มาใช้งาน เพราะขา Done จะทำงานเป็น pulse สั้นๆเมื่อทำการอ่าน/เขียนข้อมูลเสร็จแล้ว ซึ่งสามารถดูการทำงานของขา Busy และ Done ได้จาก Time Chart ข้างล่างนี้

MCClientTCP_25.png
Time Chart การทำงานของขา Busy และ Done

ในส่วนของตัวโปรแกรม เราจะทำการ Enable_Read เป็นแบบ pulse เพราะ block ทั้ง 2 ไม่ควรทำงานพร้อมกัน เมื่อ block แรกทำงานเสร็จแล้วสัญญาณ Done1 ก็จะไปสั่งให้ block ที่2 ทำงานต่อ และเมื่อ block ที่ 2 ทำงานเสร็จสัญญาณ Done2 ก็จะไปสั่งให้ block แรกทำงาน และวนลูปไปเรื่อยๆจนกว่าสัญญาณ Stop จะสั่งงานนั่นเองMCClientTCP_26

 

MCClientTCP_27
Time chart โดยรวมของสัญญาณ Busy1, Done1, Busy2 และ Done2

 

6. กรณีที่เราทำการเปลี่ยนค่าใน Data block เช่นไปเพิ่มหรือลดข้อมูลใน Data block อาจะทำให้เรา Compile program ไม่ผ่าน และขึ้นว่าตัว Data block ที่เราแก้ไขยังไม่ได้ถูก compile ในกรณีนี้ก็แค่ให้ทำการ Compile Data block ตัวนั้นก่อน แล้วจึงทำการ Compile ตัวโปรแกรมใหม่อีกที
MCClientTCP_23.pngMCClientTCP_24.png

ภาคผนวก

Block MB_CLIENT รู้ได้อย่างไรว่าเราจะทำการอ่าน/เขียนค่าจาก Modbus Server เป็นแบบ word หรือแบบ bit และจะต้องใช้ Function code แบบไหนของ Modbus???

คำตอบคือ MB_CLIENT จะรู้จากการดูค่าที่เรากำหนดใน MB_MODE, MB_DATA_ADDR และ MB_DATA_LEN นั่นเอง

MCClientTCP_17.png
MCClientTCP_18.png
MCClientTCP_19.png

 

ในบางกรณี อุปกรณ์ Modbus Server มีหมายเลข Unit ID ด้วย แล้วเราจะใช้ Block MB_CLIENT ไปอ่านเขียนอุปกรณ์นั้นได้อย่างไร

คำตอบ: ปกติแล้วการใช้งานแบบ TCP นั้นจะใช้ IP address ในการอ้างอิงกันเป็นหลัก แต่สำหรับการสื่อสารแบบ Modbus แล้วยังมีสิ่งหนึ่งที่เรียกว่า Unit ID ด้วย นอกเหนือจากการใช้งาน IP address นั่นหมายความว่าการสื่อสาร Modbus นั้นต้องอ้างอิงทั้ง IP address และ Unit ID

ทำไมจึงเป็นเช่นนั้น??  ลองสังเกตรูปแบบเฟรมของ Modbus TCP ดูจากรูปข้างล่าง เราจะเห็นว่าทั้ง Modbus RTU และ Modbus TCP จะมี ID ที่ต้องอ้างอิงเอาไว้ในเฟรมเสมอ นี่จึงเป็นสาเหตว่าทำไมเราจึงต้องส่ง Unit ID เพื่ออ้างอิงไปหาอุปกรณ์ Modbus TCP Server ด้วย
MCClientTCP_28.png

แล้ว Unit ID มีประโยชน์อย่างไร ??? สำหรับการเชื่อมต่อปกติ เราคงไม่เห็นความสำคัญของการมี Unit ID บนระบบ TCP อย่างแน่นอน แต่ถ้าลองนึกภาพ application ตามรูปแบบดังรูปข้างล่างซึ่งไม่ใช่รูปแบบปกติทั่วไป แต่เป็นการต่อผ่านตัวแปลงจาก Modbus TCP ไปยัง Modbus RTU เราจะเห็นได้ว่า IP ที่ฝั่งตัวแปลงมีแค่ IP เดียว แต่ต้องส่งข้อมูลไปหาอุปกรณ์ RTU ที่เป็นแบบ RS485 ที่มี ID แตกต่างกันหลาย ID ที่อยู่บน IP address เดียวกัน
MCClientTCP_29

แล้วทำไมปกติเวลาเชื่อมต่อ Modbus TCP ไม่เห็นต้องระบุ Unit ID ก็ยังต่อได้ ??? ก็เนื่องจากปกติอุปกรณ์ Modbus TCP Server ทุกตัวจะมีค่า Default Unit ID = 255 และอุปกรณ์ Modbus TCP Client ก็จะอ้างไปที่ Unit ID=255 เป็นค่า default เช่นกัน จึงทำให้การเชื่อมต่อไม่เกิดปัญหาใดๆ

MCClientTCP_30.png
ตัวอย่างอุปกรณ์ Modbus TCP Server ที่สามารถตั้งค่า Unit ID ได้

แล้วจะตั้ง Unit ID ในจากคำสั่ง MB_CLIENT ได้ที่ไหน ??? การตั้งค่า Unit ID นั้นจะไม่ได้อยู่ที่ตัวของ block เอง แต่จะไปอยู่ใน Instance Data block ของคำสั่ง MB_CLIENT แทน อยู่ในหัวข้อที่ชื่อว่า MB_Unit_ID นั่นเอง (สังเกตว่าค่า default คือ 16#FF ซึ่งก็คือ 255 นั่นเอง)
MCClientTCP_31.png

 

 

 

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s