Thông báo

Collapse
No announcement yet.

Cần giúp đỡ về lập trình PWM bằng ngôn ngữ VHDL

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • Cần giúp đỡ về lập trình PWM bằng ngôn ngữ VHDL

    Chào các bác!
    Em đang làm đồ án về lập trình điều khiển PWM bằng ngôn ngữ VHDL, bác nào làm về cái này rồi thì giúp em với. Em đang rất cần
    Cám ơn các bác trước!

  • #2
    Bạn cứ làm bộ đếm, đếm từ 0 tới 99, nếu bộ đếm >X thì đầu ra = 0, <X thì đầu ra =1 ... vậy là có xung PWM rồi.

    Comment


    • #3
      Anh ơi cho em hỏi 1 vấn đề nữa là nếu như thế em có 1 xung clock chuẩn đầu vào, đưa vào bộ chia xung sau đó lấy ra xung clock tương ứng với các chu kỳ xung ra khác nhau.
      thì như thế em chỉ cần so sánh 1 cái thì khi thay đổi các biến đàu vào trong bộ chia xung thì sẽ có đựocc các chu ký PWM ra khác nhau phải không anh?
      Em đang làm đò án về diều chế PWM bằng VHDL để điều khiển biến tần anh ak`, anh giúp đựoc em thì tốt quá

      Comment


      • #4
        Nguyên văn bởi FPGA_9572XL Xem bài viết
        Anh ơi cho em hỏi 1 vấn đề nữa là nếu như thế em có 1 xung clock chuẩn đầu vào, đưa vào bộ chia xung sau đó lấy ra xung clock tương ứng với các chu kỳ xung ra khác nhau.
        thì như thế em chỉ cần so sánh 1 cái thì khi thay đổi các biến đàu vào trong bộ chia xung thì sẽ có đựocc các chu ký PWM ra khác nhau phải không anh?
        Em đang làm đò án về diều chế PWM bằng VHDL để điều khiển biến tần anh ak`, anh giúp đựoc em thì tốt quá
        Bạn nói rõ hơn đi, không hiểu lắm ... Trong PWM quan trọng là Duty cycle (Hoạt kỳ ), sao bạn lại muốn có nhiều chu kỳ (Period) ở cổng ra?

        Comment


        • #5
          ý em là mình có thể thay đổi được chu kỳ của PWM,có nghĩa là điều chỉnh được độ rộng xung đó anh. Nhưng em không bít dùng như thế có được không? hay là phải dùng bộ phát xung trong VHDL? là cái máy phát gì đó, em chưa tìm hiểu kĩ
          Còn đây là ý em định nói : anh xem có được không ạ?
          library IEEE;
          use IEEE.STD_LOGIC_1164.ALL;
          use IEEE.STD_LOGIC_ARITH.ALL;
          use IEEE.STD_LOGIC_UNSIGNED.ALL;
          //Khai báo thực thể
          entity chontocdo is
          port (
          ck:in std_logic ;
          tocdo : in std_logic_vector(2 downto 0);
          clk_C,clk_Q,clk_D : out std_logic
          );
          end chontocdo;
          // Thân kiến trúc
          architecture Behavioral of chontocdo is
          signal clk_m: std_logic;
          signal dem : std_logic_vector (20 downto 0);
          begin
          chiaxung: process(ck,tocdo,clk_m,dem)
          begin
          if (ck'event and ck = '1') then
          dem <= dem +1;
          end if;
          case tocdo is
          when "000" => clk_m <= dem(20);
          when "001" => clk_m <= dem(19);
          when "010" => clk_m <= dem(18);
          when "011" => clk_m <= dem(17);
          when "100" => clk_m <= dem(16);
          when "101" => clk_m <= dem(15);
          when "111" => clk_m <= dem(14);
          when others => clk_m <= dem (15);
          end case;
          clk_Q <= dem(16);
          clk_C <= clk_M;
          end process;
          xungquetrocess (clk_M)
          variable i : integer range 0 to 401;
          begin
          if (clk_m'event and clk_m = '1') then
          i:= i+1;
          if (i < 200) then
          Clk_D <='1';
          end if;
          if ((i> 200) and (i < 400)) then
          clk_d <= '0';
          end if;
          if ( i > 400) then
          i :=0;
          end if;
          end if;
          end process;
          end Behavioral;

          Comment


          • #6
            Nguyên văn bởi vantrinh1988 Xem bài viết
            ý em là mình có thể thay đổi được chu kỳ của PWM,có nghĩa là điều chỉnh được độ rộng xung đó anh. Nhưng em không bít dùng như thế có được không? hay là phải dùng bộ phát xung trong VHDL? là cái máy phát gì đó, em chưa tìm hiểu kĩ
            Còn đây là ý em định nói : anh xem có được không ạ?
            Nếu vậy, theo code của bạn
            clk_Q ko đổi = 1/(2^17) clkin
            clk_c thay đổi theo tocdo
            clk_d thay đổi theo tocdo luôn, và = 1/400 clk_C? (clk_c = 1khz thì clock_d chỉ có 2.5Hz)

            Comment


            • #7
              anh có thể giải thích giúp em chương trình tạo code PWM này không với ạ, em chưa hiểu vẻ nó mấy, nó dùng bộ phát Genarator
              entity Counter is

              Generic (
              C_COUNTER_WIDTH : integer := 5;
              C_UP_DOWN : boolean := true
              );

              Port (
              clk : in std_logic;
              ena : in std_logic;
              reset : in std_logic;
              count : out std_logic_vector(C_COUNTER_WIDTH-1 downto 0)
              --zero : out std_logic
              );

              end Counter;

              architecture Behavioral of Counter is
              constant UP_TC : std_logic_vector(C_COUNTER_WIDTH-1 downto 0 ) := (others => '1');
              signal Q : std_logic_vector(C_COUNTER_WIDTH-1 downto 0) := (others => '0');
              signal up : std_logic;
              begin

              up_down_counter : if C_UP_DOWN = true generate
              begin
              process(reset, clk)
              begin
              if (clk'event and clk = '1' ) then
              if ( reset = '1' ) then
              Q <= (others => '0' ) ;
              up <= '0' ;
              else
              if( ena = '1' ) then
              if ( up = '1' ) then
              if( Q = UP_TC ) then
              up <= '0' ;
              else
              Q <= Q + 1 ;
              end if;
              else
              if( Q = 0 ) then
              up <= '1' ;
              else
              Q <= Q - 1 ;
              end if;
              end if;
              end if;
              end if;
              end if;
              end process;
              end generate;

              up_counter : if C_UP_DOWN = false generate
              begin
              process(reset, clk)
              begin
              if (clk'event and clk = '1' ) then
              if ( reset = '1' ) then
              Q <= (others => '0' ) ;
              else
              if( ena = '1' ) then
              Q <= Q + 1;
              end if;
              end if;
              end if;
              end process;
              end generate;

              count <= Q;
              --zero <= '1' when (Q = 0) else '0';
              end Behavioral;
              entity Compare is

              Generic (
              C_WIDTH : integer := 2;
              C_ACTIVE_HIGH : boolean := TRUE;
              C_CENTERED : boolean := TRUE
              );

              Port (
              clk : in std_logic;
              reset : in std_logic;
              ena : in std_logic;
              deadband : in std_logic_vector(C_WIDTH-1 downto 0);
              cmp : in std_logic_vector(C_WIDTH-1 downto 0);
              --load : in std_logic;
              count : in std_logic_vector(C_WIDTH-1 downto 0);
              top : out std_logic;
              bottom : out std_logic
              --deadband_active : out std_logic
              );
              end Compare;

              architecture Behavioral of Compare is
              signal compare_value : std_logic_vector(C_WIDTH downto 0 ) := (others => '0');
              signal asserted : std_logic := '0';
              begin

              asserted <= '1' when (C_ACTIVE_HIGH = TRUE) else '0';

              non_centered_pwm : if C_CENTERED = FALSE generate
              begin
              process( clk )
              begin
              if( reset = '1' or ena = '0' ) then
              top <= not asserted;
              bottom <= not asserted;
              compare_value <= '0' & cmp;
              elsif (clk'event and clk ='1') then
              --if( load = '1' ) then
              compare_value <= '0' & cmp ;
              --end if;

              if( count < compare_value ) then
              top <= asserted after 1 ns;
              bottom <= not asserted ;
              else
              top <= not asserted ;
              bottom <= asserted ;
              end if;
              end if;
              end process;
              end generate;


              centered_pwm : if C_CENTERED = TRUE generate
              begin
              process(clk, reset, ena)
              variable top_cmp : integer;
              variable bot_cmp : integer;
              begin
              if( reset = '1' or ena = '0' ) then
              --deadband_active <= '0';
              top <= not asserted;
              bottom <= not asserted;
              compare_value <= '0' & cmp;
              elsif (clk'event and clk ='1') then
              --if( load = '1' ) then
              compare_value <= '0' & cmp ;
              --end if;

              top_cmp := conv_integer(compare_value) + (conv_integer(deadband)/2);
              bot_cmp := conv_integer(compare_value) - (conv_integer(deadband)/2);

              if( conv_integer(count) >= top_cmp ) then
              --deadband_active <= '0' after 1 ns;
              top <= asserted ;
              bottom <= not asserted ;
              elsif( conv_integer(count) < bot_cmp ) then
              --deadband_active <= '0' after 1 ns;
              bottom <= asserted ;
              top <= not asserted ;
              else
              --deadband_active <= '1' after 1 ns;
              bottom <= not asserted ;
              top <= not asserted ;
              end if;
              end if;
              end process;
              end generate;
              end Behavioral;
              entity PWM is
              Generic (
              C_COUNTER_WIDTH : integer := 2;
              C_ACTIVE_HIGH : boolean := TRUE;
              C_CENTERED : boolean := TRUE
              );
              Port(
              clk : in std_logic;
              ena : in std_logic;
              reset : in std_logic;
              deadband : in std_logic_vector(C_COUNTER_WIDTH-1 downto 0);
              duty : in std_logic_vector(C_COUNTER_WIDTH-1 downto 0);
              top : out std_logic;
              bottom : out std_logic
              --deadband_active : out std_logic
              );
              end PWM;

              architecture Behavioral of PWM is

              COMPONENT Counter
              Generic (
              C_COUNTER_WIDTH : integer := C_COUNTER_WIDTH;
              C_UP_DOWN : boolean := C_CENTERED
              );
              PORT(
              clk : IN std_logic;
              ena : IN std_logic;
              reset : IN std_logic;
              count : OUT std_logic_vector(C_COUNTER_WIDTH-1 downto 0)
              --zero : OUT std_logic
              );
              END COMPONENT;

              COMPONENT Compare
              Generic (
              C_WIDTH : integer := C_COUNTER_WIDTH;
              C_ACTIVE_HIGH : boolean := C_ACTIVE_HIGH;
              C_CENTERED : boolean := C_CENTERED
              );
              PORT(
              clk : IN std_logic;
              reset : IN std_logic;
              ena : IN std_logic;
              deadband : IN std_logic_vector(C_COUNTER_WIDTH-1 downto 0);
              cmp : IN std_logic_vector(C_COUNTER_WIDTH-1 downto 0);
              --load : IN std_logic;
              count : IN std_logic_vector(C_COUNTER_WIDTH-1 downto 0);
              top : OUT std_logic;
              bottom : OUT std_logic
              --deadband_active : OUT std_logic
              );
              END COMPONENT;

              signal count : std_logic_vector( C_COUNTER_WIDTH-1 downto 0) := (others => '0');
              --signal zero : std_logic := '0';
              begin

              Inst_counter: counter PORT MAP(
              clk => clk,
              ena => ena,
              reset => reset,
              count => count
              --zero => zero
              );

              Inst_compare: compare PORT MAP(
              clk => clk,
              reset => reset,
              ena => ena,
              deadband => deadband,
              cmp => duty,
              --load => zero,
              count => count,
              top => top,
              bottom => bottom
              --deadband_active => deadband_active
              );

              end Behavioral;
              được viết theo chương trình component

              Comment


              • #8
                Bạn phải hiểu rõ vấn đề cần giải quyết ... có rất nhiều cách để giải quyết vấn đề, không nhất thiết phải dùng máy phát xung gì cả.
                Về PWM : PULSE WIDTH MODULATION, tần số thường không thay đổi, chỉ có duty cycle là thay đồi theo input. Duty cycle ko phải chu kỳ:
                duty cycle là phần thời gian xung ở mức cao so với chu kì của xung. Nhiệm vụ của PWM là phải thay đổi duty cycle của output theo input.
                Ví dụ: clock 1MHz, chu kỳ bằng 1us, xung ở mức '1' 0.3us, thì duty cycle (tạm dịch là hoạt kỳ) = 30%.
                Khi tạo PWM, bạn cần tạo 2 thứ:
                - chu kì của xung
                - duty cycle của xung

                Để tạo chu kì của xung, bạn cần làm bộ chia clock. Giả sử clock chính của bạn lá 10MHz, bạn muốn tao xung 1MHz, bạn phải chia xuống 10. Bộ đếm của ban sẽ đếm:
                0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ....
                Nếu bạn muốn tạo duty cycle = 50% thì trong phân nửa thời gian, xung output của ban là 1.

                counter: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ....
                output : 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1

                nghĩa là : if(counter<=4) then output <= '1' else output <= '0';
                Nhưng vì nhiệm vụ của PWM là phải biến điệu (modulate) output theo input:
                cho nên: if(counter<= input) then output <= '1' else output <= '0';
                input = 1: duty cycle = 20%; input = 2: duty cycle = 30%....v.v

                Bạn cần hiểu rõ vấn đề kĩ trước khi đụng vào code.

                Comment


                • #9
                  Theo kinh nghiệm, đọc code của HDL mà chưa biết rõ người ta làm gì, rất khó hiể.
                  Hạn chế làm kiểu này trừ khi bất đắc dĩ.
                  Nếu copy code: copy nguyên si rồi dùng như hộp đen blackbox.

                  Comment


                  • #10
                    em đã viết 1 chương trình thế này
                    entity PWM1 is
                    port (
                    clk_in,reset,ena:in std_logic ;
                    PWM_out: out std_logic
                    );
                    end PWM1;

                    architecture Behavioral of PWM1 is
                    begin
                    process (clk_in)
                    variable i : integer range 0 to 11;
                    begin
                    if (reset='1' )then
                    PWM_out <= '0';
                    elsif ( ena = '0')then
                    PWM_out <= '0';
                    elsif(clk_in'event and clk_in = '1') then
                    i:= i+1;
                    if (i < 8) then
                    PWM_out <='1';
                    end if;
                    if ((i> 8) and (i < 10)) then
                    PWM_out <= '0';
                    end if;
                    if i > 10 then
                    i :=0;
                    end if;
                    end if;

                    end process;
                    end Behavioral;
                    nhưng em làm theo cách anh nói là thay đổi hoạt kỳ của nó theo đâuf vào nhưng em ko làm được, anh có thể sửa vào bài giúp em đươch không ak, khi em thay đổi đầu vào thi em ko nhận đươc đầu ra tương ứng anh ak`.

                    Comment


                    • #11
                      Nguyên văn bởi FPGA_9572XL Xem bài viết
                      em đã viết 1 chương trình thế này


                      nhưng em làm theo cách anh nói là thay đổi hoạt kỳ của nó theo đâuf vào nhưng em ko làm được, anh có thể sửa vào bài giúp em đươch không ak, khi em thay đổi đầu vào thi em ko nhận đươc đầu ra tương ứng anh ak`.
                      Tôi sửa code của bạn để áp dụng "generic". Bạn có thể chỉnh độ chu kỳ và duty cycle khi đặt (instantiate) nó.

                      Code:
                      ...
                      inst1 : PWM1 
                        generic map (pwm_max => 16,
                                     pwm_hi => 8,
                                     pwm_lo => 12)
                        port map  (clk_in,reset,ena,PWM_out);
                      Tôi hy vọng ví dụ này có thể giúp đỡ bạn

                      Chúc may mắn
                      Tony


                      Code:
                      entity PWM1 is
                       generic (pwm_max : integer := 12;
                                pwm_hi : integer := 8;
                                pwm_lo : integer := 10);
                       port (
                       clk_in,reset,ena:in std_logic ;
                       PWM_out: out std_logic
                       );
                       end PWM1;
                       
                      architecture Behavioral of PWM1 is 
                      begin
                       process (clk_in)
                       variable i : integer range 0 to pwm_max-1;
                       begin
                       if (reset='1' )then
                       PWM_out <= '0';
                       elsif(clk_in'event and clk_in = '1') then
                       if (ena = '1') then
                         if (i < pwm_hi) then 
                           PWM_out <='1';
                         elsif ((i > pwm_hi) and (i < pwm_lo)) then
                           PWM_out <= '0';
                         end if;
                         if (i = pwm_max-1) then 
                           i :=0;
                         else
                           i := i+1;
                         end if;
                       end if;
                       
                      end process; 
                      end Behavioral;
                      Chúc một ngày vui vẻ
                      Tony
                      email : dientu_vip@yahoo.com

                      Comment


                      • #12
                        Nguyên văn bởi FPGA_9572XL Xem bài viết
                        em đã viết 1 chương trình thế này


                        nhưng em làm theo cách anh nói là thay đổi hoạt kỳ của nó theo đâuf vào nhưng em ko làm được, anh có thể sửa vào bài giúp em đươch không ak, khi em thay đổi đầu vào thi em ko nhận đươc đầu ra tương ứng anh ak`.
                        Khi em mô phỏng thì kết quả ra thế nào?
                        Để code rõ hơn, em nên làm 2 process; 1 process để thực hiện bộ đếm, 1 process thưc hiện việc drive output.

                        counter: process(clk)
                        begin
                        if ...
                        if(cntr<10) then cntr <= cntr + 1; else cntr <= 0; end if;
                        end process;

                        driveoutput: process(cntr)
                        if(cntr<8) PWM <= '1'; else PWM <= '0';
                        ...

                        Comment


                        • #13
                          Em mô phỏng thi` chỉ có thể thay đổi được "hoat kỳ" dương (xung cao) từ 50% trở lên, nhưng nếu như em muốn cho "hoat kỳ" dương nhỏ hơn 50% thì lại không được, em thấy thấp nhất là 50% thôi. đây là code và ảnh chụp mô phỏng của em.
                          entity PWM is
                          Port ( clk : in STD_LOGIC;
                          rst : in STD_LOGIC;
                          up_down: in std_logic;
                          start :in std_logic;
                          dutyCycle : in STD_LOGIC_VECTOR (3 downto 0);
                          PWM_OUT : out STD_LOGIC
                          );
                          end PWM;

                          architecture Behavioral of PWM is
                          signal PWM : std_logic ;
                          begin

                          process(clk, rst,up_down,start)
                          variable counter : integer;

                          begin
                          if(rst = '1'or start = '0') then
                          counter:= 0;
                          PWM <= '0';
                          elsif (clk'event and clk ='1' ) then
                          if (up_down ='1') then
                          counter := counter + 1;
                          else
                          counter := counter -1;
                          end if;
                          if(counter < dutyCycle) then
                          PWM <= '1';
                          else
                          PWM <= '0';
                          end if;
                          end if;

                          end process;
                          PWM_OUT <= PWM;
                          end Behavioral;


                          Comment


                          • #14
                            ban cho timer dem che do 2 do
                            gia su co 256 muc thi ban dat no =1 trong khoang tho x tu 0-255
                            sau do cho no =0 trong khoang thoi gian con lai 255-x
                            cu lap nhu vay thoi
                            thay doigia tri x la thay doi do rong cung Pwm
                            Rat tiec minh khong co may o day de up cho ban xem code -mophong cua minh
                            Cám ơn bạn ! nhưng mình vần không hiểu cái đó làm như thế nào, mình chưa hiểu nhiều về timer. Bạn có thể cho mình 1 ví dụ không? hoặc bạn có thể gửi vào mail bài của bạn cho mình : phamtrongvn@gmail.com
                            Cám ơn bạn rất nhiều!

                            Comment


                            • #15
                              Nguyên văn bởi FPGA_9572XL Xem bài viết
                              Em mô phỏng thi` chỉ có thể thay đổi được "hoat kỳ" dương (xung cao) từ 50% trở lên, nhưng nếu như em muốn cho "hoat kỳ" dương nhỏ hơn 50% thì lại không được, em thấy thấp nhất là 50% thôi. đây là code và ảnh chụp mô phỏng của em.



                              Lỗi ở đây là counter cần phải reset (trở lại 0). bạn có thể sửa lại như sau với ví dụ counter max là 15

                              Code:
                              if (up_down ='1') then
                                if (counter = 15) then
                                  counter = 0;
                                else  
                                  counter := counter + 1;
                                end if;
                              else
                                if (counter = 0) then
                                  counter = 15;
                                else
                                  counter := counter -1;
                                end if;
                              end if;
                              Chúc một ngày vui vẻ
                              Tony
                              email : dientu_vip@yahoo.com

                              Comment

                              Về tác giả

                              Collapse

                              FPGA_9572XL Tìm hiểu thêm về FPGA_9572XL

                              Bài viết mới nhất

                              Collapse

                              Đang tải...
                              X