AFON // радиотехник affonya@mail.ru
← Проекты на VHDL

Проект 36. Многоканальный контроллер сервоприводов

Один общий счётчик периода 20 мс обслуживает сразу четыре канала ШИМ: у каждого свой компаратор длительности импульса, а ресурсы кристалла расходуются экономно.

Задача

Формировать управляющие импульсы для четырёх сервоприводов одновременно.

Тип схемы: Синхронная схема: общий таймер и массив компараторов.
Модуль: servo_ctrl. Среда: Quartus, Vivado, ISE или свободный GHDL для моделирования. Теорию по языку смотрите в статье VHDL — язык описания аппаратуры, по самим микросхемам — на странице ПЛИС.

Алгоритм

  1. Разделить тактовую частоту до одной микросекунды делителем.
  2. На этой基е считать общий период в 20000 микросекунд.
  3. Для каждого канала сравнивать счётчик периода с его уставкой.
  4. Держать канал активным, пока счётчик меньше уставки.

Код на 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.