Задача
Формировать управляющие импульсы для четырёх сервоприводов одновременно.
Тип схемы: Синхронная схема: общий таймер и массив компараторов.
Модуль: servo_ctrl. Среда: Quartus, Vivado, ISE или свободный GHDL для моделирования.
Теорию по языку смотрите в статье VHDL — язык описания аппаратуры,
по самим микросхемам — на странице ПЛИС.
Алгоритм
- Разделить тактовую частоту до одной микросекунды делителем.
- На этой基е считать общий период в 20000 микросекунд.
- Для каждого канала сравнивать счётчик периода с его уставкой.
- Держать канал активным, пока счётчик меньше уставки.
Код на VHDL
Код проверен компилятором GHDL: проходит анализ и элаборацию без ошибок и предупреждений. Скачать: v36.vhd
--=====================================================
-- Проект 36. Многоканальный контроллер сервоприводов
-- Один таймер периода 20 мс обслуживает четыре канала
-- ШИМ с независимой длительностью импульса.
--=====================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity servo_ctrl is
generic (
CLK_DIV : integer := 50 -- 50 МГц -> 1 МГц (1 мкс/такт)
);
port (
clk : in std_logic;
rst : in std_logic;
pulse0 : in std_logic_vector(10 downto 0); -- длительность, мкс, 4 канала
pulse1 : in std_logic_vector(10 downto 0);
pulse2 : in std_logic_vector(10 downto 0);
pulse3 : in std_logic_vector(10 downto 0);
servo_out: out std_logic_vector(3 downto 0)
);
end entity servo_ctrl;
architecture rtl of servo_ctrl is
signal us_tick : std_logic := '0';
signal presc : integer range 0 to CLK_DIV-1 := 0;
signal period : integer range 0 to 19999 := 0; -- 20000 мкс = 20 мс
begin
-- делитель до одной микросекунды
process (clk, rst)
begin
if rst = '1' then
presc <= 0;
us_tick <= '0';
elsif rising_edge(clk) then
if presc = CLK_DIV - 1 then
presc <= 0;
us_tick <= '1';
else
presc <= presc + 1;
us_tick <= '0';
end if;
end if;
end process;
-- общий счётчик периода и четыре независимых компаратора
process (clk, rst)
begin
if rst = '1' then
period <= 0;
elsif rising_edge(clk) then
if us_tick = '1' then
if period = 19999 then
period <= 0;
else
period <= period + 1;
end if;
end if;
end if;
end process;
servo_out(0) <= '1' when period < to_integer(unsigned(pulse0)) else '0';
servo_out(1) <= '1' when period < to_integer(unsigned(pulse1)) else '0';
servo_out(2) <= '1' when period < to_integer(unsigned(pulse2)) else '0';
servo_out(3) <= '1' when period < to_integer(unsigned(pulse3)) else '0';
end architecture rtl;
Пояснения
- Общий счётчик периода экономичнее четырёх независимых таймеров: ресурсы ПЛИС расходуются только на компараторы, которые в разы дешевле полноценных счётчиков.
- Уставки заданы в микросекундах напрямую — при делителе до 1 МГц значение регистра совпадает с длительностью импульса без пересчёта.
- Подход легко расширяется до восьми и более каналов: добавляется лишь по одному компаратору на каждый новый сервопривод.
Что дальше
Следующие проекты — в разделе проекты на VHDL. Сравнить подход с языком Verilog можно в статье Verilog, а разобраться в устройстве самих кристаллов — в статье ПЛИС: FPGA и CPLD.