Найти тему
ПЛИСовод.

FPGA: Делаю кухонный таймер за 2 тыщи

Приветствую в своём блоге, где я стремлюсь к запуску Linux на своей платке с Altera Cyclone IV. Это уже 4-я часть блога, и сегодня я продолжу осваивать Verilog, заодно приступлю к созданию дорогого и неудобного кухонного таймера.

Цель создать кухонный таймер появилась не просто так, а после просмотра вот этого видео:

И в нём рассматривается 4-х позиционный семисегментный индикатор. А так-же на него выводится пара цифр.

Но это было скучно, поэтому решил расширить задачу. В конце концов, основная цель, решаемая мною вместе с просмотром этого видеокурса - это попрактиковаться в Verilog и усвоить несколько примеров того, как нужно проектировать схемы, а как не нужно.

Потому и таймер. Кроме индикатора, понадобится мне ещё и кнопки, которых на плате целых 4 штуки. Буду использовать их так:

  • Добавить 30 секунд ко времени
  • Убрать 30 секунд
  • Запустить таймер/поставить на паузу.
  • Остановить и сбросить таймер

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

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

Время, необходимое на прекращение дребезга зависит от кнопки, и может достигать аж 10 мс. (сотая часть секунды). Хотя это только отдельные образцы. Большинство кнопок укладываются в 6мс, а в среднем дребезг длится 1-2 мс.

Итоговый, модуль устранения дребезга выглядит так.

Длина последовательности last в битах, помноженная на время периода сигнала clk как раз и дадут продолжительность периода, в течении которого производятся замеры состояния кнопки перед её переключением. Я собираюсь тактировать модуль 512гц, длина last - 3 бита, итоговый период замера: 6мс. А поскольку самих замеров целых 3 штуки, и смотрю я на все, то ложные срабатывания крайне маловероятны. Обратите внимание, что модуль наружу выдаёт не состояние кнопки, а сигнал pos, длительность этого сигнала составляет всегда ровно 1 такт. Называется подобные сигналы стробами. Появление такого строба обозначает, что на кнопку нажали.

На нижней полоске отчётливо виден строб, возникший на 3-м прямом фронте clk от момента установления сигнала.
На нижней полоске отчётливо виден строб, возникший на 3-м прямом фронте clk от момента установления сигнала.

И раз я решил тактировать модуль дребезга 512 гц, то эти 512гц нужно откуда-то получить. На помощь приходит счётчик, с периодом работы равным: 48000000 / 512 = 93750. На этот раз ровно, а не приблизительно.

Значит, добавлю в проект делитель частоты.

Модуль невероятно прост, так что даже не удивительно, что работает хорошо и чётко.

Параметр PERIOD модуля для наглядности я поставил = 6
Параметр PERIOD модуля для наглядности я поставил = 6

Ну и последнее, что я сделаю в рамках сегодняшней статьи - создам сам дисплейный модуль. Отображать он будет 16 битное значение в 16-ричном виде. Если применить немного фантазии, то 16-ричное представление может быть отображено и на 7-сегментном индикаторе. Получится как то так

Все 16-ричные значения на 7-сегментном индикаторе.
Все 16-ричные значения на 7-сегментном индикаторе.

И пусть непосредственно для кухонного таймера, все эти abcdef не нужны, но я сделаю и их сразу. Мешать они не станут.

Дисплейный модуль получился таким.

И пусть сток кода в нём не так мало, он до неприличия прост. Ну и в завершении - диаграмма его работы:

Сигнал en показывает - какая позиция сейчас активна. А dg - конкретные сегменты.
Сигнал en показывает - какая позиция сейчас активна. А dg - конкретные сегменты.

Вот только сам контроллер таймера я решил оставить на следующую статью. Он оказался не таким уж простым, как всё то, что я понасоздавал сегодня.

До новых встреч, с вами был мой блог, в котором я планирую сообщать о своих достижениях как можно чаще (в идеале - ежедневно)