การอ่านค่าจากเพาเวอร์มิเตอร์ไฟฟ้าเฟสเดียว: SDM120-Modbus#
บทความนี้กล่าวถึง การทดลองอ่านค่าจากเพาเวอร์มิเตอร์เฟสเดียว รุ่น SDM120 โดยเชื่อมต่อผ่านบัส RS485 และใช้โฟรโตคอล Modbus RTU
Keywords: Single-Phase Power Meter, SDM120M, RS485, Modbus RTU, Python, Arduino Sketch, ESP32-C3
▷ เพาเวอร์มิเตอร์แบบดิจิทัล#
มิเตอร์วัดกำลังไฟฟ้า หรือ "เพาเวอร์มิเตอร์" แบบดิจิทัล (Digital Power Meter) เป็นอุปกรณ์ที่ใช้สำหรับการวัดค่าหรือพารามิเตอร์ต่าง ๆ สำหรับไฟฟ้ากระแสสลับ เช่น
- ความถี่ (Hz)
- แรงดันไฟฟ้า (V)
- กระแสไฟฟ้า (I)
- ค่าเพาเวอร์แฟคเตอร์ หรือ ค่าตัวประกอบกำลังไฟฟ้า (Power Factor)
- กำลังไฟฟ้าที่ใช้งานจริง (Real Power: kW)
- กำลังไฟฟ้าที่ปรากฏ (Apparent Power: kVA)
- กำลังไฟฟ้ารีแอคทีฟ (Reactive Power: kVAr)
- พลังงานไฟฟ้าที่ใช้ (Active Energy: kWh)
มิเตอร์ไฟฟ้าประเภทนี้ จำแนกได้ตามจำนวนเฟสไฟฟ้าที่ต้องการวัดทางไฟฟ้า ได้แก่ มิเตอร์แบบเฟสเดียว (Single-Phase Power Meter) และมิเตอร์แบบสามเฟส (3-Phase Power Meter) นอกจากมีหน้าจอแสดงผลแบบ LCD มิเตอร์ไฟฟ้าแบบดิจิทัลในยุคปัจจุบัน ยังรองรับการเชื่อมต่อด้วยโพรโทคอล Modbus RTU และเชื่อมต่อกับระบบบัส RS485 ได้ด้วย
การต่อวงจรไฟฟ้าเพื่อใช้งานมิเตอร์ มีหลายรูปแบบ โดยดูจากความจำเป็นที่ต้องใช้อุปกรณ์อื่นร่วมด้วยหรือไม่ เช่น การใช้หม้อแปลงแรงดันไฟฟ้า (Potential Transformer: PT) และหม้อแปลงกระแสไฟฟ้า (Current Transformer: CT) เพื่อการลดทอนแรงดันไฟฟ้าด้วย PT หรือลดกระแสไฟฟ้าด้วย CT ให้มีค่าต่ำลงและอยู่ในช่วงเหมาะสมกับมิเตอร์ไฟฟ้า
▷ มิเตอร์เฟสเดียว: SDM120(M)#
ข้อมูลเชิงเทคนิคเกี่ยวกับมิเตอร์ไฟฟ้ารุ่น SDM120-MODBUS (แบรนด์สินค้า Eastron)
- เป็นมิเตอร์ไฟฟ้าดิจิทัลแบบเฟสเดียว Single-Phase Digital Power Meter
- เชื่อมต่อด้วยสาย L (Line) และ N (Neutral)
- วัดกระแสไฟฟ้าโดยตรง (direct connected) ไม่ได้ใช้หม้อแปลงสำหรับวัดกระแส (Current Transformer: CT)
- คลาสความแม่นยำสำหรับการวัดแรงดันและกระแสไฟฟ้า: 0.5
- รองรับแรงดันอินพุต: 176 ~ 276V AC
- รองรับกระแสไฟฟ้า: 0.25A ~ 5A (45A max.)
- วัดค่าพลังงาน (kWh) และกำลังไฟฟ้า (kW) ได้ทั้งสองทิศทาง (Bi-directional measurment)
- อ่านข้อมูลได้ผ่านบัส RS485 ร่วมกับโพรโทคอล Modbus RTU
- ค่า Baudrate: 2400 (default), 4800, 9600
- ตั้งค่าหมายเลขอุปกรณ์ (Device Address) ได้ในช่วง 1 ~ 247
- ให้เอาต์พุตเป็นแบบพัลส์ (Pulsed Outputs)
- ผ่านมาตรฐาน MID (Measuring Instruments Directive, B and D)
- สามารถติดตั้งบนรางปีกนกได้ (DIN Rail Mounting)
รูป: SDM120M Digital Power Meter
รูป: การเชื่อมต่อกับมิเตอร์ (Wiring Diagram)
การต่อสายไฟจาก L และ N ไปยังมิเตอร์และโหลดไฟฟ้า
- 1: สาย L (Line-In) เพื่อให้กระแสวิ่งเข้าไปในตัวมิเตอร์
- 2 สาย L (Line-Out) เพื่อให้กระแสวิ่งออกจากตัวมิเตอร์ไปยังโหลดไฟฟ้า
- 3, 4: สาย N (Neutral)
- 5, 6, 7: เป็นเอาต์พุตแบบพัลส์ Pulse Out 1 (Export kWh), GND, Pulse Out 2 (Import kWh)
- 8, 9, 10: GND ของวงจร สัญญาณ B และ A ตามลำดับ
รูป: ตัวอย่างการต่อมิเตอร์หลายตัวในระบบบัส RS485 และมีตัวต้านทาน 120 โอห์ม ปิดปลายทั้งสองด้าน
รูป: ตัวอย่างอุปกรณ์ที่ได้นำมาทดลอง
รูป: จอแสดงผล LCD เมื่อกดปุ่มเพื่อแสดงค่าแรงดันไฟฟ้า (AC Voltage) ที่วัดได้ด้วยมิเตอร์
รูป: จอแสดงผล LCD เมื่อกดปุ่มเพื่อแสดงค่า Meter ID (001)
รูป: จอแสดงผล LCD เมื่อกดปุ่มเพื่อแสดงค่า Baudrate (2400: default)
ไฟล์เอกสารสำหรับการใช้งานมิเตอร์
ตามโพรโทคอลของ Modbus RTU การเขียนหรืออ่านข้อมูลรีจิสเตอร์ แต่ละตัวมีขนาด 2 ไบต์ หรือ 16 บิต ( Big-endian encoding) มีการจำแนกประเภทหรือแบ่งกลุ่มซึ่งจะใช้ คำสั่ง Function Code (FC) แตกต่างกัน เช่น
- Input Registers เป็นรีจิสเตอร์สำหรับข้อมูล (ขนาด 2 ไบต์) ที่ใช้เป็นอินพุตของโมดูลหรือมีการเปลี่ยนแปลงได้
- ใช้คำสั่ง FC = 0x04 (Read Input Registers) อ่านค่าจากรีจิสเตอร์หนึ่งตัว (หรือมากกว่าหนึ่งตัวแต่มีแอดเดรสต่อเนื่องกัน)
- Holding Registers เป็นรีจิสเตอร์สำหรับข้อมูล (ขนาด 2 ไบต์) เช่น การตั้งค่าการใช้งานสำหรับโมดูล
- ใช้คำสั่ง FC = 0x03 (Read Multiple Holding Registers) อ่านค่าจากรีจิสเตอร์หนึ่งตัว (หรือมากกว่าหนึ่งตัวแต่มีแอดเดรสต่อเนื่องกัน)
- ใช้คำสั่ง FC = 0x06 (Write Single Holding Register) เขียนค่ารีจิสเตอร์หนึ่งตัว
- ใช้คำสั่ง FC = 0x10 (Write Multiple Holding Registers) เขียนค่ารีจิสเตอร์มากกว่าหนึ่งตัว
รีจิสเตอร์ภายในมิเตอร์ SDM120 แบ่งเป็น 2 กลุ่มคือ
- รีจิสเตอร์อินพุตของมิเตอร์ (Modbus Input Registers) ดังนั้นจึงใช้ Function Code เท่ากับ 0x04 ในการอ่านค่า
- รีจิสเตอร์สำหรับการตั้งค่าของมิเตอร์ (Modbus Holding Registers) ดังนั้นจึงใช้ Function Code เท่ากับ 0x03 ในการอ่านค่า
รูป: แอดเดรสของรีจิสเตอร์อินพุตของมิเตอร์ (Modbus Input Registers)
จากตารางจะเห็นได้ว่ามีการระบุแอดเดรสในช่วง 30001 ~ 30345
สำหรับรีจิสเตอร์อินพุตแต่ละตัว
ให้ดูที่แอดเดรสเริ่มต้น (Start Address Hex) ซึ่งเป็นเลขฐานสิบหก
และใช้ Function Code = 0x03 สำหรับการอ่านค่า
0x0000 - 0x0001
หมายถึง รีจิสเตอร์ 2 ตัว (32 บิต) สำหรับแรงดันไฟฟ้า0x0006 - 0x0007
หมายถึง รีจิสเตอร์ 2 ตัว (32 บิต) สำหรับกระแสไฟฟ้า0x000C - 0x000D
หมายถึง รีจิสเตอร์ 2 ตัว (32 บิต) สำหรับกำลังไฟฟ้าที่ใช้จริง
รูป: แอดเดรสของรีจิสเตอร์สำหรับการตั้งค่าของมิเตอร์ (Modbus Holding Registers)
จากตารางสำหรับรีจิสเตอร์เพื่อการตั้งค่าใช้งาน และใช้ Function Code = 0x4 สำหรับการอ่านค่า
0x0014
~0x0015
หมายถึง รีจิสเตอร์ 2 ตัว (32 บิต) สำหรับหมายเลขอุปกรณ์ (Device Address)0x001C
~0x001D
หมายถึง รีจิสเตอร์ 2 ตัว (32 บิต) สำหรับค่า Baudrate (0=2400, 1=4800, 2=9600, ...)
ถ้าต้องการอ่านค่าจากรีจิสเตอร์ เพื่อให้ได้ค่า float (32 บิต)
จะต้องส่งเฟรมข้อมูล (Request Frame) ไปยังมิเตอร์ โดยมีลำดับข้อมูลไบต์ดังนี้
- Slave Address: แอดเดรสของมิเตอร์ (1 ไบต์)
- Function Code: โค้ดของฟังก์ชัน (1 ไบต์) เช่น 0x03 หรือ 0x04
- Start Address (High Byte): แอดเดรสเริ่มต้นของรีจิสเตอร์ที่ต้องการอ่านค่า (ไบต์สูง)
- Start Address (Low Byte): แอดเดรสเริ่มต้นของรีจิสเตอร์ที่ต้องการอ่านค่า (ไบต์ต่ำ)
- Number of Registers (High Byte): จำนวนรีจิสเตอร์ที่ต้องการอ่าน (ไบต์สูง)
- Number of Registers (Low Byte): จำนวนรีจิสเตอร์ที่ต้องการอ่าน (ไบต์ต่ำ)
- CRC16 (Low Byte): ค่าตัวเลขสำหรับ 16-bit CRC Checksum (ไบต์ต่ำ)
- CRC16 (High Byte): ค่าตัวเลขสำหรับ 16-bit CRC Checksum (ไบต์สูง)
เฟรมข้อมูลที่ได้รับการตอบกลับมา (Response Frame) หากทำคำสั่งได้ถูกต้อง (เช่น อ่านค่ารีจิเตอร์ 2 ตัว) มีลักษณะดังนี้
- Slave Address แอดเดรสของมิเตอร์ (1 ไบต์)
- Function Code: โค้ดของฟังก์ชัน (1 ไบต์) เช่น 0x03 หรือ 0x04
- Byte Count: จำนวนไบต์ของข้อมูลที่ตามมา
- First Register (High Byte): ค่าของรีจิสเตอร์ตัวแรก (ไบต์สูง)
- First Register (Low Byte): ค่าของรีจิสเตอร์ตัวแรก (ไบต์ต่ำ)
- Second Register (High Byte): ค่าของรีจิสเตอร์ตัวที่สอง (ไบต์สูง)
- Second Register (Low Byte): ค่าของรีจิสเตอร์ตัวที่สอง (ไบต์ต่ำ)
- CRC16 (Low Byte): ค่าตัวเลขสำหรับ 16-bit CRC Checksum (ไบต์ต่ำ)
- CRC16 (High Byte): ค่าตัวเลขสำหรับ 16-bit CRC Checksum (ไบต์สูง)
รูป: เฟรมข้อมูลสำหรับการส่งคำสั่งไปยังมิเตอร์และเฟรมข้อมูลที่ได้รับตอบกลับจากมิเตอร์ เมื่อต้องการอ่านค่าในรีจิสเตอร์
▷ ตัวอย่างโค้ด: Python#
โค้ดตัวอย่าง Python ต่อไปนี้สาธิตการอ่านค่าจากมิเตอร์ ตามแอดเดรสของรีจิสเตอร์ต่าง ๆ
โดยใช้ไลบรารี MinimalModbus
และคอมพิวเตอร์ของผู้ใช้จะต้องเชื่อมต่อ
โดยใช้อุปกรณ์ USB-to-RS485 จึงจะสามารถเชื่อมต่อกับบัส RS485 ไปยังมิเตอร์ไฟฟ้าได้
ในโค้ดจะต้องมีการระบุหมายเลขของมิเตอร์ (อยู่ในช่วง 1 ~ 247)
พอร์มอนุกรมสำหรับการสื่อสาร เช่น /dev/ttyUSB0
สำหรับ Linux
และค่า Baudrate ให้ตรงกับการตั้งค่าของมิเตอร์ เช่น 2400
#!/usr/bin/python
import minimalmodbus # Use the MinimalModbus package
# Set the device address
dev_addr = 1
# Set the serial port
serial_port = '/dev/ttyUSB0'
# Set the baudrate
baudrate = 2400 # default: 2400
rs485 = minimalmodbus.Instrument(serial_port, dev_addr)
rs485.serial.baudrate = baudrate
rs485.serial.bytesize = 8
rs485.serial.parity = minimalmodbus.serial.PARITY_NONE
rs485.serial.stopbits = 1
rs485.serial.timeout = 0.5
rs485.debug = False
rs485.mode = minimalmodbus.MODE_RTU
params = [
{"reg_addr": 0x0000, "name": "Voltage", "unit": "V"},
{"reg_addr": 0x0006, "name": "Current", "unit": "A"},
{"reg_addr": 0x000C, "name": "Active Power", "unit": "W"},
{"reg_addr": 0x0012, "name": "Apparent Power", "unit": "VA"},
{"reg_addr": 0x0018, "name": "Reactive Power", "unit": "VAr"},
{"reg_addr": 0x001E, "name": "Power Factor", "unit": "-"},
{"reg_addr": 0x0046, "name": "Frequency", "unit": "Hz"},
{"reg_addr": 0x0156, "name": "Total Active Energy", "unit": "kWh"},
]
print( "SDM120 Modbus - Digital Power Meter ")
try:
for param in params:
value = rs485.read_float(
registeraddress=param["reg_addr"],
functioncode=4,
number_of_registers=2 )
print( f'0x{hex(param["reg_addr"])[2:].zfill(4)}:',
f'{param["name"]:>20s},',
f'{value:7.3f}',
f'[{param["unit"]}]' )
except Exception as ex:
print(ex)
finally:
if rs485.serial:
rs485.serial.close()
print('Done..')
คำสั่งของ MinimalMobdus ที่ใช้ในการอ่านค่าจากริจีสเตอร์อินพุต คือ read_float(...)
ซึ่งจะต้องระบุแอดเดรสของรีจิสเตอร์
ตามด้วยค่าสำหรับ Function Code เช่น 3 หรือ 4 จำนวนของรีจิสเตอร์ที่ต้องการอ่าน
(ถ้าเป็นข้อมูลตัวเลขแบบ float
จะต้องอ่าน 2 ริจิสเตอร์ เพื่อให้ได้ 32 บิต) และลำดับของไบต์ข้อมูล
(ค่า default คือ 0 ซึ่งหมายถึง Big-endian)
read_float(
registeraddress: int,
functioncode: int = 3,
number_of_registers: int = 2,
byteorder: int = 0) → float
รูป: ตัวอย่างข้อความเอาต์พุตจากการรันโค้ดตัวอย่าง Python
ตัวอย่างโค้ดถัดไป (ตัดแสดงมาเฉพาะบางส่วนที่สำคัญ) แสดงการใช้คำสั่ง (ใช้ Function Code = 0x03) เพื่ออ่านค่าจากรีจิสเตอร์สำหรับการตั้งค่าใช้งานของมิเตอร์ เช่น หมายเลของอุปกรณ์ (Meter ID) รหัสของมิเตอร์ (Serial Number) เป็นต้น มีดังนี้
# ....
print( "SDM120 Modbus - Digital Power Meter ")
METER_ID_REG_ADDR = 0x0014
METER_SN_REG_ADDR = 0xFC00
BAUDRATE_REG_ADDR = 0x001C
value = rs485.read_float(
registeraddress=METER_ID_REG_ADDR,
functioncode=3,
number_of_registers=2 )
meter_id = int(value)
print(f'Meter ID: {meter_id}')
value = rs485.read_long(
registeraddress=METER_SN_REG_ADDR,
functioncode=3)
meter_sn = hex(value)[2:].zfill(8)
print(f'Meter S/N: {meter_sn} (hex)')
value = rs485.read_float(
registeraddress=BAUDRATE_REG_ADDR,
functioncode=3,
number_of_registers=2 )
value = int(value)
if value < 5:
meter_baudrate = (1<<value)*2400
print(f'Baudrate: {meter_baudrate}')
ถ้าต้องการจะเปลี่ยนค่า Baudrate เช่น จาก 0=2400 ให้เป็น 2=9600 ก็มีตัวอย่างการเขียนโค้ด โดยใช้คำสั่งสำหรับ Function Code = 0x10 ดังนี้
BAUDRATE_REG_ADDR = 0x001C
# Set the baudrate to 9600 (note: 0=2400, 1=4800, 2=9600)
# To enter the setup mode, press the button on the meter for 5 sec.
try:
rs485.write_float( registeraddress=BAUDRATE_REG_ADDR, value=2 )
except minimalmodbus.ModbusException as ex:
print( ex )
ข้อสังเกต: ถ้าต้องการเขียนค่าลงในรีจิสเตอร์ เช่น เพื่อเปลี่ยนค่า Baudrate จะต้องมีการกดปุ่มที่มิเตอร์ค้างไว้ อย่างน้อย 5 วินาที เพื่อเข้าสู่โหมด Setup ก่อนการส่งคำสั่งไปยังมิเตอร์
รูป: จอแสดงผลของมิเตอร์เมื่ออยู่ในโหมด Setup
รูป: การตั้งค่า Baudrate ให้เป็น 9600 ได้สำเร็จแล้ว
▷ โค้ดตัวอย่าง: Arduino Sketch#
ในการเขียนโค้ด Arduino Sketch สำหรับบอร์ดไมโครคอนโทรลเลอร์ (เลือกใช้ ESP32-C3) จะต้องใช้ร่วมกับโมดูล Serial-to-RS485 ในตัวอย่างนี้ ได้เลือกใช้ขา Tx=GPIO21 และ Rx=GPIO20 สำหรับวงจร Hardware Serial หมายเลข 0 ของ ESP32-C3 SoC เพื่อนำไปต่อกับโมดูล RS485 Transceiver (ตั้งค่า Baudrate 9600) ขา A และ B ของโมดูล RS485 Transceiver เชื่อมต่อด้วยสายไฟหนึ่งคู่ไปยังช่องสัญญาณ A และ Bsr ของมิเตอร์ไฟฟ้า การเชื่อมต่อกับคอมพิวเตอร์ผู้ใช้ จะใช้วิธี USB-CDC เพื่อการอัปโหลด Arduino Sketch และการรับข้อความจากบอร์ดไมโครคอนโทรลเลอร์
ฟังก์ชัน read_regs(...)
ใช้สำหรับการอ่านค่าจากรีจิสเตอร์ขนาด 16 บิต ได้มากกว่าหนึ่งตัว
และอีกฟังก์ชัน read_float(...)
จะใช้สำหรับการอ่านค่าจากรีจิสเตอร์ตามแอดเดรสของรีจิสเตอร์ที่ต้องการ
แต่อ่านรีจิสเตอร์ 2 ตัว เพื่อให้ได้ค่าเป็น float (32 บิต)
ฟังก์ชัน calc_modbus_crc(...)
ใช้สำหรับการคำนวณค่า 16-bit CRC
และใช้ในการตรวจสอบความถูกต้องสำหรับเฟรมข้อมูลที่มีการส่งไปและได้รับตอบกลับมา
//////////////////////////////////////////////////////////////
// Date: 2024-01-29
// Board: Super-Mini ESP32-C3
// Arduino IDE: v2.2.1
// Arduino ESP32 Core: v3.0.0aplha3
//////////////////////////////////////////////////////////////
#include <HardwareSerial.h>
// Use Hardware Serial 0 or 1
#define HW_SERIAL (0)
HardwareSerial RS485( HW_SERIAL );
//#define RS485 Serial0
void setup() {
Serial.begin(115200); // USB-CDC
while(!Serial);
RS485.begin(9600); // Set the baudrate for the power meter
// Set Tx/Rx pins for RS485-serial
if (HW_SERIAL==0) {
// Default pins for Serial0: RX=GPIO20, TX=GPIO21
RS485.setPins( 20 /*RX*/, 21 /*TX*/ );
} else {
// Default pins for Serial1: RX=GPIO18, TX=GPIO19
RS485.setPins( 10 /*RX*/, 9 /*TX*/ );
}
RS485.setRxTimeout(1);
RS485.flush();
delay(1000);
Serial.println("\n\n\n\n\n");
Serial.flush();
Serial.println( "Arduino-ESP32C3 Demo..." );
Serial.println( "Power Meter Reading: Eastron SDM120 Modbus\n");
Serial.flush();
}
// Calculate the CRC of a Modbus RTU response.
uint16_t calc_modbus_crc(const byte* data, size_t len) {
uint16_t crc = 0xFFFF;
for (size_t i=0; i < len; i++) {
crc ^= data[i];
for (int j=0; j < 8; j++) {
if (crc & 1) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
// Function to read modbus registers
bool read_regs( byte dev_addr, byte func_code,
uint16_t start_reg_addr, size_t num_regs,
byte *result, uint32_t delay_ms=1 )
{
byte reg_addr_hi = (start_reg_addr >> 8) & 0xFF;
byte reg_addr_lo = start_reg_addr & 0xFF;
byte num_regs_hi = (num_regs >> 8) & 0xFF;
byte num_regs_lo = num_regs & 0xFF;
byte req_frame[8] = { dev_addr, func_code,
reg_addr_hi, reg_addr_lo,
num_regs_hi, num_regs_lo };
size_t req_frame_len = sizeof(req_frame);
uint16_t crc = calc_modbus_crc(req_frame, req_frame_len-2 );
req_frame[req_frame_len-2] = crc & 0xff;
req_frame[req_frame_len-1] = (crc >> 8) & 0xff;
RS485.write( req_frame, req_frame_len );
delay( delay_ms );
size_t buf_len = 5 +(2*num_regs);
byte resp_frame[ buf_len+1 ] = {0};
size_t resp_frame_len = 0;
#if 1
resp_frame_len = RS485.readBytes( resp_frame, buf_len );
#else
uint32_t retries = 100;
while ( resp_frame_len < buf_len && --retries > 0 ) {
if ( RS485.available() ) {
resp_frame[resp_frame_len++] = RS485.read();
}
delay(1);
}
#endif
if ( resp_frame_len < buf_len ) {
return false; // error
}
uint16_t crc16, expected_crc16;
byte *crc_bytes = &resp_frame[resp_frame_len-2];
expected_crc16 = (crc_bytes[1] << 8) | crc_bytes[0];
crc16 = calc_modbus_crc(resp_frame, resp_frame_len-2);
if (crc16 == expected_crc16) {
memcpy( result, resp_frame, resp_frame_len );
return true; // ok
} else {
Serial.print("CRC error: ");
Serial.print(crc16, HEX);
Serial.print(" : ");
Serial.println(expected_crc16, HEX);
return false; // error
}
}
bool read_float(
uint8_t dev_addr, uint8_t func_code,
uint16_t reg_start_addr, float *value )
{
byte result[16] = {0}; // frame buffer for response
if (read_regs(dev_addr, func_code, reg_start_addr, 2, result)){
uint32_t _value = (result[3]<< 24) | (result[4] << 16)
| (result[5]<< 8) | result[6];
*value = *((float *)&_value);
return true; // success
}
*value = 0.0f;
return false; // error
}
typedef struct {
uint16_t reg_addr;
char name[20];
char unit[4];
} param_t;
param_t params[]= {
{ 0x0000, "Voltage", "V" },
{ 0x0006, "Current", "A" },
{ 0x000C, "Active Power", "W" },
{ 0x0012, "Apparent Power", "VA" },
{ 0x0018, "Reactive Power", "VAr" },
{ 0x001E, "Power Factor", "-" },
{ 0x0046, "Frequency", "Hz" },
{ 0x0156, "Total Active Energy", "kWh" },
};
void loop() {
uint8_t dev_addr = 0;
float value;
int N = sizeof(params)/sizeof(param_t);
int index = 0;
uint8_t func_code = 0x04;
int attempts = 1;
while ( index < N ) {
param_t *p = ¶ms[index];
if (read_float(dev_addr, func_code, p->reg_addr, &value)) {
Serial.printf( "0x%04X: %20s, %7.3f [%s]\n",
p->reg_addr, p->name, value, p->unit );
index++;
attempts = 1;
} else {
attempts++;
}
delay(10);
}
Serial.println("============================================");
Serial.flush();
delay(2000);
}
//////////////////////////////////////////////////////////////
รูป: ตัวอย่างข้อความเอาต์พุตจากการรันโค้ดตัวอย่าง Arduino Sketch สำหรับบอร์ด ESP32-C3
รูป: ตัวอย่างอุปกรณ์ที่ได้นำมาทดลอง (ใช้บอร์ดไมโครคอนโทรลเลอร์ ESP32-C3 SuperMini)
▷ กล่าวสรุป#
บทความนี้ได้นำเสนอการทดลองใช้งานเพาเวอร์มิเตอร์เฟสเดียว รุ่น SDM120 (Brand: Eastron) และตัวอย่างโค้ด Python และ Arduino-ESP32C3 เพื่อสาธิตการอ่านค่าจากมิเตอร์ โดยเชื่อมต่อผ่านบัส RS485 และใช้โพรโทคอล Modbus RTU เพื่อส่งเฟรมข้อมูลสำหรับคำสั่งและข้อมูลตอบกลับ
บทความที่เกี่ยวข้อง
- การใช้งานโมดูลสื่อสาร RS485 Transceiver
- การใช้งานโมดูล XY-MD02 Temperature & Humidity Sensor (RS485 Modbus RTU)
- การอ่านค่าจากเพาเวอร์มิเตอร์ไฟฟ้าสามเฟส: CJ-3D3YS (ZGCJ)
- การอ่านค่าจากเพาเวอร์มิเตอร์ไฟฟ้าสามเฟส: ZM194-D9Y (ZJZM)
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Created: 2024-01-27 | Last Updated: 2024-01-29