วันพฤหัสบดีที่ 20 พฤศจิกายน พ.ศ. 2557

การสร้างสัญญาณ PWM (เปลี่ยนค่า Duty Cycle เมื่อกดปุ่มแล้วปล่อย)

วัตถุประสงค์การทดลอง
1.สามารถใช้ภาษา VHDL ในการออกแบบการสร้างสัญญาณ PWM โดยเปลี่ยนค่าตามปุ่มกดได้
2.สามารถใช้งาน ออสซิลโลสโคป ในการวัดสัญญาณเอาต์พุต จากบอร์ด FPGA

รายการอุปกรณ์
1.บอร์ด FPGA  1 บอร์ด
2.โปรแกรม Quartus II

วิธีการทดลอง
1. ออกแบบวงจรดิจิทัลโดยใช้ภาษา VHDL สำหรับบอร์ด FPGA ที่ทำงานได้ตามข้อกำหนดต่อไป
    - มีอินพุต CLK ความถี่ 50MHz
    - มีอินพุต nRESET ทำงานแบบ active-low (ได้จากวงจรปุ่มกด) ไว้สำหรับรีเซตการทำงานของวงจร
    - มีอินพุตจากวงจรปุ่มกด PB ทำงานแบบ active-low
    - มีเอาต์พุต PWM
    - สร้างสัญญาณ PWM ออกที่ขา PWM ซึ่งมีความถี่ 500Hz คงที่ เริ่มต้นมีค่า Duty Cycle 0%
    - เมื่อกดปุ่ม PB แล้วปล่อยหนึ่งครั้ง จะทำให้ค่า Duty Cycle เพิ่มขึ้นทีละ 5%
           ถ้า Duty Cycle เท่ากับ 100% ต่อไปให้วนกลับไปเริ่มที่ 0%
2. ทดสอบและวัดสัญญาณเอาต์พุตด้วยออสซิลโลสโคป
3.เขียนรายงานการทดลอง


ผลการทดลอง

VHDL CODE
-- File: duty_pwm.vhd
-- Target Board: Cyclone III,EP3C10E144C8

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity duty_pwm is
  generic (
    PERIOD : integer := 100; -- count period for PWM
    STEP   : integer := 5    --increment step for duty cycle
  );
  port(--ใช้กำหนดขาหรือสัญญาณ
    CLK    : in  std_logic;
    nRESET : in  std_logic;
    PB     : in  std_logic; 
    Q      : out std_logic );
end duty_pwm;

--เป็นส่วนที่ใช้สำหรับบรรยายถึงฟังก์ชันการทำงานของ duty_pwm
architecture behave of duty_pwm is
  signal duty_cycle, new_duty_cycle :
         integer range 0 to (PERIOD+ STEP) := 0; --ประกาศตัวแปร ชนิด signal ขนาด PERIOD+ STEP เริ่มต้นที่ 0
  signal cnt : integer range 0 to (PERIOD-1) := 0; --ประกาศตัวแปร ชนิด signal ขนาด PERIOD-1 เริ่มต้นที่ 0

  signal ff : std_logic;
  signal D : std_logic;
 
begin
  process (CLK)
  Variable count : Integer range 0 to 50000 := 0; --ประกาศ Variable ชื่อ count ชนิด integer ขนาด0 ถึง 50000 เริ่มต้นที่ 0
  begin
    if nRESET = '0' then    --active low  ค่า reset เป็น 0
      new_duty_cycle <= 0--ให้ค่า duty cycle เป็น 0(reset ค่า)
    elsif rising_edge(CLK) then     --หากค่า reset เป็น 1 และเป็นสัญญาณขอบขาขึ้นของ clk
                   if count = 50000 then  –-ใช้เงื่อนไขถ้า count = 50000
                     if PB = '1' then        -- แล้วปุ่มกดมีสถานะเป็น 1
                       D <= PB;          -- นำค่า PB ไป assignment ให้ D
                     end if;           -- จบเงื่อนไข PB = 1
      elsif PB = '0' then        --หากค่า PB เป็น 0 ให้ นำค่า PB มาเทียบกับ D ถ้าต่างกัน 
                                  ff <= (PB xor D);  --นำค่า ไป assignment ให้ ff
                                  if ff = '1' then --ถ้า ff มีค่าเป็น 1 ก็ มาเช็คว่า
          if (new_duty_cycle+ STEP) > PERIOD then -–ค่า duty cycle มากกว่า period หรือไม่
             new_duty_cycle <= 0;--ถ้ามากกว่า ให้ ค่า duty เป็น 0
          else   --ถ้าไม่ใช่
             new_duty_cycle <= new_duty_cycle + STEP;   --increment duty cycle

          end if;                                         --จบเงื่อนไข กำหนด ค่า duty cycle
                                                 count := 0;     --ให้ count เป็น 0
        end if;              --จบเงื่อนไข ff = 1
                     D <= PB;                             --นำค่า PB ที่เท่ากับ 0ไปเก็บ ใน ตัวแปร D  
      end if;            
                                count :=count +1;  --กำหนดให้ค่า count เพิ่มทีละ 1;
    end if;                  --จบเงื่อนไข nRESET
  end process;               --จบ process

  process (CLK) begin
    if rising_edge(CLK) and nRESET = '1' then –-ทำงานที่ขอบขาขึ้นของ clk และ ค่า reset เป็น 1
       if cnt = (PERIOD-1) then  --ถ้า ค่า cnt เท่ากับ ค่าคาบลบ 1
         cnt <= 0;              --ให้ cnt เป็น 0(reset ค่า)
         duty_cycle <= new_duty_cycle; --update duty cycle
       else                                                                  --ถ้าไม่ใช่ ค่า cnt น้อยกว่า ค่าคาบลบ 1
         cnt <= cnt + 1;       --ให้ค่า cnt บวกทีละ 1
       end if;                 --จบเงื่อนไข cnt
    end if;                    --จบเงื่อนไขขอบขาขึ้น clk
  end process;                --จบ process
 
 Q <= '1' when (cnt < duty_cycle) else '0'; --ถ้าค่า cnt น้อยกว่า ค่า duty cycle ให้ เอาต์พุตเป็น 1 ถ้าไม่ใช่เป็น 0
 
end behave;

---------------------------------------------------------------------


-- File: tb_pwm_duty.vhd

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity tb_pwm_duty is
  -- no ports
end tb_pwm_duty;

architecture testbench of tb_pwm_duty is
  component duty_pwm is
    generic ( PERIOD : integer := 100; STEP : integer := 5 );
    port(
      CLK : in  std_logic;
      nRESET  : in  std_logic;
      PB  : in  std_logic;
      Q   : out std_logic );
    end component;

  constant PERIOD : integer := 20;
  constant STEP   : integer := 1;
  constant CLK_PERIOD : time := 20 ns;
  signal t_CLK, t_nReset, t_PB, t_Q : std_logic;
 
begin
  DUT: duty_pwm
    generic map( PERIOD => PERIOD, STEP => STEP )
    port map (CLK => t_CLK, nRESET => t_nReset, PB => t_PB, Q => t_Q );
 
  process begin -- a process for generating the clock signal (50MHz)
    t_CLK <= '1'; wait for 10 ns;
    t_CLK <= '0'; wait for 10 ns;
  end process;
 
  process begin -- a process for generating the nReset input signal
    t_nReset <= '1';
    wait until rising_edge(t_CLK);
    t_nReset <= '0';
    for i in 1 to 9 loop
       wait until rising_edge(t_CLK);
    end loop; 
  end process;

  process begin -- a process for generating the PB input signal
    t_PB <= '0'; wait for 100 ns;
    for i in 0 to 100 loop
       wait until rising_edge(t_CLK);
       t_PB <= '1';
       wait until rising_edge(t_CLK);
       t_PB <= '0';
       wait for (((i*3+7) mod 53) + 10*PERIOD)*CLK_PERIOD;
    end loop;
    wait; -- wait forever
  end process;
  end testbench;
-------------------------------------------------------------------


ผลการ จำลองการทำงานโดยใช้โปรแกรม  ModelSim-AlteraStarter Edition
ผลที่ได้คือ เมื่อ กดปล่อย ปุ่ม PB ครั้ง ค่า duty cycle จะเพิ่มขึ้นทีละ 5 % เมื่อค่า duty cycle เท่ากับ 100 %จะวนกลับไปเริ่มที่ 0
- กำหนด clk มีคาบเวลาเท่ากับ 20 ns  และ PB เปลี่ยนจาก 0 เป็น 1 มีคาบเวลา 2us 

วิดีโอผลการทดลอง :

ไม่มีความคิดเห็น:

แสดงความคิดเห็น