การออกแบบวงจรดิจิทัลสำหรับ FPGA เพื่อใช้งานโมดูล AC Dimmer#

Keywords: Digital Logic Design, VHDL, Intel / Altera FPGA, Quartus Prime, AC Dimmer, Opto-Triac, Light Bulb Dimming

ความรู้และทักษะพื้นฐานที่เกี่ยวข้อง

  • อิเล็กทรอนิกส์กำลัง (Power Electronics): การใช้งาน Optocoupler, Diode, Triac และวงจรไฟฟ้ากระแสสลับ
  • การออกแบบวงจรลอจิก (Logic Design): การทำงานของ Timer/Counter การใช้งาน Rotary Encoder และการใช้งาน Intel MAX 10 FPGA
  • การประมวลผลสัญญาณดิจิทัล: การตรวจจับขอบสัญญาณ (Edge Detection) การสร้างพัลส์ (Pulse Generation)
  • การวัด (Measurement): การใช้ออสซิลโลสโคป (Oscilloscope) สำหรับวัดพารามิเตอร์ของสัญญาณ
  • การเขียนโค้ดและการใช้ซอฟต์แวร์ (Software/Coding): การใช้ Python/NumPy การเขียนโค้ดด้วย VHDL, และการใช้งานซอฟต์แวร์ Intel Quartus Prime (Lite Edition)

ไอซี Triac สำหรับโมดูล AC Dimmer#

โดยทั่วไปแล้ว โมดูลหรี่ไฟสำหรับโหลดไฟฟ้ากระแสสลับ หรือ AC Dimmer เช่น สำหรับการนำไปใช้กับหลอดไฟแบบไส้ (Incandescent light bulb) เพื่อปรับความสว่าง เป็นต้น มักจะใช้ไอซีประเภทที่เรียกว่า "ไตรแอก" (Triac: Triode for Alternating Current) ซึ่งเป็นอุปกรณ์สารกึ่งตัวนำ และสามารถทำหน้าที่เป็นสวิตซ์เปิดหรือปิดการจ่ายกำลังไฟฟ้าให้โหลดได้ มีฟังก์ชันการทำงานคล้ายกับอุปกรณ์สารกึ่งตัวนำที่เรียกว่า SCR (Silicon Controlled Rectifier) แต่ไตรแอกทำงานได้กับไฟฟ้ากระแสสลับ (กระแสไหลได้ทั้งสองทิศทาง) ไตรแอกมักนิยมใช้งานคู่กับไอซีประเภทที่เรียกว่า "ออปโตคัปเปลอร์" (Opto-coupler) ซึ่งทำหน้าที่แยกสัญญาณด้วยแสง เช่น 4N25

ไอซี "ออปโต-ไตรแอก" (Opto-Triac หรือ Optocoupler - Triac Driver Output) เช่น เบอร์ MOC3020 และ MOC3041 ก็เป็นอีกประเภทหนึ่งที่ได้รวบวงจรทั้งสองชนิดไว้ด้วยกัน แต่ภาคเอาต์พุตของไอซีสามารถใช้กับกระแสไฟฟ้าค่อนข้างจำกัด (เช่น ไม่เกิน 1A) ถ้าจะใช้กับโหลดไฟฟ้าที่มีกำลังไฟฟ้าค่อนข้างสูง ก็จะใช้กับไตรแอกภายนอกที่ทนกระแสไฟฟ้าได้มากขึ้น (5A หรือ 10A) เช่น ไอซี BT138-600E หรือ BTB16-600BW เป็นต้น

ไอซี MOC3041M หรือ MOC3163M เป็น "ออปโต-ไตรแอก" ที่มีวงจรอยู่ภายในเพื่อตรวจสอบการเปลี่ยนทิศทางของแรงดันไฟฟ้ากระแสสลับ หรือ เรียกว่า Zero-Crossing Detection

รูป: Optocoupler - Triac Driver Output with Zero-Crossing Detector

อุปกรณ์ที่ได้เลือกมาทดลองใช้งานคือ 1-Channel AC Dimmer Module ของบริษัท RobotDyn จากประเทศจีน และมีขาสำหรับการเชื่อมต่อดังนี้

  • VCC แรงดันไฟเลี้ยง 3.3V หรือ 5V
  • GND กราวนด์ของวงจร GND
  • ZC (Zero-Crossing) เป็นสัญญาณดิจิทัล-เอาต์พุต มีลักษณะเป็นสัญญาณพัลส์
  • PSM / DIM เป็นสัญญาณดิจิทัล-อินพุต มีลักษณะเป็นพัลส์กระตุ้นเพื่อให้ไตรแอกทำงานและจ่ายกระแสให้โหลดไฟฟ้าได้

รูป: โมดูล RobotDyn 1-Channel AC Dimmer Module

จากรูปจะเห็นได้ว่า มีการใช้ไอซี MOC3021 Opto-Triac Driver ไอซี 4N25 Optocoupler ไอซี Full-wave Bridge Rectifier และไอซี Triac

การต่อใช้งานโมดูลสำหรับไฟฟ้า AC ในภาคอินพุต มีดังนี้

  • การป้อนไฟฟ้า AC เป็นอินพุต: ให้ต่อสายไฟ L และ N จากปลั๊กไฟ เข้าที่ตำแหน่ง IN และ N ของ Terminal Block
  • การป้อนไฟฟ้า AC ให้กับโหลด: ให้ต่อสายไฟ L และ N จากตำแหน่ง OUT และ N ของ Terminal Block ไปยังหลอดไฟ

รูป: ตัวอย่างผังวงจร

การเปิดหรือปิดการจ่ายกำลังไฟฟ้าให้โหลดไฟฟ้ากระแสสลับ โดยใช้วงจรไตรแอก โดยปรกติแล้ว จะเกิดขึ้นในขณะที่เกิดเหตุการณ์ที่เรียกว่า Zero-Crossing ซึ่งจะเกิดขึ้นทุก ๆ 10 มิลลิวินาที สำหรับระบบไฟฟ้า AC ที่มีความถี่ 50Hz แต่ถ้าต้องการปรับการจ่ายกำลังไฟฟ้าให้น้อยลง ก็ให้หน่วงเวลาไว้ก่อนกระตุ้นให้ไตรแอกทำงาน ยิ่งหน่วงเวลามากขึ้น ก็จะทำให้โหลดไฟฟ้าได้กำลังไฟฟ้าน้อยลงต่อหนึ่งรอบไซเคิล

โมดูล AC Dimmer ใช้ 4N25 Optocoupler ทำหน้าที่ตรวจสอบว่า แรงดันไฟฟ้า AC Input ซึ่งถูกเรียงกระแสให้ไหลในทิศทางเดียวแล้ว มีระดับแรงดันใกล้เคียง 0V หรือไม่ ช่วงเวลาสั้น ๆ ดังกล่าว จะให้สัญญาณเอาต์พุตเป็นพัลส์ HIGH และใช้เป็นสัญญาณเอาต์พุต ZC (Zero-Crossing)

รูปต่อไปนี้เป็นตัวอย่างคลื่นสัญญาณ AC Input 220Vrms / 50Hz และคลื่นสัญญาณที่ถูกควบคุมด้วยวงจร AC Dimmer ซึ่งจะเห็นได้ว่า สัญญาณเอาต์พุตจะไม่เป็นรูปไซน์ เนื่องจากบางช่วงเวลาของหนึ่งไซเคิล จะมีแรงดันไฟฟ้าเป็น 0V ช่วงที่มีแรงดันไฟฟ้าเท่ากับหรือใกล้เคียง 0V นี้ เป็นช่วงที่โหลดไฟฟ้าถูกปิดการจ่ายกำลังไฟฟ้า

รูป: การควบคุมการจ่ายไฟให้โหลดไฟฟ้าด้วย AC Dimmer (Leading-Edge Triac Dimming)

โค้ด Python ต่อไปนี้ ใช้สำหรับการวาดรูปกราฟคลื่นสัญญาณเป็นตัวอย่าง และช่วยให้เข้าใจหลักการทำงานของวงจร AC Dimmer

import numpy as np
import matplotlib.pyplot as plt

# Constants
f = 50      # Frequency in Hz
Vrms = 220  # RMS Voltage in Volts
Vpeak = Vrms * np.sqrt(2)  # Peak Voltage
T = 1 / f   # Period of the sine wave

sample_rate = 1e5  # Sampling rate
# time steps for signal sampling between 0 to T (one period)
ts = np.linspace(0, T, int(sample_rate * T), endpoint=False)
# Generate samples for the sine wave for one period
sine_wave = Vpeak * np.sin(2 * np.pi * f * ts)

# Sine wave with first n% set to 0V
n = len(ts)
phase_start = 15 # phase in percentage
[t0,t1,t2] = (n * np.array([phase_start,50,50+phase_start])/ 100).astype(int)

sine_wave_modified = sine_wave.copy()
sine_wave_modified[0:t0]  = 0
sine_wave_modified[t1:t2] = 0

# Plotting
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6))

# First figure: Full sine wave
ax1.plot(ts * 1000, sine_wave, label='50Hz Sine Wave Input')
ax1.set_title('50Hz Sine Wave (220V RMS) - Full Period')
ax1.set_xlabel('Time (ms)')
ax1.set_ylabel('Voltage (V)')
ax1.grid(True)
ax1.legend()

# Second figure: Sine wave with first n% set to 0V
ax2.plot(ts * 1000, sine_wave_modified, 
                   label=f'Sine Wave Output', color='r')
ax2.set_title( 'Forward-phase Control Dimmer')
ax2.set_xlabel('Time (ms)')
ax2.set_ylabel('Voltage (V)')
ax2.grid(True)
ax2.legend()

plt.tight_layout()
plt.show()

 


การสร้างวงจรดิจิทัลควบคุมการทำงานของโมดูล AC Dimmer#

โดยปรกติแล้ว ในการควบคุมการทำงานของโมดูล AC Dimmer ก็นิยมใช้บอร์ดไมโครคอนโทรลเลอร์ เขียนโปรแกรมด้วยภาษา C/C++ เป็นต้น แต่ในบทความนี้ ลองมาดูตัวอย่างการเขียนโค้ด VHDL เพื่อนำไปสร้างเป็นวงจรดิจิทัลสำหรับ FPGA และนำไปทดสอบกับบอร์ด Terasic DE10-Lite FPGA

ในการออกแบบวงจร ได้เลือกใช้โมดูล Rotary Encoder Switch ซึ่งจะให้สัญญาณดิจิทัล SW_A กับ SW_B เป็นสัญญาณพัลส์ (บางโมดูลอาจใช้ชื่อสัญญาณเป็น S1 และ S2 หรือ CLK และ DT เป็นต้น) ถ้าไม่มีการหมุนหรือเปลี่ยนตำแหน่งเชิงมุม สัญญาณทั้งสอง จะมีค่าลอจิกเป็น HIGH หากหมุนในทิศทางทวนหรือตามเข็มนาฬิกา จะทำให้มีการเปลี่ยนค่าลอจิกเกิดขึ้นทั้งสองสัญญาณ (Logic Level Transition) แต่เกิดขึ้นไม่พร้อมกัน

รูป: ตัวอย่างโมดูล Rotary Encoder Switch

รูป: ตัวอย่างรูปคลื่นสัญญาณจากโมดูล Rotary Encoder Switch เมื่อมีการหมุนในทิศทางที่แตกต่างกัน

ในตัวอย่างนี้ การหมุนปุ่มดังกล่าว จะใช้สำหรับการปรับลดหรือเพิ่มการหน่วงเวลาของสัญญาณกระตุ้น PSM / DIM ให้ไอซีไตรแอก หลังจากเกิดสัญญาณพัลส์ ZC ในแต่ละรอบ (เกิดขึ้นทุก ๆ 10 มิลลิวินาที หรือ 100Hz)

วงจรดิจิทัลใช้สัญญาณ CLK ความถี่ 50MHz ของวงจรบนบอร์ด FPGA สำหรับกำหนดจังหวะการทำงานของวงจรดิจิทัล และมีสัญญาณอินพุต nRST สำหรับรีเซตการทำงานของวงจร (Active-Low Asynchronous Reset)

วงจรจะทำหน้าที่คอยตรวจสอบการเปลี่ยนแปลงของสัญญาณ SW_A กับ SW_B และดูว่า มีการหมุนไปในทิศทางใด เพื่อนำมาเพิ่มหรือลดค่าของตัวนับ set_delay_cnt ซึ่งจะถูกนำไปใช้ในการหน่วงเวลาสำหรับสัญญาณพัลส์ PSM / DIM การตรวจสอบสัญญาณอินพุต และอัปเดตค่าตัวนับ จะเกิดขึ้นด้วยอัตราคงที่ (เช่น 500Hz)

 

File: de10_lite_ac_dimmer.vhd

----------------------------------------------------------------------------
-- Date: 2024-09-10
-- Target Board: Terasic DE10 Lite FPGA Board
-- Purpose: Demonstrate AC dimming for a light bulb
----------------------------------------------------------------------------

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
USE IEEE.math_real.ALL;

ENTITY de10_lite_ac_dimmer IS
  GENERIC (
    CLK_HZ : NATURAL := 50000000
  );
  PORT (
    CLK  : IN STD_LOGIC; -- system clock input (50MHz)
    nRST : IN STD_LOGIC; -- active-low asynchronous reset input
    SW_A : IN STD_LOGIC; -- digital input for rotary encoder switch A
    SW_B : IN STD_LOGIC; -- digital input for rotary encoder switch B
    ZC   : IN STD_LOGIC; -- digital input for zero crossing pulse
    PSM  : OUT STD_LOGIC -- digital output for triac trigger pulse
  );
END de10_lite_ac_dimmer;

ARCHITECTURE behave OF de10_lite_ac_dimmer IS

  TYPE state_type IS (ST_IDLE, ST_DELAY, ST_PULSE_START, ST_PULSE_HIGH);
  SIGNAL state : state_type := ST_IDLE;

  SIGNAL pulse_out      : STD_LOGIC;
  SIGNAL pulse_in       : STD_LOGIC;
  SIGNAL pulse_in_prev  : STD_LOGIC;
  SIGNAL pulse_detected : STD_LOGIC := '0';

  CONSTANT UPDATE_CNT_MAX : INTEGER := (CLK_HZ/500) - 1;
  SIGNAL sw_capture       : STD_LOGIC_VECTOR(3 DOWNTO 0) := (OTHERS => '1');
  SIGNAL update_enable    : STD_LOGIC := '0';
  SIGNAL change_detected  : STD_LOGIC := '0';
  SIGNAL delay_cnt_inc    : STD_LOGIC := '0';
  SIGNAL delay_cnt_dec    : STD_LOGIC := '0';

  CONSTANT DELAY_CNT_MAX  : INTEGER := (CLK_HZ/100) * 90 / 100 - 1;
  CONSTANT BW : INTEGER := INTEGER(ceil(log2(real(DELAY_CNT_MAX))));
  SIGNAL set_delay_cnt : INTEGER RANGE 0 TO (2 ** BW - 1) := 0;
  SIGNAL delay_cnt     : unsigned(19 DOWNTO 0) := (OTHERS => '0');

  CONSTANT PULSE_WIDTH_CNT_MAX : unsigned(15 DOWNTO 0) 
                               := to_unsigned(20000, 16);
  SIGNAL pulse_width_cnt : unsigned(15 DOWNTO 0) := (OTHERS => '0');

BEGIN
  -- This process implements switch debouncing logic.
  P1 : PROCESS (nRST, CLK)
    VARIABLE update_cnt : INTEGER RANGE 0 TO UPDATE_CNT_MAX := 0;
  BEGIN
    IF nRST = '0' THEN
      update_cnt := 0;
      sw_capture <= (OTHERS => '1');
      update_enable <= '0';
    ELSIF rising_edge(CLK) THEN
      IF update_cnt = UPDATE_CNT_MAX THEN
        update_cnt := 0;
        update_enable <= '1';
        sw_capture <= sw_capture(1 DOWNTO 0) & (SW_A & SW_B);
      ELSE
        update_cnt := update_cnt + 1;
        update_enable <= '0';
      END IF;

    END IF;
  END PROCESS;

  -- Detect the falling edge on the captured SW_A signal.
  change_detected <= sw_capture(3) AND (NOT sw_capture(1));
  delay_cnt_inc <= change_detected AND (NOT sw_capture(0)); -- Increment
  delay_cnt_dec <= change_detected AND sw_capture(0);       -- Decrement

  P2 : PROCESS (nRST, CLK)
  BEGIN
    IF nRST = '0' THEN
      set_delay_cnt <= 20000;
    ELSIF rising_edge(CLK) THEN
      IF update_enable = '1' THEN
        IF delay_cnt_inc = '1' THEN
          IF set_delay_cnt <= DELAY_CNT_MAX THEN
            set_delay_cnt <= set_delay_cnt + 2000;
          END IF;
        ELSIF delay_cnt_dec = '1' THEN
          IF set_delay_cnt > 20000 THEN
            set_delay_cnt <= set_delay_cnt - 2000;
          END IF;
        END IF;
      ELSIF set_delay_cnt < 20000 THEN
        set_delay_cnt <= 20000;
      END IF;
    END IF;
  END PROCESS;

  P3 : PROCESS (CLK, nRST)
  BEGIN
    IF nRST = '0' THEN
      state <= ST_IDLE;
      pulse_in_prev <= '0';
      pulse_out <= '0';
      delay_cnt <= (OTHERS => '0');
      pulse_width_cnt <= (OTHERS => '0');

    ELSIF rising_edge(CLK) THEN
      pulse_in_prev <= pulse_in;
      pulse_in <= ZC; -- Capture the zero-crossing (ZC) pulse

      CASE state IS
        WHEN ST_IDLE =>
          pulse_out <= '0';
          delay_cnt <= (OTHERS => '0');
          pulse_width_cnt <= (OTHERS => '0');
          -- Detect the rising edge of the ZC pulse
          IF pulse_in = '1' AND pulse_in_prev = '0' THEN
            state <= ST_DELAY;
          END IF;

        WHEN ST_DELAY =>
          IF delay_cnt < to_unsigned(set_delay_cnt, BW) THEN
            delay_cnt <= delay_cnt + 1;
          ELSE
            state <= ST_PULSE_START;
          END IF;

        WHEN ST_PULSE_START =>
          pulse_out <= '1';
          state <= ST_PULSE_HIGH;

        WHEN ST_PULSE_HIGH =>
          IF pulse_width_cnt < PULSE_WIDTH_CNT_MAX THEN
            pulse_width_cnt <= pulse_width_cnt + 1;
          ELSE
            pulse_out <= '0';
            state <= ST_IDLE;
          END IF;

        WHEN OTHERS =>
          state <= ST_IDLE;

      END CASE;
    END IF;
  END PROCESS;

  PSM <= pulse_out;

END behave;

ตัวอย่างไฟล์ Tcl Script สำหรับเลือกใช้ขาชิป 10M50DAF484C7G FPGA สำหรับสัญญาณ I/O มีดังนี้

# Pin & Location Assignments
# ==========================

set_location_assignment PIN_P11 -to CLK
set_location_assignment PIN_B8  -to nRST
# GPIO18
set_location_assignment PIN_AB11 -to PSM 
# GPIO20
set_location_assignment PIN_AB10 -to ZC
# GPIO22
set_location_assignment PIN_AA9 -to SW_A
# GPIO24
set_location_assignment PIN_AA8 -to SW_B

set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to CLK
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to nRST
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ZC
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to PSM
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW_A
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW_B

รูป: การใช้ซอฟต์แวร์ Intel Quartus Prime Lite Edition v22.1 (Ubuntu) ในการแปลงโค้ด VHDL ให้เป็นไฟล์ Bitstream เพื่อนำไปทดลองใช้กับบอร์ด FPGA

 


การทดลองกับอุปกรณ์ฮาร์ดแวร์#

เมื่อได้ออกแบบวงจรดิจิทัลได้สำเร็จแล้ว ถัดไปเป็นการทดสอบการทำงานกับอุปกรณ์จริง

คำเตือน: การทดลองที่มีการใช้ไฟฟ้า AC จะต้องทำด้วยความระมัดระวัง เพื่อมิให้เกิดอันตรายต่อชีวิต หรือความเสียหายต่อวงจร หากต่อวงจรไม่ถูกต้อง

คำแนะนำ: ก่อนทดลองใช้บอร์ด FPGA เชื่อมต่อกับโมดูล AC Dimmer ในเบื้องต้นยังไม่ต้องใช้โมดูลหรี่ไฟ และให้ใช้ Function Generator มาสร้างสัญญาณพัลส์ให้กับบอร์ด FPGA โดยสร้างสัญญาณ ZC ซึ่งเป็นสัญญาณรายคาบ ตั้งค่าความถี่ 100 Hz แรงดันไฟฟ้าอยู่ระหว่าง 0V ถึง 3.3V ตั้งค่า Duty Cycle สำหรับสัญญาณพัลส์ (Pulse) เช่น ไม่เกิน 5% เพื่อดูการทำงานของวงจรดิจิทัล และใช้ออสซิลโลสโคปวัดสัญญาณ ZC และสัญญาณพัลส์ PSM / DIM ที่เป็นเอาต์พุตจากบอร์ด FPGA

รูป: ตำแหน่งของขา I/O ของบอร์ด FPGA และไฟเลี้ยง 3.3V & GND สำหรับโมดูล AC Dimmer

รูป: การเชื่อมต่อสายไฟ AC สำหรับจ่ายไฟ และโหลดไฟฟ้า (หลอดไฟ)

รูป: การปรับความสว่างสูงสุด

รูป: การปรับความสว่างลดลง

รูป: สัญญาณZC (CH1) และ PSM (CH2) เมื่อมีการหน่วงเวลาน้อยมาก หลังจากเกิดสัญญาณพัลส์ ZC แล้วตามด้วยการเกิดพัลส์ PSM ในกรณีนี้จะทำให้หลอดไฟสว่างสูงสุด

รูป: สัญญาณพัลส์ ZC และ PSM เมื่อมีการหน่วงเวลาปานกลาง ซึ่งจะทำให้หลอดไฟสว่างลดลง

รูป: สัญญาณพัลส์ ZC และ PSM เมื่อมีการหน่วงเวลามากสุด ซึ่งจะทำให้หลอดไฟไม่สว่าง

จากรูปสัญญาณตัวอย่าง จะเห็นได้ว่า มีการหน่วงเวลานับจากการเกิดสัญญาณพัลส์ ZC แล้วตามด้วยพัลส์ PSM ในแต่ละไซเคิล แต่การหน่วงเวลาจะต้องน้อยกว่า 10 มิลลิวินาที

 


กล่าวสรุป#

บทความนี้ได้นำเสนอ ตัวอย่างการใช้งานโมดูล AC Dimmer และนำมาใช้เป็นโจทย์ฝึกการออกแบบวงจรดิจิทัลด้วยภาษา VHDL เพื่อนำไปใช้กับบอร์ด FPGA โดยเลือกใช้บอร์ด Terasic DE10-Lite FPGA (Intel MAX 10 FPGA) และสาธิตการทดลองใช้งานกับหลอดไฟแบบไส้เพื่อปรับความสว่างของหลอดไฟได้

บทความที่เกี่ยวข้อง

 


This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

Created: 2024-10-10 | Last Updated: 2024-10-12