สอนใช้ 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 แบบ:
- CANopen Master (built-in) — PLC จะ initialize network เอง ส่ง NMT, Heartbeat, SDO ตามมาตรฐาน CiA-301 ทำให้สามารถเชื่อมต่อกับอุปกรณ์ CANopen ค่ายอื่น เช่น Servo Drive, Remote I/O Module ของ Wago, Beckhoff, Advantech ได้
- 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-DCFAs-32MT-AC-E/FAs-32MR-AC-EFAs-50MT-AC-E/FAs-50MR-AC-EFAs-66MT-AC-E/FAs-66MR-AC-E
S-Series Extension (รุ่นมี -C suffix ที่ด้านหลัง):
S-8X8T-CS-E16X-CS-16T-C
หมายเหตุเรื่อง
-MRvs-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_H | CAN High | สาย differential ขาบวก |
| CAN_L | CAN Low | สาย differential ขาลบ |
| GND | Ground | Common 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 Mbps | 25 m |
| 500 kbps | 100 m |
| 250 kbps | 250 m |
| 125 kbps | 500 m |
| 50 kbps | 1000 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
- ติ๊ก "配置和初始化" (Configure and Initialize) ในหน้า download
- Download project ไปที่ PLC
- Power-cycle PLC เพื่อให้ CAN stack boot ใหม่
คำสั่ง SEND_CAN — การส่งข้อมูล CAN
โครงสร้างคำสั่ง
SEND_CAN Timeout IDE Ident DLC Data Return
| พารามิเตอร์ | ประเภท | ความหมาย |
|---|---|---|
Timeout | Word (D) | เวลา timeout (ms) หาก send ไม่สำเร็จ เช่น K100 = 100ms |
IDE | Bit (M) | Frame type: OFF = Standard 11-bit, ON = Extended 29-bit |
Ident | Word/DWORD (D) | CAN ID (ถ้า IDE=ON ต้องใช้ DWORD เพราะ ID ใหญ่ถึง 29 bits) |
DLC | Word (D) | Data Length Code (0-8 bytes) |
Data | Word (D) start | Register ตัวแรกของข้อมูล — ใช้ต่อเนื่องตาม DLC |
Return | DWORD (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 การส่ง
- Enable rung ของ SEND_CAN ให้ทำงาน (เช่น ต่อกับ
M8151= always-on while RUN) - Set ค่าทั้งหมดไว้ใน register
- เขียน
K1ลงใน Return register → PLC จะส่ง 1 frame - หากสำเร็จ Return จะถูก auto-clear เป็น
0 - หากล้มเหลว Return จะเก็บ error code ไว้
Error Code ของ SEND_CAN
| ค่า | ความหมาย |
|---|---|
0x00000000 | สำเร็จ (auto-cleared) |
0x00000001 | กำลังส่ง (transmitting) |
0x00000003 | IDE error |
0x00000004 | DLC ไม่ถูกต้อง (0-8 เท่านั้น) |
0x05040000 | Timeout — ไม่มีใคร ACK (ตรวจสอบ bus มี node อื่นไหม, bitrate ตรงกันไหม) |
ข้อจำกัดที่ต้องรู้
⚠️ สำคัญ: คำสั่ง
SEND_CANใช้ได้ เพียง 1 ครั้งต่อ 1 ladder program เท่านั้นหากต้องการส่ง frame ที่มี ID หรือ data ต่างกัน ให้ทำแบบนี้:
- Enable คำสั่ง SEND_CAN ไว้ตลอด (ต่อกับ M8151)
- MOV ค่าใหม่ (ID, DLC, data) ลงใน register ของ SEND_CAN
- เขียน K1 ลงใน Return → ส่ง 1 frame ด้วยค่าที่เปลี่ยนแล้ว
คำสั่ง REV_CAN — การรับข้อมูล CAN
โครงสร้างคำสั่ง
REV_CAN RxStart Mask Filter
| พารามิเตอร์ | ประเภท | ความหมาย |
|---|---|---|
RxStart | Word (D) start | Register ตัวแรกของ buffer รับข้อมูล — จองต่อเนื่อง 10 word (5 DWORD) |
Mask | DWORD (D) | Mask bits ของ ID filter — 1 = bit นี้ต้องตรง, 0 = ไม่สน |
Filter | DWORD (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 byte | IDE flag (0 = standard, 0x04 = extended) |
| D1004 high byte | RTR flag (0 = data, 1 = remote request) |
| D1005 low byte | DLC (0-8) |
| D1005 high byte | FMI (Filter Match Index) |
| D1006, D1007 | Data byte 0-3 |
| D1008, D1009 | Data 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) ไม่ใช่ boolean0x01เพราะ 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 / ExtId | Standard frame อ่าน StdId (D+0), Extended อ่าน ExtId (D+2) — อีก field จะค้างค่าเก่า |
| DLC bounded write | RX buffer ไม่ zero byte ที่ไม่ได้ใช้ — ต้องเช็ค DLC ก่อนอ่าน data |
| No FIFO | REV_CAN เก็บแค่ frame ล่าสุด — frame ที่มาเร็วๆ อาจหายได้ |
| SEND_CAN 1 ครั้ง | ใช้ได้แค่ 1 instruction ต่อ program — เปลี่ยน parameter แล้วส่งซ้ำ |
| Enable Extension Module | ลืมติ๊ก → CAN port ไม่ทำงาน (silent failure) |
| ACK needed | Bus ต้องมี node อื่นอย่างน้อย 1 ตัว — ไม่งั้น SEND_CAN จะ timeout ทุกครั้ง |
| Self-receive | Samkoon ไม่ 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
มีคำถาม? ติดต่อทีมงาน


