การสร้างสัญญาณ PWM ช่องสัญญาณ สำหรับ RGB LED
วัตถุประสงค์
1.ศึกษาการทำงานของบอร์ด
FPGA
2.สามารถออกแบบการทำงานของวงจรดิจิทัลได้
3.เข้าใจและสามารถอธิบายการทำงานของวงจรได้
อุปกรณ์
1.บอร์ด FPGA
CYCLOne 3 ชิปหมายเลข EP3C10E144C8 1 บอร์ด
2. ออสซิโลสโคป 1 เครื่อง
3. สายไฟ
4. คอมพิวเตอร์ที่มีโปรแกรม
QuartUS
ข้อกำหนดในการทดลอง
จงออกแบบวงจรดิจิทัล
โดยใช้ภาษา VHDL สำหรับนำไปสร้างเป็นวงจรในชิป FPGA โดยใช้บอร์ดที่มีอยู่ในห้องแล็ป
1) วงจรดิจิทัลมี I/O ดังนี้
-
CLK (input) มีความถี่ 50MHz ใช้สำหรับกำหนดจังหวะการทำงานของวงจรทั้งหมด
(เป็นการออกแบบวงจรดิจิทัลแบบ Synchronous Design)
-
RST_B (input) เป็นอินพุตสำหรับใช้รีเซตแบบ Asynchronous สำหรับการทำงานของวงจรโดยรวม (ทำงานแบบ Active-Low) ซึ่งได้จากวงจรปุ่มกด
(Push Button)
- PB[2:0] (input) เป็นอินพุตจากปุ่มกด
3 ปุ่ม ทำงานแบบ Active-low เพื่อใช้ในการเปลี่ยนค่า
Duty Cycle โดยเพิ่มทีละ 10 ในช่วง 0
ถึง 100 สำหรับสัญญาณ PWM(2:0) ที่มี 3 ช่องสัญญาณ
- PWM[2:0] (output) เป็นเอาต์พุตสำหรับนำไปควบคุมการทำงานของ
RGB LED จำนวน
1 ดวง
2) พฤติกรรมการทำงานเป็นดังนี้
-
เมื่อเริ่มต้นหรือกดปุ่มรีเซต RST_B ค่า PWM
[2:0] จะเป็นลอจิก 0 ทั้ง 3 ช่องสัญญาณ และมีค่า Duty Cycle สำหรับสัญญาณ PWM[i],
i=0,1,2 เป็น 0
-
เมื่อกดปุ่มใดๆ PB[i], i=0,1,2, แล้วปล่อยในแต่ละครั้ง
จะเพิ่มค่า Duty Cycle ของสัญญาณ PWM สำหรับช่องสัญญาณ
i ทีละ 10 แต่ถ้าถึง 100 จะกลับไปเริ่มต้นที 0 ใหม่
-
สัญญาณ PWM แต่ละช่อง
ต้องมีความถี่เท่ากันและคงที่ และสามารถเลือกใช้ความถี่ได้ในช่วง 500Hz ถึง 1kHz
3) แนวทางการออกแบบและทดสอบ
-
ออกแบบวงจรโดยใช้ภาษา VHDL
-
เขียน VHDL Testbench เพื่อทดสอบการทำงาน
และจำลองการทำงาน
-
ทดสอบการทำงานในบอร์ด FPGA แล้ววัดสัญญาณโดยใช้ออสซิลโลสโคป
(ไม่ต้องต่อวงจร RGB LED จริง)
-
บันทึกผลและเขียนรายงานการทดลอง
แนวทางการออกแบบ
สร้าง
delay ปุ่มกดประมาณครึ่งวินาที
แล้วจึงสั่งให้ทำงานโดยที่ clk ขอบขาขึ้นให้ ใช้ตัวนับ duty
เพิ่มขึ้นทีละ 10% duty เรื่อยๆ
เมื่อกดปุ่มแต่ละครั้ง
Code VHDL
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
entity test is
port(clk,RST_B:in
std_logic ;
PB
: in std_logic_vector(2 downto 0);
pwm:out
std_logic_vector(2 downto 0));
end test;
architecture behavioral of test is
type
duty_update_array is array (0 to 2 )of integer ;
type
count_botton_array is array (0 to 2) of integer ;
signal
count_freq : integer:=0;
signal
count_botton : count_botton_array :=(0,0,0);
signal
duty : duty_array := (0,0,0);
begin
begin
if(RST_B='0')then
--set to reset Asynchronus
duty
<= (0,0,0);
elsif
rising_edge(clk)then
for
i in 0 to 2 loop
if
(PB(i) = '0')then --botton delay
count_botton(i)
<= count_botton(i)+1;
elsif(PB(i)='1')and
count_botton(i)>100000 then
count_botton(i)
<=0;
if(duty(i)<=100000)then
--adding
10% of duty
else duty(i)
<= 0;
end
if;
duty_update(i)
<= duty(i); --update duty
end
loop;
if (count_freq < 100000) then
--count_freq less than 100% duty
count_freq
<= count_freq+1;
else
end
if;
end
if;
end process;
pwm(0) <= '1' when duty_update(0) > count_freq
else
'0';
pwm(1) <= '1' when duty_update(1) > count_freq
else
'0';
pwm(2) <= '1' when duty_update(2) > count_freq
else '0';
Testbench
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use work.all;
entity tb_lab1 is
end tb_lab1;
architecture testbench of tb_lab1 is
component
labb1
port(
clk:in
std_logic
RST_B
:in std_logic_vector(2 downto 0); --reset "000"
PB
: in std_logic_vector(2 downto 0);
pwm
: out std_logic_vector(2 downto 0)--output
);
end
component ;
signal
tb_clk : std_logic;
signal
tb_reset : std_logic_vector(2 downto 0)
:= ('0','0','0');
signal
tb_pb : std_logic_vector(2 downto 0);
signal
tb_pwm : std_logic_vector(2 downto 0);
signal
count : integer range 0 to 7 := 0;
begin
DUT
: labb1 port map(
clk=>tb_clk,RST_B=>tb_reset,PB=>tb_pb,pwm
=> tb_pwm
);
process
constant
period : TIME := 20 ns;
begin
tb_clk
<= '1';
wait
for (period/2);
tb_clk
<= '0';
wait
for (period/2);
end
process ;
process
begin
tb_reset
<= '0';
'1'
after period;
'0'
after (period*2);
end
process;
process
begin
tb_pb
<= std_logic_vector(count,3);
if
count < 7 then
count
<= count+1;
else
count
<= 0;
end
if;
wait
for 100000 s;
end
process;
end testbench;
ผลการทดสอบโปรแกรมจากโปรแกรม model-sim
ผลการทดลอง
ภาพการทดลองตอนวัดคลื่นสัญญาณ
รูปคลื่นจากออสซิโลสโคป
กด 1 ครั้ง duty
เพิ่มขึ้นทีละ 10 % เป็น 10%
กด 3 ครั้ง
duty เพิ่มขึ้นทีละ 10 % เป็น 30%
กด 8 ครั้ง
duty เพิ่มขึ้นทีละ 10 % เป็น 80%
- CLK (input) มีความถี่ 50MHz ใช้สำหรับกำหนดจังหวะการทำงานของวงจรทั้งหมด (เป็นการออกแบบวงจรดิจิทัลแบบ Synchronous Design)
- RST_B (input) เป็นอินพุตสำหรับใช้รีเซตแบบ Asynchronous สำหรับการทำงานของวงจรโดยรวม (ทำงานแบบ Active-Low) ซึ่งได้จากวงจรปุ่มกด (Push Button)
- PB[2:0] (input) เป็นอินพุตจากปุ่มกด 3 ปุ่ม ทำงานแบบ Active-low เพื่อใช้ในการเปลี่ยนค่า Duty Cycle โดยเพิ่มทีละ 10 ในช่วง 0 ถึง 100 สำหรับสัญญาณ PWM(2:0) ที่มี 3 ช่องสัญญาณ
- PWM[2:0] (output) เป็นเอาต์พุตสำหรับนำไปควบคุมการทำงานของ RGB LED จำนวน 1 ดวง
- เมื่อเริ่มต้นหรือกดปุ่มรีเซต RST_B ค่า PWM [2:0] จะเป็นลอจิก 0 ทั้ง 3 ช่องสัญญาณ และมีค่า Duty Cycle สำหรับสัญญาณ PWM[i], i=0,1,2 เป็น 0
- เมื่อกดปุ่มใดๆ PB[i], i=0,1,2, แล้วปล่อยในแต่ละครั้ง จะเพิ่มค่า Duty Cycle ของสัญญาณ PWM สำหรับช่องสัญญาณ i ทีละ 10 แต่ถ้าถึง 100 จะกลับไปเริ่มต้นที 0 ใหม่
- สัญญาณ PWM แต่ละช่อง ต้องมีความถี่เท่ากันและคงที่ และสามารถเลือกใช้ความถี่ได้ในช่วง 500Hz ถึง 1kHz
- ออกแบบวงจรโดยใช้ภาษา VHDL
- เขียน VHDL Testbench เพื่อทดสอบการทำงาน และจำลองการทำงาน
- ทดสอบการทำงานในบอร์ด FPGA แล้ววัดสัญญาณโดยใช้ออสซิลโลสโคป
(ไม่ต้องต่อวงจร RGB LED จริง)
- บันทึกผลและเขียนรายงานการทดลอง
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
entity test is
port(clk,RST_B:in
std_logic ;
PB
: in std_logic_vector(2 downto 0);
pwm:out
std_logic_vector(2 downto 0));
end test;
architecture behavioral of test is
type
duty_update_array is array (0 to 2 )of integer ;
type
count_botton_array is array (0 to 2) of integer ;
signal
count_freq : integer:=0;
signal
count_botton : count_botton_array :=(0,0,0);
signal
duty : duty_array := (0,0,0);
begin
begin
if(RST_B='0')then
--set to reset Asynchronus
duty
<= (0,0,0);
elsif
rising_edge(clk)then
for
i in 0 to 2 loop
if
(PB(i) = '0')then --botton delay
count_botton(i)
<= count_botton(i)+1;
elsif(PB(i)='1')and
count_botton(i)>100000 then
count_botton(i)
<=0;
if(duty(i)<=100000)then
--adding
10% of duty
else duty(i)
<= 0;
end
if;
duty_update(i)
<= duty(i); --update duty
end
loop;
if (count_freq < 100000) then
--count_freq less than 100% duty
count_freq
<= count_freq+1;
else
end
if;
end
if;
end process;
pwm(0) <= '1' when duty_update(0) > count_freq
else
'0';
pwm(1) <= '1' when duty_update(1) > count_freq
else
'0';
pwm(2) <= '1' when duty_update(2) > count_freq
else '0';
Testbench
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use work.all;
entity tb_lab1 is
end tb_lab1;
architecture testbench of tb_lab1 is
component
labb1
port(
clk:in
std_logic
RST_B
:in std_logic_vector(2 downto 0); --reset "000"
PB
: in std_logic_vector(2 downto 0);
pwm
: out std_logic_vector(2 downto 0)--output
);
end
component ;
signal
tb_clk : std_logic;
signal
tb_reset : std_logic_vector(2 downto 0)
:= ('0','0','0');
signal
tb_pb : std_logic_vector(2 downto 0);
signal
tb_pwm : std_logic_vector(2 downto 0);
signal
count : integer range 0 to 7 := 0;
begin
DUT
: labb1 port map(
clk=>tb_clk,RST_B=>tb_reset,PB=>tb_pb,pwm
=> tb_pwm
);
process
constant
period : TIME := 20 ns;
begin
tb_clk
<= '1';
wait
for (period/2);
tb_clk
<= '0';
wait
for (period/2);
end
process ;
process
begin
tb_reset
<= '0';
'1'
after period;
'0'
after (period*2);
end
process;
process
begin
tb_pb
<= std_logic_vector(count,3);
if
count < 7 then
count
<= count+1;
else
count
<= 0;
end
if;
wait
for 100000 s;
end
process;
end testbench;
ผลการทดสอบโปรแกรมจากโปรแกรม model-sim
ผลการทดลอง
ภาพการทดลองตอนวัดคลื่นสัญญาณ
รูปคลื่นจากออสซิโลสโคป
กด 1 ครั้ง duty
เพิ่มขึ้นทีละ 10 % เป็น 10%
กด 3 ครั้ง
duty เพิ่มขึ้นทีละ 10 % เป็น 30%
กด 8 ครั้ง
duty เพิ่มขึ้นทีละ 10 % เป็น 80%
ไม่มีความคิดเห็น:
แสดงความคิดเห็น