PWM 和 VHDL 实现舵机控制






4.73/5 (10投票s)
使用 VHDL 生成 PWM 信号以控制舵机。
引言
在这篇简短的文章中,我们将使用 VHDL 生成用于舵机控制的脉宽调制 (PWM) 信号。
背景
首先,舵机不过是带有附加电子电路的直流电机,目的是实现更好的控制。为了进行这种控制,我们需要生成如下波形
脉冲的时间或频率决定了舵机的角度位置。每个舵机都有自己的频率范围,由制造商在数据手册中提供。图示的值在 1ms 到 2ms 之间。
控制设计
舵机的控制信号由两个频率组成
- 刷新频率,为 20ms。
- 脉冲宽度范围,由制造商提供。对于本文,我们假设该频率范围为 0.5ms 到 2.5ms。
首先,我们需要确定我们的工作范围,由下式给出
现在我们需要知道舵机的分辨率,即它可以采取的位置数量。因此,所需的最小频率相当于
如果我们的舵机最多可以采取 128 个位置,那么结果是
现在我们需要一个 64kHz 的频率分频器。虽然我们可以按照 VHDL 实现频率分频器 中描述的过程来做,但这里我们提供了从 50MHz 到 64kHz 的完整分频器代码
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity clk64kHz is
Port (
clk : in STD_LOGIC;
reset : in STD_LOGIC;
clk_out: out STD_LOGIC
);
end clk64kHz;
architecture Behavioral of clk64kHz is
signal temporal: STD_LOGIC;
signal counter : integer range 0 to 780 := 0;
begin
freq_divider: process (reset, clk) begin
if (reset = '1') then
temporal <= '0';
counter <= 0;
elsif rising_edge(clk) then
if (counter = 780) then
temporal <= NOT(temporal);
counter <= 0;
else
counter <= counter + 1;
end if;
end if;
end process;
clk_out <= temporal;
end Behavioral;
最后,我们知道使用 64kHz 时钟,每 64 次迭代将有 1ms。因此,为了获得 20ms 的频率,我们只需要将 20 * 64 相乘,这将使用一个从 0 到 1279 的计数器来实现。
VHDL 实现
对于 VHDL 实现,我们有三个输入:64 kHz 时钟、复位和可以取 0 到 127 值的向量。唯一的输出是舵机控制信号。代码如下所示。library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity servo_pwm is
PORT (
clk : IN STD_LOGIC;
reset : IN STD_LOGIC;
pos : IN STD_LOGIC_VECTOR(6 downto 0);
servo : OUT STD_LOGIC
);
end servo_pwm;
architecture Behavioral of servo_pwm is
-- Counter, from 0 to 1279.
signal cnt : unsigned(10 downto 0);
-- Temporal signal used to generate the PWM pulse.
signal pwmi: unsigned(7 downto 0);
begin
-- Minimum value should be 0.5ms.
pwmi <= unsigned('0' & pos) + 32;
-- Counter process, from 0 to 1279.
counter: process (reset, clk) begin
if (reset = '1') then
cnt <= (others => '0');
elsif rising_edge(clk) then
if (cnt = 1279) then
cnt <= (others => '0');
else
cnt <= cnt + 1;
end if;
end if;
end process;
-- Output signal for the servomotor.
servo <= '1' when (cnt < pwmi) else '0';
end Behavioral;
信号 cnt
用于实现从 0 到 1279 的计数器,其描述在第 22 行到第 33 行。
输入信号 pos
是一个可以取 0 到 127 之间的任何值的向量,产生 0ms 到 2ms 的范围。由于我们需要一个从 0.5ms 到 2.5ms 的信号,我们需要添加一个相当于 0.5ms 的偏移量 32。
列表 3,如下所示,描述了将频率分频器和舵机控制组件连接在一起所需的 PORT MAP
。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity servo_pwm_clk64kHz is
PORT(
clk : IN STD_LOGIC;
reset: IN STD_LOGIC;
pos : IN STD_LOGIC_VECTOR(6 downto 0);
servo: OUT STD_LOGIC
);
end servo_pwm_clk64kHz;
architecture Behavioral of servo_pwm_clk64kHz is
COMPONENT clk64kHz
PORT(
clk : in STD_LOGIC;
reset : in STD_LOGIC;
clk_out: out STD_LOGIC
);
END COMPONENT;
COMPONENT servo_pwm
PORT (
clk : IN STD_LOGIC;
reset : IN STD_LOGIC;
pos : IN STD_LOGIC_VECTOR(6 downto 0);
servo : OUT STD_LOGIC
);
END COMPONENT;
signal clk_out : STD_LOGIC := '0';
begin
clk64kHz_map: clk64kHz PORT MAP(
clk, reset, clk_out
);
servo_pwm_map: servo_pwm PORT MAP(
clk_out, reset, pos, servo
);
end Behavioral;
测试平台和仿真
对于测试平台,我们使用 pos
的五个不同值,描述在第 43 行到第 59 行。
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY servo_pwm_clk64kHz_tb IS
END servo_pwm_clk64kHz_tb;
ARCHITECTURE behavior OF servo_pwm_clk64kHz_tb IS
-- Unit under test.
COMPONENT servo_pwm_clk64kHz
PORT(
clk : IN std_logic;
reset : IN std_logic;
pos : IN std_logic_vector(6 downto 0);
servo : OUT std_logic
);
END COMPONENT;
-- Inputs.
signal clk : std_logic := '0';
signal reset: std_logic := '0';
signal pos : std_logic_vector(6 downto 0) := (others => '0');
-- Outputs.
signal servo : std_logic;
-- Clock definition.
constant clk_period : time := 10 ns;
BEGIN
-- Instance of the unit under test.
uut: servo_pwm_clk64kHz PORT MAP (
clk => clk,
reset => reset,
pos => pos,
servo => servo
);
-- Definition of the clock process.
clk_process :process begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimuli process.
stimuli: process begin
reset <= '1';
wait for 50 ns;
reset <= '0';
wait for 50 ns;
pos <= "0000000";
wait for 20 ms;
pos <= "0101000";
wait for 20 ms;
pos <= "1010000";
wait for 20 ms;
pos <= "1111000";
wait for 20 ms;
pos <= "1111111";
wait;
end process;
END;
仿真结果如下所示。获得了以下频率
- 刷新频率为 19.9936 ms。
- 最小频率为 0.4920 ms。
- 最大频率为 2.4835 ms。