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

Проект 23. Частотомер

Частота измеряется подсчётом импульсов за строго отмеренную секунду. Точность целиком определяется стабильностью тактового генератора.

Задача

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

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

Алгоритм

  1. Синхронизировать входной сигнал цепочкой триггеров.
  2. Считать его нарастающие фронты.
  3. Параллельно отсчитывать секундное окно по тактовой частоте.
  4. В конце окна защёлкнуть результат, обнулить счётчик и выдать признак готовности.

Код на VHDL

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

--=====================================================
-- Проект 23. Частотомер
-- Импульсы считаются в измерительном окне ровно
-- в одну секунду; результат защёлкивается в конце окна.
--=====================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity freq_meter is
    generic ( CLK_HZ : integer := 50_000_000 );
    port (
        clk     : in  std_logic;
        rst     : in  std_logic;
        sig     : in  std_logic;                        -- измеряемый сигнал
        freq    : out std_logic_vector(19 downto 0);    -- частота в герцах
        ready   : out std_logic
    );
end entity freq_meter;

architecture rtl of freq_meter is
    signal window : integer range 0 to CLK_HZ := 0;
    signal cnt    : unsigned(19 downto 0) := (others => '0');
    signal sync   : std_logic_vector(2 downto 0) := "000";
begin
    process (clk, rst)
    begin
        if rst = '1' then
            window <= 0; cnt <= (others => '0'); ready <= '0';
        elsif rising_edge(clk) then
            sync  <= sync(1 downto 0) & sig;            -- синхронизация входа
            ready <= '0';

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

            if window = CLK_HZ - 1 then                 -- окно закрылось
                window <= 0;
                freq   <= std_logic_vector(cnt);        -- защёлкиваем результат
                cnt    <= (others => '0');
                ready  <= '1';
            else
                window <= window + 1;
            end if;
        end if;
    end process;
end architecture rtl;

Пояснения

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

Что дальше

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