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

Проект 30. Измеритель частоты

За эталонный интервал в одну секунду схема считает фронты входного сигнала — результат сразу читается в герцах. Точность целиком определяется опорным генератором.

Задача

Измерить частоту входного сигнала и выдать значение в герцах.

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

Алгоритм

  1. Отсчитывать такты до значения тактовой частоты — это ровно секунда.
  2. Параллельно синхронизировать входной сигнал и считать его фронты.
  3. По окончании окна переписать счётчик в выходной регистр.
  4. Обнулить счётчик и начать новое измерение.

Код на VHDL

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

--=====================================================
-- Проект 30. Измеритель частоты
-- За эталонную секунду считаем импульсы входного
-- сигнала — получаем частоту в герцах.
--=====================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity freq_counter is
    generic (
        CLK_HZ : integer := 50_000_000                  -- тактовая частота
    );
    port (
        clk     : in  std_logic;
        rst     : in  std_logic;
        sig_in  : in  std_logic;                        -- измеряемый сигнал
        freq    : out std_logic_vector(23 downto 0);    -- частота, Гц
        valid   : out std_logic                         -- результат обновлён
    );
end entity freq_counter;

architecture rtl of freq_counter is
    signal gate    : integer range 0 to CLK_HZ := 0;    -- отсчёт секунды
    signal pulses  : unsigned(23 downto 0) := (others => '0');
    signal sync    : std_logic_vector(2 downto 0) := "000";
begin
    process (clk, rst)
    begin
        if rst = '1' then
            gate   <= 0;
            pulses <= (others => '0');
            valid  <= '0';
            sync   <= "000";
        elsif rising_edge(clk) then
            sync  <= sync(1 downto 0) & sig_in;         -- синхронизация входа
            valid <= '0';

            -- считаем нарастающие фронты входного сигнала
            if sync(2) = '0' and sync(1) = '1' then
                pulses <= pulses + 1;
            end if;

            if gate = CLK_HZ - 1 then                   -- секунда истекла
                freq   <= std_logic_vector(pulses);
                valid  <= '1';
                pulses <= (others => '0');
                gate   <= 0;
            else
                gate <= gate + 1;
            end if;
        end if;
    end process;
end architecture rtl;

Пояснения

  • Точность измерения равна точности опорного генератора: погрешность кварца в тысячные доли процента напрямую переходит в результат.
  • Метод счёта за фиксированное окно хорош на высоких частотах; на низких выгоднее измерять период и брать обратную величину.
  • Разрешение метода — один герц, и улучшить его можно только удлинением измерительного окна.

Что дальше

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