Инструкция
Действие ультразвукового дальномера HC-SR04 основано на принципе эхолокации. Он излучает звуковые импульсы в пространство и принимает отражённый от препятствия сигнал. По времени распространения звуковой волны к препятствию и обратно определяется расстояние до объекта.
Запуск звуковой волны начинается с подачи положительного импульса длительностью не менее 10 микросекунд на ножку TRIG дальномера. Как только импульс заканчивается, дальномер излучает в пространство перед собой пачку звуковых импульсов частотой 40 кГц. В это же время запускается алгоритм определения времени задержки отражённого сигнала, а на ножке ECHO дальномера появляется логическая единица. Как только датчик улавливает отражённый сигнал, на выводе ECHO появляется логический ноль. По длительности этого сигнала ("Задержка эхо" на рисунке) определяется расстояние до объекта.
Диапазон измерения расстояния дальномера HC-SR04 - до 4 метров с разрешением 0,3 см. Угол наблюдения - 30 градусов, эффективный угол - 15 градусов. Ток потребления в режиме ожидания 2 мА, при работе - 15 мА.
Питание ультразвукового дальномера осуществляется напряжением +5 В. Два других вывода подключаются к любым цифровым портам Arduino, мы подключим к 11 и 12.
Теперь напишем скетч, определяющий расстояние до препятствия и выводящий его в последовательный порт. Сначала задаём номера выводов TRIG и ECHO - это 12 и 11 пины. Затем объявляем триггер как выход, а эхо - как вход. Инициализируем последовательный порт на скорости 9600 бод. В каждом повторении цикла loop()
считываем дистанцию и выводим в порт.
Функция getEchoTiming()
генерирует импульс запуска. Она как раз создаёт ток 10 мксек импульс, который является триггером для начала излучения дальномером звукового пакета в пространство. Далее она запоминает время от начала передачи звуковой волны до прихода эха.
Функция getDistance()
рассчитывает дистанцию до объекта. Из школьного курса физики мы помним, что расстояние равно скорость умножить на время: S = V*t. Скорость звука в воздухе 340 м/сек, время в микросекундах мы знаем, это "duratuion". Чтобы получить время в секундах, нужно разделить на 1.000.000. Так как звук проходит двойное расстояние - до объекта и обратно - нужно разделить расстояние пополам. Вот и получается, что расстояние до объекта S = 34000 см/сек * duration / 1.000.000 сек / 2 = 1,7 см/сек / 100, что мы и написали в скетче. Операцию умножения микроконтроллер выполняет быстрее, чем деления, поэтому "/ 100" я заменил на эквивалентное "* 0,01".
Также для работы с ультразвуковым дальномером написано множество библиотек. Например, вот эта: http://robocraft.ru/files/sensors/Ultrasonic/HC-SR04/ultrasonic-HC-SR04.zip. Установка библиотеки происходит стандартно: скачать, разархивировать в директорию libraries
, которая находится в папке с Arduino IDE. После этого библиотекой можно пользоваться.
Установив библиотеку, напишем новый скетч. Результат его работы тот же - в мониторе последовательного порта выводится дистанция до объекта в сантиметрах. Если в скетче написать float dist_cm = ultrasonic.Ranging(INC);
, то дистанция будет отображаться в дюймах.
Итак, мы с вами подключили к Arduino ультразвуковой дальномер HC-SR04 и получили с него данные двумя разными способами: с использованием специальной библиотеки и без.
Преимущество использования библиотеки в том, что количество кода значительно сокращается и улучшается читаемость программы, вам не приходится вникать в тонкости работы устройства и вы сразу же можете его использовать. Но в этом же кроется и недостаток: вы хуже понимаете, как работает устройство и какие в нём происходят процессы. В любом случае, каким способом пользоваться - решать только вам.
Сегодня попробуем остановиться на выводе на текстовый дисплей. Наиболее популярным является чип HD44780 (или совместимый с ним KS0066). Перечислим их плюсы и минусы:
Исходя из вышеизложенного буду рассматривать только подключение дисплея через I2C.
Давайте попробуем.
Что нам понадобится.
На самом деле все довольно просто. Если, перевернув дисплей мы видим длинную колодку разъемов (как правило 16 штук) то модуля I2C на дисплее нет:
А вот так выглядит дисплей с уже установленным I2C-модулем:
Контакты SCL, SDA, VCC, GND используются для подключения Arduino. Два контакта слева - на картинке они замкнуты перемычкой - нужны для работы подсветки.
Если модуль не подключен - придется сделать это самостоятельно. Главное, на что стоит обратить внимание - соединить контакты в правильном порядке. Как правило первый и 16 пины помечены. Иногда бывает, что 15-16 контакты, через которые осуществляется управление подсветкой, могут располагаться перед первым (в этом случае они будут пронумерованы). На самом же модуле первый пин также может быть обозначен не цифрой, а квадратом вокруг самого пина.
Соберем следующую схему:
Обращу внимание на следующие моменты:
как заметили, два пина на I2C-модуле с маркировкой LED отвечают за подсветку дисплея. Если не хотим использовать управление яркостью - их просто можно замкнуть.
Теперь давайте разберем код.
Тут почти все нам должно быть знакомо. В строке 5 указываем адрес устройства. В строках 16 и 17 - количество символов в строке и количество строк. В строках 20-22 - Создаем объект для работы с дисплеем и описываем параметр работы с ним.
В большинстве своем адрес можно посмотреть в даташите к микросхеме, на которой построено I2C-устройство. Если же такой возможности нет вот ссылка на архив со скетчем и схемами - http://www.ansealk.ru/files/Arduino_lcd_i2c.zip который определяет адреса всех устройств, подключенных по I2C-шине. Достаточно только подключить устройство к Arduino, загрузить скетч, открыть консоль и увидеть адрес.
Тут мы видим функцию, которая, собственно, и будет заниматься выводом на дисплей. Принцип вывода примерно такой:
Задаём позицию начала вывода функцией setCursor()
Печатаем строку функцией print()
После этого следующая функцию print() начнет вывод со следующей позиции, после которой закончился предыдущий ввод. Также обращу внимание на то, что, в отличие от вывода в консоль, тут не используется функция println() для завершения вывода и перевода строки.
Таким образом у нас на экране в первой строке появится надпись "Test LCD1602", а во второй будет указано разрешение дисплея и счетчик, показывающий, сколько циклов отработал наш скетч.
Но, если нам надо будет выводить много значений переменных на экран, этот метод не совсем удобен. Дело в том, что процедура вывода на дисплей - очень энергоёмкая и медленная, а вывод мы делаем в этой функции аж 7 раз. Гораздо проще будет заранее сформировать строку заранее, а затем вывести её целиком. В этом нам поможет функция форматированного ввода sprintf().
Небольшое отступление №3: Функция форматированного ввода sprintf().
В Языке C существует несколько очень удобных функций для вывода строк - они называются функциями форматированного вывода - printf (от слов print и format). В нашем конкретном случае нас интересует функция sprintf, которая не выводит ничего на экран, а формирует строку для последующего вывода. Выглядит она примерно так:
sprintf (str , "Строка %d для вывода ", i );
Функция формирует строку (помечено синим) с использованием шаблона (желтым), в который подставляются значения переменных (зеленым). Полученный результат будет записан в строковую переменную (красным).
Шаблонов и переменных может быть несколько. В этом случае переменные записываются через запятую. Главное, следите за тем, чтобы количество шаблонов в строке соответствовало количеству переменных. Переменные для шаблонов берутся последовательно, т.е. в первый шаблон подставляется значение первой переменной, во второй - второй переменной и т.д.
Что же такое шаблоны? Любой шаблон начинается символом "%" и заканчивается одним из десяти (в случае Arduino - семи) символов типа. Между ними может быть указано довольно много информации о том, как выводить значение, а может быть не указано и ничего.
Давайте разберем что же может быть в шаблоне. В общем случае шаблон имеет такой вид:
%[флаг ][ширина ][.точность ]типа
Квадратные скобки показывают, что элемент заключенный в них может отсутствовать. Вертикальная черта говорит о том, что в этом поле должно быть выбрано одно из указанных значений (в нашем случае одна из букв H, I, или L).
Давайте сначала разберемся с обязательным элементом шаблона - типом. Он указывает, какой тип переменной будет выводится и может принимать одно из следующих значений:
Символ | Значение |
c | Один символ |
s | Строка символов |
d,i | Целое десятичное со знаком |
o | Целое восьмеричное |
u | Целое десятичное без знака |
x, X | Целое шестнадцатеричное |
p | Указатель (в шестнадцатеричном виде) |
f | Дробное число в фиксированном формате |
e, E | Дробное число в научном формате |
g, G | Дробное число в научном или фиксированном формате |
Серым помечены те типы, которые не применимы при работе с Arduino. Таким образом, для вывода строки надо указать "%s", а для вывода целого числа - "%d".
Далее рассмотрим поле ширины. Число в нем указывает минимальную ширину поля, в котором будет выведен шаблон. Если размер значения в переменной меньше - поле будет добито пробелами, если больше - запись выйдет за пределы поля. Таким образом шаблон "%6d" для числа 385 выведет 385 (обратим внимание на три пробела перед числом).
Спецификатор точности всегда начинается с точки и следующее за ним число указывает различные действия в зависимости от типа значения. Для типов "d,o,u,x" он укажет минимальное количество символов, которое должно появится при обработке. Для типа "f" - число знаков после запятой. Для типа "s" - максимальное число символов стоки, который будут выведены. Например, "%6.1f" для числа 34.2345 выведет "34.1" (обращу внимание, что точка также считается знаком и перед числом будет присутствовать два пробела). Или шаблон "%.3s" от строки "точность" выведет только первые три символа - "точ".
Флаг позволяет изменить отображение выводимого значения:
Более подробно о шаблонах функции printf можно прочитать интернете. Здесь же я дал краткий обзор наиболее часто используемых возможностей.
Таким образом, наша функция вывода, переписанная с учетом использования форматированного вывода будет выглядеть следующим образом:
Заметим, что в строках 33 и 37 мы формируем целую строку для вывода, а в строках 34 и 38 - выводим их.
Наконец, наши любимые функции setup и loop.
В строке 47 мы задаем разрешение дисплея, в строке 48 - включим подсветку (яркость которой можно отрегулировать потенциометром). В строке 49 установим счетчик циклов в ноль. Увеличивать его будем на единицу в 37-й строке при выводе (помните конструкцию count++?). Наконец, в строке 56 вызываем рассмотренную раннее функцию вывода на дисплей. Все.
К примеру, можно сделать автоматическое управление подсветкой в зависимости от освещенности, использовав фоторезистор или датчик освещенности из рассмотренной несколькими статьями ранее метеостанции. Допустим, при сильном освещении - увеличить яркость подсветки, а в ночное время - уменьшить. Или прикрутить датчик движения и зажигать подсветку при появлении объект перед дисплеем, или... В общем, я думаю, вы уже поняли, что при желании, заменив один или несколько компонентов и написав кусок кода можно довольно серьезно улучшить удобство работы с дисплеем. Также мы можем использовать для вывода на дисплей собственноручно разработанные символы.
Все эти вопросы я тут не рассматриваю, так как они выходят за рамки обзора для начинающих.
А на сегодня у меня все.
Arduino. Подключаем LCD-дисплей
26 оценок, Средняя оценка: 5 из 5LCD дисплей Arduino позволяет визуально отображать данные с датчиков. Расскажем, как правильно подключить LCD монитор к Arduino по I2C и рассмотрим основные команды инициализации и управления LCD 1602. Также рассмотрим различные функции в языке программирования C++, для вывода текстовой информации на дисплее, который часто требуется использовать в проектах на Ардуино.
I2C - последовательная двухпроводная шина для связи интегральных схем внутри электронных приборов, известна, как I²C или IIC (англ. Inter-Integrated Circuit). I²C была разработана фирмой Philips в начале 1980-х годов, как простая 8-битная шина для внутренней связи между схемами в управляющей электронике (например, в компьютерах на материнских платах, в мобильных телефонах и т.д.).
В простой системе I²C может быть несколько ведомых устройств и одно ведущее устройство, которое инициирует передачу данных и синхронизирует сигнал. К линиям SDA (линия данных) и SCL (линия синхронизации) можно подключить несколько ведомых устройств. Часто ведущим устройством является контроллер Ардуино, а ведомыми устройствами: часы реального времени или LCD Display.
Жидкокристаллический дисплей 1602 с I2C модулем подключается к плате Ардуино всего 4 проводами — 2 провода данных и 2 провода питания. Подключение дисплея 1602 проводится стандартно для шины I2C: вывод SDA подключается к порту A4, вывод SCL – к порту A5. Питание LCD дисплея осуществляется от порта +5V на Arduino. Смотрите подробнее схему подключения жк монитора 1602 на фото ниже.
Для занятия нам понадобятся следующие детали:
После подключения LCD монитора к Ардуино через I2C вам потребуется установить библиотеку LiquidCrystal_I2C.h для работы с LCD дисплеем по интерфейсу I2C и библиотека Wire.h (имеется в стандартной программе Arduino IDE). Скачать рабочую библиотеку LiquidCrystal_I2C.h для LCD 1602 с модулем I2C можно на странице Библиотеки для Ардуино на нашем сайте по прямой ссылке с Google Drive.
Приехал Arduino Nano, приехал кит, в котором макетка (бредборд), и LCD-дисплей. На дисплее на плате написано - 1602А, ниже - QAPASS. Начал ваять первое устройство, и конечно же, захотелось выводить информацию на дисплей, а не мигать светодиодами.
Гугл помог, рассказал, что это символьный дисплей; если не извращаться, то доступны скорее всего символы ASCII - цифры, латиница, что-то из базовых символов.
Запустить дисплей помогли следующие материалы: Driving a character type LCD from a PC printer port ; How to connect Arduino with a character LCD ; Pwm Servo Driver Motor Control PDF .
Дисплей достаточно распространенный, и для него уже понапридумывали шилдов - есть варианты с SPI вроде, и/или с I2C, и интернет полон рецептами для этих случаев. Но у меня был в наличии только оригинальный дисплей 16x2, и ардуинка, к которой хотелось его прицепить.
У дисплея есть режим работы и передачи данных полубайтами, по 4 бита, при этом младшие разряды шины не используются. Подключение только половины шины данных много где описано, и я не стал разбираться, как подключить дисплей и работать с ним по 8ми линиям. Меня вполне устроило, что и так работает.
Хорошее описание дисплеев данного типа я нашел тут - http://greathard.ucoz.com/44780_rus.pdf . А тут (http://arduino.ru/forum/programmirovanie/lcd-i2c-partizanit#comment-40748) - пример задания знакогенератора.
Сперва я подключил контакт 15 (A) на +5В, 16 (K) на землю, и убедился, что подсветка работает. Вообще, правильно подключать катод на землю через резистор 220Ом, что я потом и сделал.
Затем подключил землю (1) и питание (2). Arduino может питаться от USB, от стабилизированного напряжения 5В и от нестабилизированного 6-12В, автоматически выбирается наибольшее напряжение. Сейчас ардуинка запитана от USB, и я думал, где там вытащить 5 Вольт. Оказалось, что 5В есть на контакте ардуины, куда подключаются внешние стабилизированные 5В. Вернее, там оказалось 4.7В, но мне хватило.
После подключения питания, если всё хорошо, то верхний ряд загорается сплошными прямоугольниками знакомест.
Затем подключаем потенциометр контраста (пин 3 V0). Один из крайних выводов потенциометра бросаем на землю, второй - на +5В, средний - на пин 3 дисплея. Рекомендуется потенциометр 10К. У меня был 50К из кита, сначала я использовал его. Регулировка была только на одном краю, весьма тонко приходилось ловить нужный контраст. Затем в другом ките нашел аналогичный на 5К, и поставил его. Настройка растянулась от одного края до половины оборота. Видимо, можно и еще меньше взять потенциометр. 10К наверно рекомендуют, чтобы схема поменьше потребляла. Да, пришлось немного попаять, припаял к выводам потенциометров проводки с дюпонами.
В принципе, в этом скетче есть и описание, что куда подключать. Можно подключить, как там указано, тогда менять вообще ничего не нужно.
// include the library code:
#include
Получается что-то вроде этого:
Кстати, дисплей, который попал ко мне в руки, без подсветки не работает. В смысле, работает, но практически ничего не видно.
# контакта | Наименование | Как подключать |
---|---|---|
1 | VSS | GND |
2 | VDD | +5V |
3 | V0 | Контраст - на средний вывод потенциометра |
4 | RS (Register select) | D7 Arduino |
5 | R/W (Read or write) | GND |
6 | E (Enable signal) | D6 Arduino |
7-14 | D0-D7 | D0-D3 - не подключены; D4-D7 - подключены к контактам D5-D2 Ардуино |
15 | A | Анод подсветки, подключается к +5В |
16 | K | Катод подсветки, подключается к земле через резистор 220Ом |
За все время увлечения электроникой мне довелось пользоваться ЖКД от нескольких производителей - DataVision, WINSTAR, Uniworld Technology Corp
. Они отличались типом контроллера, количеством выводов и длинною строк, но при этом все имели одинаковую схему подключения, систему команд и обслуживались одной и той же программой со стороны микроконтроллера. Поэтому, хотя речь сейчас пойдет о дисплее WH0802A фирмы WINSTAR
, все ниже сказанное применимо к символьным ЖК-дисплеям и других фирм.
У некоторых дисплеев есть два дополнительных вывода – выводы подсветки +LED и –LED. Причем если выводы есть – это еще не означает что есть и подсветка. Как и наоборот. У моего дисплея подсветка есть, а выводов управления нет.
По умолчанию подсветка у дисплея WH0802A-YGH-CT отключена. Чтобы ее включить, нужно проделать парочку нехитрых манипуляций, а именно – установить две перемычки и впаять токоограничительный резистор (смотри на фотке RK, JF и RA соответственно).
Это типовая схема включения символьных LCD. Схему управления подсветкой дисплея мы задействовать не будем, но я ее на всякий случай нарисовал.
Подав питание на схему, нужно покрутить регулятор контраста (резистор R1). Если на экранчике появилась верхняя строка, значит, он живой и самое время приступать к написанию кода. На начальном этапе мы будем использовать 8-ми разрядную шину. Чтобы получить первые результаты, нам понадобится написать две функции – функцию записи данных и функцию записи команд. Отличаются они всего одной строчкой – когда записываются данные, сигнал RS должен быть 1, когда записывается команда, RS должен быть 0. Функции чтения мы пока использовать не будем, поэтому сигнал R/W будет всегда 0.
Цикл записи для 8-ми разрядной шины выглядит следующим образом:
1. Установить RS (0 - команда, 1 – данные)
2. Вывести значение байта данных на шину DB7…DB0
3. Установить E=1
4. Программная задержка 1
5. Установить E=0
6. Программная задержка 2
Контроллер символьного ЖК-дисплея, не обладает бесконечным быстродействием, поэтому между некоторыми операциями используются программные задержки. Первая нужна для удержания на некоторое время строб сигнала, вторая, для того чтобы контроллер успел записать данные или выполнить команду. Величины задержек всегда приводятся в описании на контроллер дисплея и нужно всегда выдерживать хотя бы их минимальное значение, в противном случае неизбежны сбои в работе контроллера.
Вообще у контроллера дисплея есть так называемый флаг занятости – BF. Если флаг в 1 – контроллер занят, если в 0 – свободен. Вместо второй программной задержки можно читать флаг занятости и проверять, когда контроллер дисплея освободится. Но поскольку мы хотим быстро получить первые результаты, с флагом занятости будем разбираться потом.
//порт к которому подключена шина данных ЖКД
#define
PORT_DATA PORTD
#define
PIN_DATA PIND
#define
DDRX_DATA DDRD
//порт к которому подключены управляющие выводы
#define
PORT_SIG PORTB
#define
PIN_SIG PINB
#define
DDRX_SIG DDRB
//номера выводов микроконтроллера
//к которым подключены управляющие выводы ЖКД
#define
RS 5
#define
RW 6
#define
EN 7
//макросы для работы с битами
#define
ClearBit(reg, bit) reg &= (~(1<<(bit)))
#define
SetBit(reg, bit) reg |= (1<<(bit))
#define
F_CPU 8000000
#define
_delay_us(us) __delay_cycles
((F_CPU / 1000000) * (us));
#define
_delay_ms(ms) __delay_cycles
((F_CPU / 1000) * (ms));
//функция записи команды
void
LcdWriteCom(unsigned char
data)
{
ClearBit(PORT_SIG, RS); // устанавливаем RS в 0
PORT_DATA = data; // выводим данные на шину
SetBit(PORT_SIG, EN); // устанавливаем Е в 1
_delay_us
(2);
ClearBit(PORT_SIG, EN); // устанавливаем Е в 0
_delay_us(40);
//функция записи данных
ClearBit(PORT_SIG, EN); // устанавливаем Е в 0
Delay_us(40);
}
int
main(void
)
{
while
(1);
return
0;
}
Здесь нет сложных мест, все должно быть понятно. Идем дальше.
Любой ЖК-дисплей перед использованием нужно инициализировать. Процесс инициализации обычно описан в datasheet`е на контроллер дисплея. Но даже если там и нет информации, последовательность, скорее всего, будет такая.
1. Подаем питание2. Ждем >40 мс
3. Подаем команду Function set
DL
– бит установки разрядности шины
0 – 4 разрядная шина, 1 – 8 разрядная шина
N
– бит установки количества строк дисплея
0 – однострочный режим, 1 – двухстрочный режим
F
– бит установки шрифта
0 – формат 5*8, 1 – формат 5*11
* - не важно что будет в этих битах
4. Подаем команду Display ON/OFF
D
– бит включения/выключения дисплея
0 – дисплей выключен, 1 – дисплей включен
C
– бит включения/выключения курсора
0 – курсор выключен, 1 – курсор включен
B
– бит включения мерцания
0 – мерцающий курсор включен, 1 – мерцающий курсор выключен
5. Подаем команду Clear Display
6. Ждем > 1,5 ms
7. Подаем команду Entry Mode Set
I/D
– порядок увеличения/уменьшения адреса DDRAM(ОЗУ данных дисплея)
0 – курсор движется влево, адрес уменьшается на 1, 1 – курсор движется вправо, адрес увеличивается на 1
SH
– порядок сдвига всего дисплея
0 – сдвига нет, 1 – сдвиг происходит согласно сигналу I/D – если он 0 – дисплей сдвигается вправо, 1 – дисплей сдвигается влево
Для нашего примера функция инициализации будет выглядеть так