Измеритель расстояния на HC-SR04 без микроконтроллера
В этой статье пошагово соберем схему измерителя расстояния из нескольких микросхем стандартной логики.
Зачем
Все just-for-fun. Конечная схема является тривиальной и не несет новых технических решений. Автор не является профессиональным конструктором электроники и некоторые решения могут не отвечать принятым стандартам.
Больше оправданийРазработка даже простейшего цифрового устройства без использования микроконтроллера все чаще становится практически нецелесообразным занятием в силу низкой цены микроконтроллеров, их гибкости и богатого набора периферии, упакованного в компактный корпус.
Несмотря на это, автор находит разработку схем на дискретных элементах интересным занятием-пазлом, что-то на уровне лампового звука. В мире где все описывается программным кодом, исполняемым черными ящиками с миллиардами транзисторов, испытываешь неподдельное удивление, когда видишь, как небольшой набор логических вентилей, счетчиков и триггеров образуют устройство имеющее непростое поведение.
Конечно, такое мнение смогут разделить в основном те, для кого работа с дискретной логикой не была обыденностью.
Задача
Хотим получать устройство, представляющее расстояние в сантиметрах в десятичной системе счисления. Минимальное значение — 1 см, максимальное — 254 см. Для отображения используем 7-сегментный индикатор с 3 знакоместами, для измерения расстояния — модуль ультразвукового датчика HC-SR04 или аналог.
Да, я понимаю, что в модуле датчика скорее всего используется микроконтроллер. Это не считается.
Собираем
HC-SR04 — очень популярный, дешевый и неточный ультразвуковой датчик. Кратко о интерфейсе. Датчик имеет две сигнальные линии TRIG
(вход) и ECHO
(выход).
На вход TRIG
подаем импульс запуска измерения и через некоторое время получаем положительный импульс на выходе ECHO
. Длительность импульса ECHO
умноженная на некоторую константу K равна измеренному расстоянию.
Вся задача сводится к измерению длительности импульса в единицах времени K, для чего нам понадобится 8-битный счетчик, который будем тактировать частотой 1/K Гц. Выход счетчика будет отражать расстояние в сантиметрах (в двоичном представлении).
При этом, мы не хотим, чтобы в процессе счета на индикаторе отображалось постепенно увеличивающееся значение — это будет мешать чтению результата. Поэтому возьмем счетчик 74HC590 со встроенным выходным буферным регистром.
Выводами СЕ
(разрешение счета) и OE
(включение выходов) мы управлять не будем. На вход тактирования счетчика CPC
подан сигнал CLK0
задающего генератора (~= 58 мкс или 17240 Гц).
Нам нужно сбросить счетчик по фронту ECHO
и сохранить состояние счетчика в выходной регистр по спаду. Сбросом занимается вывод MRC
, а записью в выходной регистр — вывод CPR
. Сброс происходит по низкому уровню, как нам и нужно, а вот запись — по фронту (не по спаду, как хотелось бы). Придется добавить инвертор. Для уменьшения количества корпусов в качестве инвертора возьмем 74HC00 (4 элемента И-НЕ), далее нам еще понадобятся элементы И-НЕ.
Тут сталкиваемся с первой небольшой проблемой. После спада ECHO
сигнал на вывод MRC
придет чуть быстрее, чем на CPR
, так как инвертор вносит некоторую задержку. Состояние счетчика будет сохраняться сразу после сброса, то есть сохранится ноль. Обычно для дополнительной задержки сигала ставят буферы, но мы не будем разбрасываться элементами и внесем задержку с помощью RC цепочки.
Выбранный счетчик может считать только до 255, но от датчика может прийти сигнал большей длительности: когда измеренное расстояние более 255 см или если измерение не удалось (в этом случаи датчик намеренно выдает очень длинный импульс). В таких ситуациях наш счетчик просто переполнится (возможно, не один раз) и затем будет остановлен на каком-то случайном значении. Поэтому нужно останавливать счет по достижению максимального значения, что можно сделать используя выход переноса RCO
.
По достижению счетчиком значения 255 RCO
переходит в низкое состояние отключая тактирование счетчика, что «замораживает» его значение до сброса (следующего измерения). Еще мы тут «случайно» инвертировали сигнал тактирования (с целью не добавлять новый корпус и использовать оставшиеся элементы И-НЕ), в данном случаи это не приведет к проблемам.
Теперь нужно сформировать сигнал TRIG
, запускающий измерения. Его период должен быть на несколько порядков больше CLK0
(>60 мс). Для этого можно использовать отдельный низкочастотный генератор или поставить делитель на сигнал тактирования. Снова стремясь уменьшить количество элементов, пойдем вторым путем.
Возьмём CD4060 — делитель с коэффициентом деления до 214 с двумя встроенными инверторами (на которых мы соберем задающий RC генератор).
Генератор по схеме из даташита CD4060 запускаться у автора отказался, поэтому схема была изменена.
Для запуска измерения подадим сигнал с Q13
(~4 Гц) на TRIG
. Частота у него подходящая, а коэффициент заполнения (50%) — нет. Нам не нужен сигнал высокого уровня длительностью в 125 мс, нам нужно всего около 0.02–1 мкс. Решим эту проблему еще одной RC цепочкой в режиме high-pass фильтра.
Вы, наверное, заметили появление кнопки на схеме. Она реализует функцию «HOLD»: при ее удержании подавляются сигналы запуска измерения, тем самым на выходе счетчика будет удерживаться значение последнего измерения.
Запустив схему в таком виде с подключенными к выходу счетчика светодиодами мы уже сможем порадоваться значениям измеренного расстояния… в бинарном виде. Не сильно user-friendly, согласитесь, нужно срочно переводить в десятичную систему счисления. Сделать это можно несколькими способами, все они ужасны (требуют много корпусов), поэтому начинаем читерить (=.
Да, да, будет ПЗУ (параллельная EEPROM, в данном случаи). Тут многие могут возразить: «Как же так, без микроконтроллера, а программировать все равно нужно?! Заголовок — клик-бейт!» Что еще будет, когда придется показать, как прошивалась ПЗУ без покупки программатора.
«Программатор»В качестве программатора берем ардуину и кучку проводов. Прищурив глаза будем смотреть на ПЗУ как на гигантский декодер адреса и 8192 диода в одном корпусе.
Описание процесса программирования ПЗУ выходит за рамки статьи. Скажу лишь, что с ардуино сделать это довольно просто. Самое неудобное — необходимость формирования двух источников напряжения 14В (для стирания) и 12В (для записи). Скетч «программатора» приведен с файлами проекта в конце статьи.
При формировании содержимого ПЗУ, преобразование числа 255 было заменено на вывод трех прочерков »---», что означает неудачное измерение.
Входов у ПЗУ много, а вот выходов хватит только на одну цифру 7-сегментного индикатора, потому будем использовать динамическую индикацию. Входы A8
и A9
в бинарном коде выбирают одну из трех отображаемых цифр, четвертое состояние не используется и соответствует погашенным сегментам. Для активации цифры индикатора (в зависимости от кода на A8
и A9
) понадобится 2-битный дешифратор с инвертированными выходами (т.к. нам нужно управлять общими катодами индикатора). Сделать дешифратор можно так (четвертый код мы не используем).
Теперь осталось подключить наш дешифратор и ПЗУ к делителю частоты, который будет заниматься формированием сигналов для A8
, A9
и IN0
, IN1
, тем самым последовательно перебирая десятичные цифры.
Цифры будут переключаться с частотой ~1кГц, поэтому не страшно, что они переключаются не по порядку, глазу это будет не заметно.
Однако, выходы делителя рассчитаны на нагрузку около 1 мА, чего недостаточно для управления индикатором (на схеме выше сигнал CLK5
с делителя напрямую подключен к индикатору). Нас тут спас бы еще один инвертор (или буфер) перед CLK5
, но мы уже использовали все 4 элемента И-НЕ из 74HC00. Не добавлять же ради одного элемента еще один корпус. Используем вместо этого свободный выход D7
ПЗУ, запрограммировав его так, чтобы на D7
всегда была инверсия A9
. (Можно было бы и без инверсии, просто так сложилось.) Нагрузочная способность выхода ПЗУ достаточна для управления индикатором.
Собираем все вместе, добавляем регулятор питания и посыпаем схему щепоткой блокировочных конденсаторов.
Правильно собранное устройство настройки не требу -
Калибровка
Для правильного измерения расстояния нам нужно подстроить частоту задающего генератора подстрочным резистором. Сделать это можно так: размещаем датчик напротив ровной стены на известном расстоянии (чем больше, тем лучше точность калибровки). Расстояние выбираем как N+0.5 см, где N — целое. Далее ищем положение резистора, при котором значение на индикаторе самопроизвольно переключается между N и N+1. (Например, между 127 и 128, если выбранное расстояние — 127.5 см.)
Итог
Теоретическая точность измерений +/- 1 см, не считая погрешность датчика. На самом деле все еще хуже, т.к. частота генератора плавает.
Потребление ~14 мА, предполагается питание от «кроны». Даже плохой батарейки должно хватить на 6–8 часов.
Схема может измерять не только расстояние, но и другие физические величины. Нужен только преобразователь, который линейно переводит измеряемую величину в длительность сигнала.
Фото
Схема была отлажена на бредборде.
Потом решил заказать плату, для эстетического удовольствия.
Знаете, как называется, когда берешь первую непроверенную плату и впаиваешь в нее ПЗУ без каретки?
Это смелость.
Смелость и слабоумие, конечно.
В процессе переноса схемы с бредборда была допущена ошибка: перепутаны общие катоды двух крайних индикаторов (число 123 отображается как 321). Благо, это было исправлено через перепрошивку ПЗУ. Так что даже не пришлось резать и подпаивать проводки.
Ссылки
github.com/AlexIII/no-mcu-distance-meter — схема/плата в Ki-CAD 5.1 и скетч для Arduino mega 2560, которым прошивалась ПЗУ
— На этом все, спасибо за внимание!