หน้าแรกคู่มือPLCสอนใช้ CAN Bus และ CANopen กับ Samkoon PLC (SEND_CAN / REV_CAN)
PLC
ขั้นสูง
45 นาที

สอนใช้ CAN Bus และ CANopen กับ Samkoon PLC (SEND_CAN / REV_CAN)

คู่มือครบวงจรการใช้งาน CAN Bus บน Samkoon PLC ตั้งแต่การต่อสาย การตั้งค่าใน SamSoar2022 คำสั่ง SEND_CAN REV_CAN การใช้ Filter พร้อมตัวอย่างโค้ดและการทดสอบด้วย USB-CAN Adapter

อัพเดทล่าสุด: 20/4/2569

CAN Bus คืออะไร? ทำไมต้องใช้?

CAN Bus (Controller Area Network) คือโปรโตคอลการสื่อสารแบบ multi-master ที่ออกแบบมาสำหรับงานอุตสาหกรรมและยานยนต์ตั้งแต่ปี 1986 จุดเด่นหลักคือ:

  • ทนทาน (Robust) — ออกแบบมาสำหรับสภาพแวดล้อมที่มี noise สูง เช่น โรงงานและรถยนต์
  • Multi-master — ทุก node สามารถส่งข้อมูลได้ ไม่ต้องรออนุญาตจากใคร (ต่างจาก Modbus ที่มี Master/Slave)
  • Priority-based — Frame ที่มี ID น้อยกว่าจะได้ส่งก่อน (arbitration)
  • Short messages — แต่ละ frame ส่งข้อมูลได้สูงสุด 8 bytes (เร็วและแน่นอน เหมาะกับ real-time)
  • Error detection — มี CRC และ ACK ภายใน protocol

บน Samkoon PLC รุ่นที่รองรับ CAN เราสามารถใช้ได้ 2 แบบ:

  1. CANopen Master (built-in) — PLC จะ initialize network เอง ส่ง NMT, Heartbeat, SDO ตามมาตรฐาน CiA-301 ทำให้สามารถเชื่อมต่อกับอุปกรณ์ CANopen ค่ายอื่น เช่น Servo Drive, Remote I/O Module ของ Wago, Beckhoff, Advantech ได้
  2. Raw CAN (SEND_CAN / REV_CAN) — ส่ง/รับ CAN frame ดิบๆ ด้วย CAN ID และ data byte ที่เรากำหนดเอง เหมาะสำหรับโปรโตคอลเฉพาะ เช่น เชื่อมต่อกับ MCU อื่น, CAN Sensor, หรือระบบ custom

รุ่น Samkoon PLC ที่รองรับ CAN

คำสั่ง SEND_CAN และ REV_CAN รองรับรุ่นเหล่านี้:

PLC หลัก (Main PLC):

  • FAT-16MT-DC
  • FAs-32MT-AC-E / FAs-32MR-AC-E
  • FAs-50MT-AC-E / FAs-50MR-AC-E
  • FAs-66MT-AC-E / FAs-66MR-AC-E

S-Series Extension (รุ่นมี -C suffix ที่ด้านหลัง):

  • S-8X8T-C
  • S-E16X-C
  • S-16T-C

หมายเหตุเรื่อง -MR vs -MT: คู่มือ SamSoar2022 ฉบับเก่าระบุเฉพาะรุ่น -MT (Transistor output) ว่ารองรับ CAN แต่จากการตรวจสอบสินค้าจริง รุ่น -MR (Relay output) ก็มี CAN port ทางกายภาพเช่นกัน ความแตกต่างของ -MT กับ -MR อยู่ที่ชนิดของ Output (Transistor vs Relay) ไม่ใช่ความสามารถในการสื่อสาร

หากต้องการความมั่นใจ 100% ก่อนออกแบบระบบ — ทดสอบ CAN บน PLC รุ่นที่มีอยู่จริงตามวิธีใน section การทดสอบด้วย USB-CAN Adapter เพื่อยืนยัน

การต่อสาย CAN Bus

Pin ของ CAN Port

Samkoon PLC มี CAN port ที่ด้านข้าง (side connector) และบางรุ่น (-C variants) มีที่ด้านหลังด้วย — โดยทั้งสองเป็น CAN bus เดียวกัน ใช้ได้ port ใดก็ได้

Pinสัญญาณความหมาย
CAN_HCAN Highสาย differential ขาบวก
CAN_LCAN Lowสาย differential ขาลบ
GNDGroundCommon ground reference

Topology และ Termination

CAN Bus เป็น Linear bus topology — ทุก node ต่อขนานกันเป็นเส้นตรง ไม่ใช่ star หรือ ring

Node1 ─── Node2 ─── Node3 ─── Node4
 [120Ω]                        [120Ω]

กฎสำคัญ:

  • ต้องใส่ Termination Resistor 120Ω ที่ ปลายทั้งสองด้านของ bus (ไม่ใช่ที่ทุก node)
  • ใช้สายแบบ Shielded Twisted Pair เพื่อลด noise
  • วัดจาก CAN_H ↔ CAN_L ขณะปิดไฟ: ~60Ω = ปลายทั้งสองข้าง terminate แล้ว (ถูกต้อง), ~120Ω = terminate ข้างเดียว, เกือบ 0Ω หรือ เปิดวงจร = มีปัญหา

ความยาวสาย vs Bitrate

Bitrateความยาวสายสูงสุด (แนะนำ)
1 Mbps25 m
500 kbps100 m
250 kbps250 m
125 kbps500 m
50 kbps1000 m

สำหรับการทดลอง แนะนำใช้ 500 kbps — balance ดีระหว่างความเร็วและความยาวสาย

การตั้งค่า Project ใน SamSoar2022

ขั้นตอนที่ 1: สร้าง Project และเลือกรุ่น PLC

File > New Project
Project Name: CAN_Test
PLC Model: FAs-32MT-AC (หรือรุ่นที่รองรับ CAN)

ขั้นตอนที่ 2: ตั้งค่า CAN Communication

ไปที่เมนู 设置 > 工程设置 (Settings > Project Settings)

Tab "通信参数" (Communication Parameters) > CAN:

Node ID (节点号): 1
Bitrate (比特率): 500 kbps
Filter (滤波设置): Default หรือปล่อยว่าง

Node ID จะใช้เป็น CANopen Node ID ของ PLC ตัวนี้ และเป็น offset ของ heartbeat/boot-up frame (เช่น Node ID 1 = boot-up ที่ 0x701)

ขั้นตอนที่ 3: เปิดใช้งาน CAN Hardware

สำคัญมาก — CAN transceiver ของ PLC ไม่ทำงานจนกว่าจะเปิด toggle นี้:

Tab "扩展模块" (Extension Module):

☑ 启用扩展模块 (Enable Extension Module)

หากลืมติ๊กนี้ PLC จะไม่ส่งสัญญาณใดๆ ออกมาทาง CAN_H / CAN_L เลย (ทั้งที่ SEND_CAN compile ผ่าน)

ขั้นตอนที่ 4: Download Project

  1. ติ๊ก "配置和初始化" (Configure and Initialize) ในหน้า download
  2. Download project ไปที่ PLC
  3. Power-cycle PLC เพื่อให้ CAN stack boot ใหม่

คำสั่ง SEND_CAN — การส่งข้อมูล CAN

โครงสร้างคำสั่ง

SEND_CAN  Timeout   IDE   Ident   DLC   Data   Return
พารามิเตอร์ประเภทความหมาย
TimeoutWord (D)เวลา timeout (ms) หาก send ไม่สำเร็จ เช่น K100 = 100ms
IDEBit (M)Frame type: OFF = Standard 11-bit, ON = Extended 29-bit
IdentWord/DWORD (D)CAN ID (ถ้า IDE=ON ต้องใช้ DWORD เพราะ ID ใหญ่ถึง 29 bits)
DLCWord (D)Data Length Code (0-8 bytes)
DataWord (D) startRegister ตัวแรกของข้อมูล — ใช้ต่อเนื่องตาม DLC
ReturnDWORD (D)Trigger + Status code (32-bit ใช้ 2 word รวมกัน)

Byte Ordering ของ Data Register

ใน Samkoon register 1 word = 16-bit = 2 bytes เรียงแบบ little-endian (low byte ก่อน):

ถ้าต้องการส่ง 4 bytes: AA BB CC DD
ต้อง MOV:
  HBBAA  →  D200   (low byte AA = byte 0, high byte BB = byte 1)
  HDDCC  →  D201   (low byte CC = byte 2, high byte DD = byte 3)

บน CAN wire จะเป็น: AA BB CC DD ✓

การ Trigger การส่ง

  1. Enable rung ของ SEND_CAN ให้ทำงาน (เช่น ต่อกับ M8151 = always-on while RUN)
  2. Set ค่าทั้งหมดไว้ใน register
  3. เขียน K1 ลงใน Return register → PLC จะส่ง 1 frame
  4. หากสำเร็จ Return จะถูก auto-clear เป็น 0
  5. หากล้มเหลว Return จะเก็บ error code ไว้

Error Code ของ SEND_CAN

ค่าความหมาย
0x00000000สำเร็จ (auto-cleared)
0x00000001กำลังส่ง (transmitting)
0x00000003IDE error
0x00000004DLC ไม่ถูกต้อง (0-8 เท่านั้น)
0x05040000Timeout — ไม่มีใคร ACK (ตรวจสอบ bus มี node อื่นไหม, bitrate ตรงกันไหม)

ข้อจำกัดที่ต้องรู้

⚠️ สำคัญ: คำสั่ง SEND_CAN ใช้ได้ เพียง 1 ครั้งต่อ 1 ladder program เท่านั้น

หากต้องการส่ง frame ที่มี ID หรือ data ต่างกัน ให้ทำแบบนี้:

  1. Enable คำสั่ง SEND_CAN ไว้ตลอด (ต่อกับ M8151)
  2. MOV ค่าใหม่ (ID, DLC, data) ลงใน register ของ SEND_CAN
  3. เขียน K1 ลงใน Return → ส่ง 1 frame ด้วยค่าที่เปลี่ยนแล้ว

คำสั่ง REV_CAN — การรับข้อมูล CAN

โครงสร้างคำสั่ง

REV_CAN  RxStart   Mask   Filter
พารามิเตอร์ประเภทความหมาย
RxStartWord (D) startRegister ตัวแรกของ buffer รับข้อมูล — จองต่อเนื่อง 10 word (5 DWORD)
MaskDWORD (D)Mask bits ของ ID filter — 1 = bit นี้ต้องตรง, 0 = ไม่สน
FilterDWORD (D)ค่า ID ที่คาดหวัง — frame ผ่านถ้า (frame_id AND Mask) == (Filter AND Mask)

Layout ของ Buffer (เริ่มที่ RxStart)

สมมติ RxStart = D1000:

Registerข้อมูล
D1000 (low word of DWORD)StdId ของ frame — ใช้เมื่อ IDE=0
D1001 (high word)(ต่อของ StdId DWORD)
D1002 (low word of DWORD)ExtId ของ frame — ใช้เมื่อ IDE=1
D1003 (high word)(ต่อของ ExtId DWORD)
D1004 low byteIDE flag (0 = standard, 0x04 = extended)
D1004 high byteRTR flag (0 = data, 1 = remote request)
D1005 low byteDLC (0-8)
D1005 high byteFMI (Filter Match Index)
D1006, D1007Data byte 0-3
D1008, D1009Data byte 4-7

การอ่าน CAN ID ให้ถูกต้อง

REV_CAN เก็บ Standard ID และ Extended ID ใน field แยกกัน ต้องดูที่ IDE ก่อนเสมอ:

# IDE byte (D1004 low byte)
ถ้า = 0x00 → Standard 11-bit frame → อ่าน ID จาก D1000 DWORD
ถ้า = 0x04 → Extended 29-bit frame → อ่าน ID จาก D1002 DWORD

⚠️ Quirk ที่ต้องรู้: IDE byte ของ Samkoon ใช้ bit 2 (value 0x04) ไม่ใช่ boolean 0x01 เพราะ copy ค่าดิบจาก STM32 CAN_RIR register ดังนั้นใน ladder ต้อง AND H4 กับ D1004 low byte เพื่อเช็ค

ข้อจำกัดที่ต้องรู้

⚠️ ไม่มี FIFO buffer — หาก frame มาถี่ๆ register จะถูก overwrite ตัวใหม่ ไม่เก็บประวัติ

แนะนำ: อ่านข้อมูลและ copy ไปเก็บใน register อื่นทันทีใน scan cycle เดียวกัน

⚠️ Data byte ที่ไม่ได้ใช้ไม่ถูก clear — หาก frame ใหม่มี DLC=2 แต่ frame ก่อนหน้ามี DLC=8 ค่า byte 2-7 จะยังค้างจาก frame ก่อน

วิธีแก้: เช็ค DLC เสมอ และอ่านเฉพาะ byte 0 ถึง (DLC-1) เท่านั้น

Mask และ Filter — การกรอง CAN Frame

หลักการ

Samkoon ใช้ semantic มาตรฐาน: Mask bit = 1 หมายถึง "bit นี้ต้องตรงกับ Filter", Mask bit = 0 หมายถึง "bit นี้ไม่สนใจ"

เกณฑ์การรับ frame:

(frame_id AND Mask) == (Filter AND Mask)

ตัวอย่างการตั้งค่า Mask/Filter

รับทุก frame (Accept All):

Mask = 0x00000000
Filter = 0x00000000
→ (any & 0) == (0 & 0) = true เสมอ

รับเฉพาะ ID 0x456 เท่านั้น:

Mask = 0x000007FF  (ทุก bit ของ 11-bit ID ต้องตรง)
Filter = 0x00000456
→ รับ 0x456 ✓, ปฏิเสธทุก ID อื่น ✗

รับทุก ID ในช่วง 0x100-0x1FF:

Mask = 0x00000700  (เช็คเฉพาะ 3 bit บนสุดของ 11-bit)
Filter = 0x00000100
→ รับ 0x100, 0x123, 0x1FF ✓, ปฏิเสธ 0x200, 0x300 ✗

รับ Extended frame ID 0x1ABCDEF0:

Mask = 0x1FFFFFFF  (ทุก bit ของ 29-bit)
Filter = 0x1ABCDEF0

ตัวอย่างโปรแกรม Ladder สมบูรณ์

นี่คือโครงสร้าง ladder program ครบวงจรสำหรับทดสอบ CAN แบ่งเป็น 3 network:

Network 1: Initialize (ใช้ M8150 — First Scan)

|--[ M8150 ]--[ MOV  K100    D0  ]--|      ; Timeout = 100ms
             |
             |--[ MOV  H123   D10 ]--|      ; CAN ID = 0x123 (Standard frame)
             |
             |--[ MOV  K4     D100]--|      ; DLC = 4 bytes
             |
             |--[ MOV  HBBAA  D200]--|      ; Data byte 0-1: AA BB
             |
             |--[ MOV  HDDCC  D201]--|      ; Data byte 2-3: CC DD

|--[ M8150 ]--[ DMOV H7FF    D1100 ]--|     ; Mask = 0x7FF (เช็คทุก bit ของ 11-bit ID)
             |
             |--[ DMOV H456    D1200 ]--|   ; Filter = 0x456 (รับเฉพาะ ID 0x456)

Network 2: SEND_CAN และ REV_CAN (ใช้ M8151 — Always On while RUN)

|--[ M8151 ]--[ SEND_CAN  D0  M0  D10  D100  D200  D300 ]--|
                         ^    ^   ^    ^     ^     ^
                         |    |   |    |     |     Return (DWORD)
                         |    |   |    |     Data start
                         |    |   |    DLC
                         |    |   CAN ID
                         |    IDE bit (OFF = 11-bit standard)
                         Timeout

|--[ M8151 ]--[ REV_CAN  D1000  D1100  D1200 ]--|
                        ^       ^      ^
                        |       |      Filter (DWORD)
                        |       Mask (DWORD)
                        Rx buffer start (จอง 10 word)

Network 3: Manual Trigger (พิมพ์ K1 เพื่อส่ง 1 frame)

|--[ M100 ]--[ MOV  K1  D300 ]--[ RST M100 ]--|

กด M100 ใน Device Monitor 1 ครั้ง → เขียน K1 ลง D300 → PLC ส่ง 1 frame → M100 reset อัตโนมัติ

อ่าน Frame ที่ได้รับ

หลังจาก REV_CAN รับ frame เข้ามา:

# อ่าน ID (ต้องเช็ค IDE ก่อน)
[ D1004 AND H4 ] == 0    → Standard frame, ID อยู่ที่ D1000 DWORD
[ D1004 AND H4 ] != 0    → Extended frame, ID อยู่ที่ D1002 DWORD

# อ่าน DLC
DLC = D1005 AND HFF   (เอาเฉพาะ low byte)

# อ่าน Data byte (เฉพาะ DLC byte แรก)
Byte 0 = D1006 AND HFF       (low byte ของ D1006)
Byte 1 = (D1006 SHR 8) AND HFF  (high byte ของ D1006)
Byte 2 = D1007 AND HFF
Byte 3 = (D1007 SHR 8) AND HFF
... (ไปจนถึง DLC byte)

การทดสอบด้วย USB-CAN Adapter

หากต้องการทดสอบว่า CAN port ของ PLC ใช้งานได้จริง แนะนำใช้ USB-CAN Adapter เชื่อมกับ Linux หรือ Windows

Hardware ที่แนะนำ

  • CANable 2.0 (~$25) — Open hardware, ใช้งานกับ Linux socketcan ได้
  • WaveShare USB-CAN-A (~$20) — มี GUI บน Windows
  • USB-CAN FD adapters — ทำงานได้ใน classic CAN mode (backward compatible)

การตั้งค่าบน Linux (socketcan)

# Bring up interface ที่ 500 kbps (ตรงกับ PLC)
sudo ip link set can0 down 2>/dev/null
sudo ip link set can0 type can bitrate 500000
sudo ip link set can0 up

# ดู frame ที่เข้ามา (แยก terminal)
candump -tz can0

# ส่ง frame ไปให้ PLC
cansend can0 456#11223344        # Standard 11-bit ID 0x456, 4 bytes
cansend can0 1ABCDEF0#CAFEBABE   # Extended 29-bit ID, 4 bytes
cansend can0 7FF#AA              # Max 11-bit ID, 1 byte

สังเกตการทำงานของ PLC

เมื่อเปลี่ยน PLC จาก STOP → RUN บน candump จะเห็น CANopen initialization sequence:

(000.000000)  can0  000   [2]  80 00      ← NMT: Enter Pre-Operational (all nodes)
(001.154562)  can0  701   [1]  00         ← Boot-up message จาก Node 1
(001.154780)  can0  7E5   [8]  04 00 ...  ← LSS SwitchStateGlobal
(001.170933)  can0  000   [2]  01 01      ← NMT: Start Node 1 (เข้าสู่ Operational)

ถ้าเห็น frame เหล่านี้ = CAN port ทำงานได้สมบูรณ์ และ PLC เป็น CANopen Master มาตรฐาน

Quirks และข้อควรระวัง (สรุป)

จากการทดลองจริง สิ่งที่ต้องจำไว้เสมอเมื่อเขียน ladder program:

เรื่องรายละเอียด
IDE encodingใช้ bit 2 (value 0x04) ไม่ใช่ 0x01 — ต้อง AND H4 เพื่อเช็ค
StdId / ExtIdStandard frame อ่าน StdId (D+0), Extended อ่าน ExtId (D+2) — อีก field จะค้างค่าเก่า
DLC bounded writeRX buffer ไม่ zero byte ที่ไม่ได้ใช้ — ต้องเช็ค DLC ก่อนอ่าน data
No FIFOREV_CAN เก็บแค่ frame ล่าสุด — frame ที่มาเร็วๆ อาจหายได้
SEND_CAN 1 ครั้งใช้ได้แค่ 1 instruction ต่อ program — เปลี่ยน parameter แล้วส่งซ้ำ
Enable Extension Moduleลืมติ๊ก → CAN port ไม่ทำงาน (silent failure)
ACK neededBus ต้องมี node อื่นอย่างน้อย 1 ตัว — ไม่งั้น SEND_CAN จะ timeout ทุกครั้ง
Self-receiveSamkoon ไม่ receive frame ของตัวเอง (default)

Troubleshooting

อาการ: SEND_CAN return 0x05040000 ทุกครั้ง (Timeout)

สาเหตุที่พบบ่อย:

  • Bus มี PLC อยู่ตัวเดียว ไม่มี node อื่น ACK — ลองต่อ USB-CAN adapter เพิ่ม
  • Bitrate ไม่ตรงกับ node อื่น — ตรวจสอบทั้งสองฝั่ง
  • Termination resistor ขาด หรือมีแค่ข้างเดียว — วัด 60Ω ระหว่าง H-L
  • CAN_H / CAN_L สลับกัน — ลองสลับสาย

อาการ: ไม่เห็น frame บน candump เลย

สาเหตุที่พบบ่อย:

  • ลืมติ๊ก "启用扩展模块" (Enable Extension Module) ใน Project Settings
  • ไม่ได้ติ๊ก "配置和初始化" ตอน download
  • Bitrate บน adapter ไม่ตรงกับ PLC
  • PLC ยังอยู่ใน STOP mode — ต้อง switch เป็น RUN

อาการ: REV_CAN ไม่รับ frame ที่ cansend จาก Linux

สาเหตุที่พบบ่อย:

  • Mask/Filter ไม่ตรง — ลอง set Mask=0, Filter=0 (accept all) ก่อน
  • Adapter อยู่ใน listen-only mode — จะไม่ ACK, PLC เห็น frame เป็น error
  • IDE ไม่ตรง — ถ้าส่ง extended ID ต้องใช้ 8-hex digit เช่น 1ABCDEF0 ไม่ใช่ ABCDEF0

อาการ: Data byte ที่รับมาเรียงแปลกๆ

ตรวจสอบ byte ordering — Samkoon ใช้ little-endian:

  • cansend can0 123#11223344
  • บน PLC: D1006 = 0x2211, D1007 = 0x4433
  • เพราะ: low byte ของ register = byte แรกของ frame

สรุป

Samkoon PLC (รุ่นที่รองรับ ทั้ง -MT และ -MR) มี CAN port ที่สมบูรณ์ตามมาตรฐาน CiA-301:

  • CANopen Master built-in — initialize network, NMT, Heartbeat, LSS
  • Raw CAN TX ผ่าน SEND_CAN — กำหนด ID, DLC, data ได้เอง
  • Raw CAN RX ผ่าน REV_CAN — รับพร้อม hardware filter
  • Standard 11-bit (CAN 2.0A) และ Extended 29-bit (CAN 2.0B)
  • Bitrate ปรับได้ 50 kbps - 1 Mbps

ใช้เชื่อมต่อกับ:

  • Servo Drive ที่รองรับ CANopen (Maxon, Elmo, Copley, etc.)
  • Remote I/O Module ของ Wago, Beckhoff, Advantech
  • Sensor / Device ที่มี CAN interface
  • MCU และระบบ custom ผ่าน raw CAN frame

เป็นความสามารถที่ Mitsubishi FX series ไม่มี built-in (ต้องซื้อ FX3U-CAN Module เพิ่ม) ทำให้ Samkoon PLC มีจุดเด่นที่เหนือกว่าในงานที่ต้องใช้ CAN Bus

สินค้าที่ใช้ในบทความนี้
3 รายการ
FAs-32MT-AC-E
FAs-32MT-AC-E

PLC 32 I/O 220V AC Transistor Output รองรับ Modbus RTU/RS485 TCP/IP

฿3,690

FAs-50MT-AC-E
FAs-50MT-AC-E

PLC 50 I/O 220V AC Transistor Output รองรับ Modbus RTU/RS485 TCP/IP

฿5,690

FAs-66MT-AC-E
FAs-66MT-AC-E

PLC 66 I/O 220V AC Transistor Output รองรับ Modbus RTU/RS485 TCP/IP

฿6,490

รวมทั้งหมด

฿15,870