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

Проект 19. Декодер квадратурного энкодера

Два сигнала со сдвигом фаз позволяют определить не только факт вращения, но и его направление. Схема ведёт счёт положения со знаком.

Задача

Определять направление вращения и вести счёт положения вала.

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

Алгоритм

  1. Пропустить оба канала через синхронизаторы.
  2. Обнаружить фронт канала A детектором фронта.
  3. В этот момент прочитать канал B: его уровень задаёт направление.
  4. Увеличить или уменьшить счётчик положения.

Код на VHDL

Код проверен компилятором GHDL: проходит анализ и элаборацию без ошибок и предупреждений. Скачать: v19.vhd

--=====================================================
-- Проект 19. Декодер квадратурного энкодера
-- По двум сигналам со сдвигом фаз определяем
-- направление вращения и ведём счёт положения.
--=====================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity quad_decoder is
    port (
        clk      : in  std_logic;
        rst      : in  std_logic;
        a, b     : in  std_logic;                       -- каналы энкодера
        position : out std_logic_vector(15 downto 0);
        cw       : out std_logic;                       -- импульс: по часовой
        ccw      : out std_logic                        -- импульс: против
    );
end entity quad_decoder;

architecture rtl of quad_decoder is
    signal a_sync, b_sync : std_logic_vector(2 downto 0) := "000";
    signal pos : signed(15 downto 0) := (others => '0');
begin
    process (clk, rst)
    begin
        if rst = '1' then
            pos    <= (others => '0');
            a_sync <= "000";
            b_sync <= "000";
            cw     <= '0';
            ccw    <= '0';
        elsif rising_edge(clk) then
            -- синхронизация и запоминание прошлого состояния
            a_sync <= a_sync(1 downto 0) & a;
            b_sync <= b_sync(1 downto 0) & b;
            cw  <= '0';
            ccw <= '0';

            -- реагируем на фронт канала A
            if a_sync(2) = '0' and a_sync(1) = '1' then
                if b_sync(1) = '0' then
                    pos <= pos + 1;                     -- B отстаёт — вращение вперёд
                    cw  <= '1';
                else
                    pos <= pos - 1;                     -- B опережает — назад
                    ccw <= '1';
                end if;
            end if;
        end if;
    end process;

    position <= std_logic_vector(pos);
end architecture rtl;

Пояснения

  • Счётчик объявлен типом signed, поэтому корректно работает с отрицательными значениями при вращении назад.
  • Синхронизация каналов обязательна: энкодер — механическое устройство, полностью асинхронное относительно тактовой сетки.
  • Схема считает по одному фронту канала A. Учитывая оба фронта и оба канала, разрешение можно увеличить вчетверо.

Что дальше

Следующие проекты — в разделе проекты на VHDL. Сравнить подход с языком Verilog можно в статье Verilog, а разобраться в устройстве самих кристаллов — в статье ПЛИС: FPGA и CPLD.