Простой pov дисплей на базе arduino

Arduino controlled POV Display

So, I’ve graduated. I am single. I have nothing else to do at home except eat, sleep, watch movies and check facebook. Then I come up across this awesome blog by Carlos Asmat which has a lot of interesting stuff.

There I find a simple project based on using Persistence of Vision (POV) to create a display (2D) using an LED strip (1D). So I decide ‘Lets do it’ and what goes below is my first attempt at replicating that display.

It is still very crude and requires polishing, but well its a start.

Here is a list of parts that went into the making of it:

  1. Arduino Uno (or any Arduino for that matter, as long as it has 11 or more digital I/O pins)
  2. CPU Fan (You can find it in any electronics store). The one I have is rated 12V/0.25 mA.
  3. 9V Batteries
  4. LED’s (whichever color suits).
  5. Connectors
  6. IR Transmitter (I used TSUS4400 from Vishay. You can find it on element 14 here.)
  7. IR Receiver  (I used TEFT4300 from Vishay. You can find it here)
  8. 220E resistors (for LED’s and IR Transmitter)
  9. 1K8 resistor for IR Receiver
  10. 7805 voltage regulator (for giving 5V continuously to IR transmitter. Not needed if you have a 5V or 3.3V battery)
  11. Bergsticks
  12. Some kind of glue (I used Fevistick)

Construction:

Well, you can refer this page and construct the platform. Its very easy and you dont really need any expertise. Also, not to mention, I am pretty lazy to get into each and every detail.

Working:

Again, this is very well documented by Carlos Asmat on his page. He clearly explains using the working a 1D LED strip for 2D display patterns. The basis behind my model is the same, although I’ve made two major software changes:

  1. With Carlos’ version, you need to use an additional variable ‘timer3’ which can be adjusted to get a stable display. I started out with this but soon realized that it was tough to modify the value of that variable because it’s all trial-and-error. Even if you luckily get a value of timer3 for which the text, say “KARAN”, is visibly stable, you will still need to change its value if you change the number of alphabets in a text, or the delay between different columns, or the delay between different frames. This is because you want the letters ‘K’, ‘A’, ‘R’, ‘A’, ‘N’ to be displayed at the same position to make the text look stable. This is not possible if the parameter’s I mentioned are changed. So I, after surfing around, found a strategy which used an IR Transmitter Receiver pair to mark the ‘home’ location.The blue colored component is the IR Transmitter. It is constantly powered using 5V supply. The (black colored) IR Receiver is powered from the Arduino and its value is checked after one drawing (“KARAN”) is displayed. Once it is triggered by the transmitter, then the arduino again displays the drawing. As a result, the drawing is stable. As long as the speed of rotation is sufficiently fast, you should clearly see the text without any impairment.
  2. Another change is that I have not used a data array for an entire drawing. Instead I have defined bitmap patterns for various alphabets and symbols and used a function show()which displays each frame/alphabet/symbol. This makes the use more flexible.You can find my arduino code for the display here.

Explanation of the code:

The LED’s which are used for displaying the text are connected from pin 2 to pin 9. There are additionally two LED’s connected to pins 12 & 13. They are used as borders for the text and are optional. You can choose to forget about them.

The IR Receiver is powered from pin 11 of the Arduino. Its output is taken from pin 10.

The  bitmap pattern for alphabets and some symbols are  passed to the show() function which systematically displays each column of the text bitmap pattern. You can choose timer1, timer2 values as and how it suits you. I have used the ones which worked perfect for me. The frame length can also be changed. However I preferred to deal with a 8 x 8 square matrix which was easy.

You might think why have I called the functions in a reverse order, i.e. show(N) then show(A), then show(R), then show(A), then show(K). This is because my fan was rotating in the anti-clockwise direction. You can imagine the logic for a second here.

In the end there is a loop

while(digitalRead(10) != 1) { }

which stops the display until the ‘home’ location is read by the IR Receiver.

The rest of the code is pretty straightforward.

Here are some pictures of my assembly:

This slideshow requires JavaScript.

Drawback: A big drawback of this is that the CPU fan that I have used is not capable of bearing the load of the rotating arm (LED strip + Arduino + Battery) which results in a drastic reduction in the speed of the fan (which normally is 3800 rpm).

This tend to distort the text that I am trying to display. This is a reason why I havent included a video of the working model. So currently I am looking for something fast with moderate torque. Once I have it, I’ll post a video which demonstrates the working model. This is the video.

I must warn you that it is very very premature but just to show that it works, here it is:

Well, thats the end of it. You can do-it-yourself. Its pretty easy. Took me only 2 days to get it going and that too because I was very lazy. You can probably do it in 14-16 hours, if you can go on for that stretch of a time. If there are any doubts you have about the explanation, code or anything, please leave a comment and I’ll try to see that it gets resolved to the best of my ability.

Peace out m/

Источник: https://karanjthakkar.wordpress.com/2012/06/11/arduino-controlled-pov-display/

Arduino / Механический дисплей на Arduino — работа над ошибками

Механический дисплей из лего и Arduino, о котором я писал в начале января оказался, по-моему, довольно неплох для конструкции собранной за вечер. Однако в комментариях справедливо указали на возможности его улучшения. Заодно, читая отзывы, я узнал что такое «POV», спасибо всем откликнувшимся! Выявленные недостатки

Малый размер «экрана», недостаточный для написания слова «Хабрахабр»

Монохромность

Неравномерность шага пикселей, расчитанного простым делением времени цикла на разрешение

Разочарование ожидавших увидеть видео хаброюзеров

Необходимость вручную побитово кодировать изображение каждой буквы

Общая нестабильность конструкции — «дисплей» при работе сильно раскачивается

Холостой обратный ход планки со светодиодами. Они подсвечиваются только во время движения справа налево

За прошедшие четыре недели конструкцию удалось доработать, и вот что получилось в результате:
Работа над ошибками

Стабильность и размер

Улучшить механическую стабильность оказалось проще всего — у ребёнка были позаимствованы кубики Duplo (lego двойного размера совместимое со стандартным), и из них собрана прочная и тяжёлая платформа.

После этого удлинил кривошип и нарастил качающуюся планку со светодиодами, тем самым увеличив горизонтальное разрешение. Сперва думал поставить более мощный мотор, но хватило замены батареек на стабилизированный блок питания и небольшого повышения напряжения.

При 10,3 вольт моя конструкция делает ровно 6 полных колебаний в секунду. На переднем плане видны две оптические пары — теперь можно ловить и начало обратного хода.

Цвет

Сделать дисплей цветным казалось лёгкой задачей — достаточно заменить одноцветные светодиоды на RGB. Сказано — сделано. Общие аноды через ограничительные резисторы соединил с шиной данных, а катоды спаял вместе поцветно и подсоединил к выходам Arduino, ответственным за выбор цвета.

Когда горят все восемь светодиодов, по каждому проводу выбора цвета стекает до 39 миллиампер, при том что Arduino может максимум 40. Для гарантии добавил три MOSFET транзистора IRF 540 — по одному на каждый цвет. Получилось примерно такая схема (показаны лишь три RGB светодиода): Качающаяся планка соединяется с контроллером 8+3 тонкими проводами.

Немало, но если их аккуратно проложить, то движению они не мешают.

Грабли номер один

Подаём логическую единицу на нужный анод (D6-D13), единицей-же открываем ответственный за цвет транзистор(D0-D2) и светодиод зажигается. Если на управляющие цветом выходы подать 001, то загорается красный, 010 — зелёный, 011… снова красный, хотя ожидался жёлтый.

Чтение даташита показало, что красный светодиод зажигается при напряжении в 2,0 Вольта, тогда как зелёному и синему нужны 3,2. В результате после открытия красного диода напряжение практически не растёт, только увеличивается ток, и зелёный с синим не открываются. Решения проблемы для приведёной схемы подключения с ограничивающими ток резисторами в цепи анода я так и не нашёл.

Если подключить резисторы к катодам, то на каждом диоде будет падать своё, нужное ему напряжение, но резисторов понадобится 24 штуки, что для моей подвижной конструкции слишком тяжело. Гугль нашёл несколько микросхем драйверов матриц светодиодов, но у меня в хозяйстве их не было. В результате обошёл проблему программно, быстро зажигая цвета по очереди.

При задержке в 50 микросекунд на цвет, за время показа одного пикселя элементарные цвета успевают смениться много раз и сливаются в один.

Грабли номер два

В неподвижном положении устройство теперь показывает ожидаемые цвета, пора опробовать его в движении.

Запускаю мотор, и обнаруживаю следующую проблему: В RGB cветодиоде красный и синий элементы находятся на противоположных сторонах корпуса, и в результате вместо сиреневого цвета получаем две хорошо различимые отдельные полоски — красную и синюю.

На стыке красной и зелёной областей тоже хорошо видна разница в расположении светоизлучающих точек. Эту проблему удалось полностью решить заменой прозрачных светодиодов на матовые.

Механическая развёртка

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

Мотор неидеален и скорость вращения зависит от нагрузки. Гибкий пластик и люфты в соедиениях окончательно запутывают картину. Учебник по теоретической механике я в последний раз открывал лет пятнадцать назад, так что даже не пытался рассчитать динамику движения моего дисплея, и сразу решил измерять как он ведёт себя в реальности.

Это оказалось не так уж трудно: впереди поставил маску с равномерно расположенными отверстиями, направил на неё свет яркой лампы, а на конце планки закрепил фоторезистор. Осталось написать несложную программу, которая сперва делает несколько холостых циклов и усредняет для точности их период, а потом собирает через АЦП данные об освещённости фотодиода.

Каждое измерение сопровождается вызовом функции micros, выдающей количество прошедших микросекунд. Массив с данными по последовательному порту перекачал в компьютер и проанализировал в Экселе.

Вот как выглядит напряжение на фоторезисторе — отлично видно когда на него попадал свет сквозь отверстия в маске: А вот нелинейность во всей своей красе, хорошо что не стал пытаться это смоделировать и рассчитать: Эксель умеет аппроксимировать произвольные наборы данных полиномами до пятого порядка, так что через несколько минут в моих руках была заветная формула описывающая движение: Здесь y это задержка в микросекундах от начала цикла, x — номер виртуального пикселя меняющийся от 1 до 20 (у меня в калибровочной маске было 20 отверстий). Давая x дробные значения, можно расчитать задержки для произвольного разрешения. Я остановился на 54 пикселях.

Пиксели

Для проверки формулы написал простенькую программку, выводящую попеременно 0x55 и 0xAA для подсвечивания пикселей в шахматном порядке. Экселевская математика не подвела, и к равномерности шага растра претензий нет, но вот сами пиксели получились вместо прямоугольных овальными.

Не удивительно, ведь формула рассчитывает задержки для центра идеального пикселя, а реальный светодиод имеет 5 мм в диаметре, и засвечивает прилегающие области.

Прямоугольные пиксели проще рисовать прямоугольными светодиодами, чего я и добился, наклеив по бокам непрозрачный скотч: Контрольная «шахматная доска» подтвердила, что так действительно намного лучше:

Программирование

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

Я предполагал, что объявленные как const массивы хранятся в Flash-памяти, однако выяснилось, что это не так. Точнее говоря, они сперва лежат действительно в постоянной памяти, но при запуске копируются в RAM, хотя их и нельзя изменять. Чтобы этого избежать, переменные нужно объявлять через PROGMEM, про это нашлась статья на сайте ардуино. В общем «читайте маны, они рулез».

Руссификация

Рисовать буквы по-точкам неудобно, так что положил в тот же PROGMEM таблицу знакогенератора и написал функцию отрисовки букв. С английскими символами никаких проблем, а вот вместо русских выводилась белиберда. В качестве среды разработки использовался VisualStudio 2010 с плагином Visaul Micro Arduino.

Несмотря на то, что файлы исходников сохранялись в кодировке Win1251 (один байт на символ), строка видаchar* text = “ХАБРАХАБР”; объявляла массив длиной 27+1 байт, в котором каждая тройка имела одинаковое содержание, к исходному тексту никакого отношения не имеющее.

Тот же код из-под среды Arduino UNO пишет по два байта на русский символ, скорей всего в UTF8.

Проблему удалось обойти, закодировав строку посимвольно:char russianText[] = {'Х', 'А', 'Б', 'Р', 'А', 'Х', 'А', 'Б', 'Р', ''}; Теперь, как и ожидалось, получаем 9 байт текста плюс ещё один на завершающий ноль.

Запускаем программу и видим… совсем другие символы. Исследование показало, что большая русская буква «А» компилируется в код 144, что никак не соответсвует ожидаемому для Win1251 коду 192. Не поленился и почитал в Интернете про возможные кодировки русских букв, в том числе и весьма экзотические.

Ни в одной из них А не транслируется в 144. Единственное приходящее в голову объяснение, это представление русских букв в юникоде, после чего из буквы А (U+0410) вырезается младший байт, к которому почему-то добавляется 128. Почему так — непонятно, но после добавления к коду букв нужной константы, они встали на свои места. Вот что получилось в итоге:

Видео

А как же без него? При длительности цикла в 170 миллисекунд получается почти точно шесть кадров в секунду. У камеры же — 30 кадров в секунду, и из-за кратности частот на видео заметно сильное мерцание. Если смотреть глазами, то картинка выглядит намного стабильней.

Что дальше?

Вывод изображения при обратном ходе развёртки пока не запрограммировал. Это позволило бы удвоить частоту кадров, но усложнило бы программирование анимации и прокрутки текста. При рисовании только во время прямого хода у микроконтроллера есть целых 80 миллисекунд, чтобы неторопливо рассчитать следующий кадр.

Источник: http://www.pvsm.ru/diy/1379

Пишем в воздухе светодиодами | Аппаратная платформа Arduino

Чт, 17/02/2011 – 03:52 | by Alexander

Все, наверное, знают об эффекте возникающей надписи или рисунка при быстром перемещении планки, иногда диска с полосой светодиодов, которые загораются специально синхронизированным образом. Эффект называется персистенция.

Сам эффект основан на инерции человеческого глаза.

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

В конструкции, о которой пойдет речь, автором был использован акселерометр на монтажной плате с планкой светодиодов и Arduino Diecimila для управления. Питание осуществляется по USB, но можно подключить и автономное.

Сборка

Монтаж был произведен на макетной плате. Были смонтированы планка светодиодов, прямые коннекторы для подключения к плате Ардуино и краевой коннектор для акселерометра. Плата подключается к Arduino как стандартная плата расширения.

Маленькая зеленая плата – трехосевой акселерометр, с которого снимается значение через аналоговые входы Arduino.  В зависимости от ускорения акселерометр меняет напряжение на своих выходах.

 Код

0x00,0x00,0x00,0x00,0x00,
0x00,0xF6,0xF6,0x00,0x00,
0x00,0xE0,0x00,0xE0,0x00,
0x28,0xFE,0x28,0xFE,0x28,
0x00,0x64,0xD6,0x54,0x08,
0xC2,0xCC,0x10,0x26,0xC6,
0x4C,0xB2,0x92,0x6C,0x0A,
0x00,0x00,0xE0,0x00,0x00,
0x00,0x38,0x44,0x82,0x00,
0x00,0x82,0x44,0x38,0x00,
0x88,0x50,0xF8,0x50,0x88,
0x08,0x08,0x3E,0x08,0x08,
0x00,0x00,0x05,0x06,0x00,
0x08,0x08,0x08,0x08,0x08,
0x00,0x00,0x06,0x06,0x00,
0x02,0x0C,0x10,0x60,0x80,
0x7C,0x8A,0x92,0xA2,0x7C,
0x00,0x42,0xFE,0x02,0x00,
0x42,0x86,0x8A,0x92,0x62,
0x44,0x82,0x92,0x92,0x6C,
0x10,0x30,0x50,0xFE,0x10,
0xE4,0xA2,0xA2,0xA2,0x9C,
0x3C,0x52,0x92,0x92,0x0C,
0x80,0x86,0x98,0xE0,0x80,
0x6C,0x92,0x92,0x92,0x6C,
0x60,0x92,0x92,0x94,0x78,
0x00,0x00,0x36,0x36,0x00,
0x00,0x00,0x35,0x36,0x00,
0x10,0x28,0x44,0x82,0x00,
0x28,0x28,0x28,0x28,0x28,
0x00,0x82,0x44,0x28,0x10,
0x40,0x80,0x8A,0x90,0x60,
0x7C,0x82,0xBA,0xBA,0x62,
0x3E,0x48,0x88,0x48,0x3E,
0xFE,0x92,0x92,0x92,0x6C,
0x7C,0x82,0x82,0x82,0x44,
0xFE,0x82,0x82,0x82,0x7C,
0xFE,0x92,0x92,0x92,0x82,
0xFE,0x90,0x90,0x90,0x80,
0x7C,0x82,0x82,0x8A,0x4E,
0xFE,0x10,0x10,0x10,0xFE,
0x82,0x82,0xFE,0x82,0x82,
0x84,0x82,0xFC,0x80,0x80,
0xFE,0x10,0x28,0x44,0x82,
0xFE,0x02,0x02,0x02,0x02,
0xFE,0x40,0x20,0x40,0xFE,
0xFE,0x60,0x10,0x0C,0xFE,
0x7C,0x82,0x82,0x82,0x7C,
0xFE,0x90,0x90,0x90,0x60,
0x7C,0x82,0x82,0x86,0x7E,
0xFE,0x90,0x98,0x94,0x62,
0x64,0x92,0x92,0x92,0x4C,
0x80,0x80,0xFE,0x80,0x80,
0xFC,0x02,0x02,0x02,0xFC,
0xF8,0x04,0x02,0x04,0xF8,
0xFC,0x02,0x0C,0x02,0xFC,
0xC6,0x28,0x10,0x28,0xC6,
0xC0,0x20,0x1E,0x20,0xC0,
0x86,0x8A,0x92,0xA2,0xC2,
0x00,0x00,0xFE,0x82,0x00,
0x00,0x00,0x00,0x00,0x00,
0x80,0x60,0x10,0x0C,0x02,
0x20,0x40,0x80,0x40,0x20,
0x01,0x01,0x01,0x01,0x01,
0x80,0x40,0x20,0x00,0x00,
0x04,0x2A,0x2A,0x2A,0x1E,
0xFE,0x12,0x22,0x22,0x1C,
0x1C,0x22,0x22,0x22,0x14,
0x1C,0x22,0x22,0x12,0xFE,
0x1C,0x2A,0x2A,0x2A,0x18,
0x10,0x7E,0x90,0x80,0x40,
0x18,0x25,0x25,0x25,0x1E,
0xFE,0x10,0x10,0x10,0x0E,
0x00,0x12,0x5E,0x02,0x00,
0x02,0x01,0x01,0x11,0x5E,
0xFE,0x08,0x08,0x14,0x22,
0x00,0x82,0xFE,0x02,0x00,
0x3E,0x20,0x1C,0x20,0x1E,
0x3E,0x20,0x20,0x20,0x1E,
0x1C,0x22,0x22,0x22,0x1C,
0x3F,0x24,0x24,0x24,0x18,
0x18,0x24,0x24,0x3F,0x01,
0x3E,0x10,0x20,0x20,0x10,
0x12,0x2A,0x2A,0x2A,0x04,
0x00,0x10,0x3C,0x12,0x04,
0x3C,0x02,0x02,0x02,0x3E,
0x30,0x0C,0x02,0x0C,0x30,
0x38,0x06,0x18,0x06,0x38,
0x22,0x14,0x08,0x14,0x22,
0x38,0x05,0x05,0x05,0x3E,
0x22,0x26,0x2A,0x32,0x22,
0x00,0x10,0x6C,0x82,0x82,
0x04,0x02,0xFF,0x02,0x04,
0x82,0x82,0x6C,0x10,0x00,
    for (int temp = i; temp < i + 5; temp++ ) {
        PORTD = text_array[temp]; delayMicroseconds(500);
    digitalWrite(SLEEP,HIGH);

Теперь осталось подключить сборку к компьютеру и размахивать ею.

Оригинал описания (англ.) – http://forums.adafruit.com/viewtopic.php?t=6446

Источник: http://rfanat.ru/Arduino_projekts/POV_display_by_Arduino.html

Подключаем LCD дисплей к плате Arduino своими руками

Доброго времени суток. В сегодняшней статье речь пойдёт об LCD дисплеях. Вернее об одном конкретном дисплее — LCD 1602A на базе контроллера HD44780. Почему именно данный экземпляр? Если не вдаваться в подробности: он простой и относительно дешёвый.

При изготовлении различных самоделок, что представлены на МозгоЧинах, использовались подобные/аналогичные дисплеи. Однако подробного пояснения того, как подключать его к плате Arduino и выводить информацию, к сожалению, не было. Постараемся это исправить.

Подобного рода дисплеи бывают двух видов:

  • С чёрными буквами и желтой подсветкой;
  • С белыми буквами и синей подсветкой.

Что же касается размерности таких дисплеев, она может быть разной, но при этом стоит учесть – управляются они одинаково. Например, в продаже можно встретить дисплеи с размерностями 16×02 и 20×04. Разрешение символов составляет 5×8 точек.

Стоит отметить следующее: кириллицу поддерживают только дисплеи с маркировкой CTK.

Дисплей имеет 16 выводов (пинов) для подключения к плате. Распиновка следующая:

  • 1 «GND» (VSS) – «земля» минус питание;
  • 2 «Vcc» (VDD) — питание (+5В);
  • 3 «VEE» (VO) —  управления контрастом;
  • 4 «RS» — выбор регистра;
  • 5 «R/W» — Чтение/запись ( режим записи при соединении с землей);
  • 6 «EN» (E) – синхронизация;

Шина данных:

  • 7-10 «DB0-DB3» — Младшие биты 8-битного интерфейса;
  • 11-14 «DB4-DB7» — Старшие биты интерфейса;
  • 15 «А» — Анод (+5В) питания подсветки;
  • 16 «K» — Катод (земля) питания подсветки.

Прежде чем подключать дисплей к плате контроллера нужно произвести тестовый запуск и убедится в работоспособности периферии. Чтобы выполнить это подадим напряжение на контроллер (VSS и VDD), запитаем подсветку (A и K) и настроим контрастность.

Контрастность регулируется 10 кОм потенциометром. На крайние выводы подводим +5V и GND, центральный вывод соединяем с выводом VO.

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

Для того, чтобы вывести информацию на экран дисплея воспользуемся стандартным библиотечным файлом LiquidCrystal.h.

Существует два режима работы дисплея:

  • 8-битный режим —  используются младшие и старшие биты (BB0- DB7);
  • 4-битный режим —  используются только старшие биты (BB4- DB7).

Будем использовать 4-битный режим.

Для отображения информации подключаем выводы RS, E, DB4, DB5, DB6, DB7 к выводам платы Ардуино (выводы на плате могут быть любые, критически важно задать в коде программы верную последовательность).

Распиновка выводов дисплея и платы Ардуино:

  • 1 – GND
  • 2 – +5V
  • 4 – 7
  • 6 – 6
  • 11 – 5
  • 12 – 4
  • 13 – 3
  • 14 – 2
  • 15 – +5V
  • 16 – GND

Загружаем прошивку на плату Ардуино Уно и смотрим на результат.

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

Ниже описаны дополнительные функции по работе с дисплеем.

  • home() возвращает курсор на начала экрана;
  • clear() возвращает курсор на начала экрана и стирает всё, что было на дисплее;
  • write(ch) выводит единичный символ ch на дисплей;
  • cursor() включает отображение курсора на дисплее (символ подчёркивания);
  • noCursor() выключает отображение курсора на дисплее;
  • blink() включает мигание курсора, если включено его отображение;
  • noBlink() выключить мигание курсора, если включено его отображение;
  • display() включает дисплей;
  • noDisplay() выключает дисплей;
  • scrollDisplayLeft() прокрутка экрана на один символ влево;
  • scrollDisplayRight() прокрутка экрана на один символ вправо;
  • autoscroll() включает режим автопрокрутки;
  • noAutoscroll() выключает режим автопрокрутки;
  • leftToRight() выбор направления вывода текста (слева направо);
  • rightToLeft() справа налево;
  • createChar(ch, bitmap) позволяет создать пользовательский символ с кодом ch (от 0 до 7), используя массив битовых масок bitmap для задания тёмных и светлых точек.

Спасибо за внимание. Продолжение следует.

LCDExample

LCD 1602A

Источник: http://mozgochiny.ru/electronics-2/podklyuchaem-lcd-displey-k-plate-arduino-svoimi-rukami/

Простейший барометрический высотомер на базе Arduino

Приветствую коллеги!Т.к. зимой погода в основном не летная, то есть много свободного времени, которое не плохо бы чем-то занимать, чтобы мозги не засыхали от безделья. Я с недавних пор решил освоить предмет лютых холиваров и жарких споров, а именно: микроконтроллер Atmega328 в реализации Arduino.

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

Подробнее?Сразу скажу, на оригинальность и новаторство не претендую, подобных проектов в сети навалом. Но на этом ресурсе ничего подобного поиском не обнаружил, потому и решил опубликовать, вдруг кому-то пригодится.Код опять же писал сам, потому, если там сплошная индусятина – не судите строго =) Я пока только учусь.

Последний раз контроллеры программировал на 4-м курсе института больше 10 лет назад =) Грамотная и конструктивная критика приветствуется!Постараюсь доступно и подробно объяснить как собрать такое устройство, справится человек с почти любым уровнем подготовки, я думаю.Основной плюс данного девайса – его цена.

Даже по теперешней жизни и курсе валют можно уложиться в 350р., что в общем-то не деньги. Так же потребуются прямые руки и умение обращаться с паяльником.

Функции устройства:

– Измерение текущей высоты и вывод ее на светодиодный дисплей.- Запоминание максимального значения высоты имевшей место с момента включения питания.- Вывод максимальной высоты на дисплей посредством нажатия кнопки.- Запись максимального значения высоты в энергонезависимую память (EEPROM) контроллера (сохраняется после отключения питания).- Чтение сохраненной максимальной высоты из EEPROM и вывод ее на дисплей.За нулевую точку отсчета принимается высота на которой было включено питание устройства.

Что понадобится (в скобках ключевые слова для поиска на всяких там ебаях и т.п.)

– микроконтроллер ардуино, в принципе подойдет почти любой, если код даптировать, но собиралось и проверялось все на базе (Arduino Nano).- барометрический датчик высоты с шиной I2C (BMP085).- трехразрядный семисегментный светодиодный дисплей с общим анодом (7-Segment LED Display).

– провода для соединения всего этого в единое целое, я использовал готовые и с разъемами, но это совсем не обязательно (Dupont Wire).

– кнопка, подойдет любая без фиксации положения (Tact Switch Push Button). Например такая:

– резистор от 1КОм до 10КОм.

– три резистора 100Ом.- паяльник со всеми гобулями и умение им пользоваться.

– Arduino Software.

Опционально:- макетная плата для распайки дисплея.

Для тех кто совсем не в теме. Прежде чем пытаться собрать девайс и вникнуть в код настоятельно рекомендую посетить и почитать несколько ресурсов:

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

Сначала немного о дисплее.
Семисегментный светодиодный дисплей с общим анодом представляет из себя вот такую сборку из светодиодов (на картинке обведено красным):

Если повнимательней посмотреть на схему, то станет понятно, что одновременно может светиться только один из разрядов, т.е. чтобы отобразить трехразрядное число, нужно по очереди зажигать и гасить каждый разряд, причем делать это очень быстро. Поэтому цифры как ни крути будут мерцать, главное, чтобы это мерцание было достаточно частым и не воспринималось глазом как мерцание. А это значит, что ардуино будет работать в том числе и в качестве контроллера этого дисплея, по сути рисуя по очереди цифры составляющие число равное текущей высоте. Сразу оговорюсь, можно купить и готовое решение, со встроенным контроллером, но стоит оно в 5 раз дороже, да и мне не попалось подходящей реализации при поиске, т.к. хотелось именно 3 разрядный, а в продаже все больше 4-х разрядные.Кстати, учитывая что дисплей трехразрядный, максимальная высота, которую он в состоянии отобразить = 999м. В принципе устройство может быть легко адаптировано для 4-х разрядного дисплея, но программу при этом придется немного модифицировать. Кто разберется в коде для 3-х разрядов, тот легко сможет его адаптировать и для 4-х.В итоге не смотря на всплывшие проблемы с этим самым мерцанием, удалось добиться более-менее приемлимых результатов, об этом ниже, т.к. проблемы возникли из-за датчика высоты.

Подробней о датчике.

Датчик барометрический, т.е. определяет изменение высоты по изменению атмосферного давления. Фактически датчик измеряет только атмосферное давление, вычислением высоты как функции от давления занимается уже код библиотеки для датчика. При этом датчик имеет встроенный АЦП и интерфейс I2C, т.е. выдает измеренную величину уже в цифровом виде, что несомненно является плюсом. Для работы с датчиком существует готовая библиотка. Я использовал именно первую версию, она менее ресурсоемка и проще встраивается в код. Функционал библиотеки позволяет настраивать точность измерений по шкале от 0 – наименьшая точность, до 3 – наибольшая точность (см. код). Хотя если честно я не заметил особенной разницы между уровнями выше 0. Погрешность измерений составляет около 1 метра, что в общем-то вполне приемлимо. Результат измерений – это абсолютная высота над уровнем моря при нормальном атмосферном давлении. Но это как раз совсем неинтересно. С другой стороны при помощи ардуино и простейших математических операций легко можно вычислить относительную высоту, что и было проделано.Но не обошлось и без ложки дегтя: опрос датчика при помощи стандартной функции происходит достаточно длительное время, а учитывая, что ардуино еще и контроллер семисегментного дисплея, получились достаточно забавные спецэффекты, т.е. во время опроса датчика вывод на дисплей само собой останавливался и поэтому цифра, которая отображалась на тот момент горела чуть дольше других. В итоге получалась такая типа гирлянда из трех элементов.

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

В принципе будь у меня скилл покруче, можно было бы переписать библиотеку датчика, но пока не готов. Да и в такой реализации функции свои вполне выполняет, остальное лирика.
Вывод цифр был переведен на прерывание, мерцание ликвидировано, скетч обновлен.На этом краткий экскурс по элементам устройства пожалуй закончу и перейду к сборке.

Схема соединения элементов устройства (кликабельно):

Предвосхищая вопросы из серии “что, нормальную схему не мог нарисовать?!” скажу, что мог бы, но для непосвященных такой ваиант мне думается будет проще для восприятия, а посвященным все равно, и так читается схема нормально. Распиновку семисегментника нашел только для четырехразрядной версии, трехразрядная версия отличается банально отсутствием 6-й ноги.

Что касется питания устройства: ардуино в первозданном виде способен нормально пережить от 7В до 16В, в крайнем случае от 6В до 20В. Но, учитывая, что у меня был китайский клон, гнусных опытов я ставить не стал, но от батареи LiPo 3S работает без проблем.

Датчик желательно упаковать таким образом, чтобы доступ воздуха был свободный, но при этом исключить прямой обдув потоками воздуха отверстия в датчике, например, прикрыть его пороллоном.С платы ардуино рекомендую удалить светодиоды RX и TX, т.к. они включены параллелльно 0 и 1 цифровым выводам, из-за чего сегменты подключенные к этим выводам будут светиться с меньшей яркостью.

Код для Aduino IDE:
(Altimeter_v1.01.ino)
Комментирован очень подробно, но если все же возникнут вопросы – не стесняйтесь.

Об интерфейсе:

Ну и что, что весь интерфейс – одна кнопка и три символа?! Описать все равно надо =)При нажатии и удержании кнопки на дисплей выводится максимальная высота, зафиксированная с момента включения питания.Если продолжить удерживать кнопку в течении 2 секунд на дисплей будет выведено значение высоты записанное в EEPROM.

Если продолжить удерживать кнопку в течении 4 секунд, в EEPROM будет записана текущая максимальная высота и на дисплее загорится буква “S”, которая на самом деле цифра “5” =)Дальше кнопку держать смысла нет, можно отпускать.

Отрицательная высота не выводится, т.к. знак минус рисовать некуда, поэтому в таком случае на дисплей выводятся три буквы “L”.
Скетч обновлен.

Отрицательная высота выводится на первые два разряда, т.е. минимальное значение -99.

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

Еще один нюанс: запись в EEPROM происходит побайтно, то есть в одну ячейку можно записать число не больше 255. С одной стороны можно было реализовать разбиение на байты, писать побайтно, а при чтении склеивать обратно.

С другой стороны, учитывая, что максимальное значение 999, проще, как мне показалось перед записью делить значение высоты на 4, а при чтении умножать записанное на 4 перед выводом на дисплей.

В сумме с погрешностью датчика максимальная высота после записичтения из EEPROM может врать в пределах 5м, что я посчитал приемлимым.
Скетч обновлен, реализована побайтная запись, таким образом высота записывается как есть и восстанавливается из памяти точно такая же.

Девайс планирую использовать на учебном FPV пепелаце, на который ОСД ставить жаба душит, а эту штуку вполне можно разместить в поле зрения камеры.

В теории в этот же агрегат можно встроить датчик напряжения батареи и переключать вывод на дисплей того или другого параметра используя для этого канал РУ, но для этого у меня отдельный вольтметр имеется и заморачиваться не стал.

Немного фотографий:
Пины напаял не все, а только те, что будут использоваться. При этом использовал загнутые и разместил их с двух сторон платы.

Дисплей распаял на макетке, не люблю платы травить, да и лень =)

При подключении дисплея не забываем про токоограничивающие резисторы!

Собрал всю лапшу в кучку.

Упаковал.

Общий вид.
Насчет дизайна исполнения: делался под конкретное применение и в моем случае эти гроздья лапши оправданы, так удобней на пепелаце разместить получится.Если делать как единое устройство и нет необходимости выставлять дисплей в поле камеры, то вполне можно упаковать в какой-нибудь корпус с минимальным количеством торчащих проводов, главное дело не закрывать корпус герметично.Вес в сборе около 20гр.Проверял девайс катаясь на лифте до 12 этажа, показывает вполне адекватно.

На этом все. Спасибо за внимание! Еще раз напомню, грамотная критика, отзывы и предложения приветствуются!

Мои предыдущие записи:

FPV. От начинающего начинающим. Часть 2. Маленький и шустрый.

FPV. От начинающего начинающим. Часть 1. Близко и низко.Внедрение джойстика от PS2 в аппаратуру Turnigy 9XУвеличиваем максимальный угол отклонения стандартной сервомашинки.
Отдельностоящий (выносной ретранслятор) модуль РУ для FPV.

Источник: http://www.parkflyer.ru/ru/blogs/view_entry/10539/?commentpage=1

Описание библиотеки Adafruit_GFX для Arduino

Источник: http://robocontroller.ru/news/opisanie_biblioteki_adafruit_gfx_dlja_arduino/2015-04-26-56

Ссылка на основную публикацию
Adblock
detector
",css:{backgroundColor:"#000",opacity:.6}},container:{block:void 0,tpl:"
"},wrap:void 0,body:void 0,errors:{tpl:"
",autoclose_delay:2e3,ajax_unsuccessful_load:"Error"},openEffect:{type:"fade",speed:400},closeEffect:{type:"fade",speed:400},beforeOpen:n.noop,afterOpen:n.noop,beforeClose:n.noop,afterClose:n.noop,afterLoading:n.noop,afterLoadingOnShow:n.noop,errorLoading:n.noop},o=0,p=n([]),h={isEventOut:function(a,b){var c=!0;return n(a).each(function(){n(b.target).get(0)==n(this).get(0)&&(c=!1),0==n(b.target).closest("HTML",n(this).get(0)).length&&(c=!1)}),c}},q={getParentEl:function(a){var b=n(a);return b.data("arcticmodal")?b:(b=n(a).closest(".arcticmodal-container").data("arcticmodalParentEl"),!!b&&b)},transition:function(a,b,c,d){switch(d=null==d?n.noop:d,c.type){case"fade":"show"==b?a.fadeIn(c.speed,d):a.fadeOut(c.speed,d);break;case"none":"show"==b?a.show():a.hide(),d();}},prepare_body:function(a,b){n(".arcticmodal-close",a.body).unbind("click.arcticmodal").bind("click.arcticmodal",function(){return b.arcticmodal("close"),!1})},init_el:function(d,a){var b=d.data("arcticmodal");if(!b){if(b=a,o++,b.modalID=o,b.overlay.block=n(b.overlay.tpl),b.overlay.block.css(b.overlay.css),b.container.block=n(b.container.tpl),b.body=n(".arcticmodal-container_i2",b.container.block),a.clone?b.body.html(d.clone(!0)):(d.before("
"),b.body.html(d)),q.prepare_body(b,d),b.closeOnOverlayClick&&b.overlay.block.add(b.container.block).click(function(a){h.isEventOut(n(">*",b.body),a)&&d.arcticmodal("close")}),b.container.block.data("arcticmodalParentEl",d),d.data("arcticmodal",b),p=n.merge(p,d),n.proxy(e.show,d)(),"html"==b.type)return d;if(null!=b.ajax.beforeSend){var c=b.ajax.beforeSend;delete b.ajax.beforeSend}if(null!=b.ajax.success){var f=b.ajax.success;delete b.ajax.success}if(null!=b.ajax.error){var g=b.ajax.error;delete b.ajax.error}var j=n.extend(!0,{url:b.url,beforeSend:function(){null==c?b.body.html("
"):c(b,d)},success:function(c){d.trigger("afterLoading"),b.afterLoading(b,d,c),null==f?b.body.html(c):f(b,d,c),q.prepare_body(b,d),d.trigger("afterLoadingOnShow"),b.afterLoadingOnShow(b,d,c)},error:function(){d.trigger("errorLoading"),b.errorLoading(b,d),null==g?(b.body.html(b.errors.tpl),n(".arcticmodal-error",b.body).html(b.errors.ajax_unsuccessful_load),n(".arcticmodal-close",b.body).click(function(){return d.arcticmodal("close"),!1}),b.errors.autoclose_delay&&setTimeout(function(){d.arcticmodal("close")},b.errors.autoclose_delay)):g(b,d)}},b.ajax);b.ajax_request=n.ajax(j),d.data("arcticmodal",b)}},init:function(b){if(b=n.extend(!0,{},a,b),!n.isFunction(this))return this.each(function(){q.init_el(n(this),n.extend(!0,{},b))});if(null==b)return void n.error("jquery.arcticmodal: Uncorrect parameters");if(""==b.type)return void n.error("jquery.arcticmodal: Don't set parameter \"type\"");switch(b.type){case"html":if(""==b.content)return void n.error("jquery.arcticmodal: Don't set parameter \"content\"");var e=b.content;return b.content="",q.init_el(n(e),b);case"ajax":return""==b.url?void n.error("jquery.arcticmodal: Don't set parameter \"url\""):q.init_el(n("
"),b);}}},e={show:function(){var a=q.getParentEl(this);if(!1===a)return void n.error("jquery.arcticmodal: Uncorrect call");var b=a.data("arcticmodal");if(b.overlay.block.hide(),b.container.block.hide(),n("BODY").append(b.overlay.block),n("BODY").append(b.container.block),b.beforeOpen(b,a),a.trigger("beforeOpen"),"hidden"!=b.wrap.css("overflow")){b.wrap.data("arcticmodalOverflow",b.wrap.css("overflow"));var c=b.wrap.outerWidth(!0);b.wrap.css("overflow","hidden");var d=b.wrap.outerWidth(!0);d!=c&&b.wrap.css("marginRight",d-c+"px")}return p.not(a).each(function(){var a=n(this).data("arcticmodal");a.overlay.block.hide()}),q.transition(b.overlay.block,"show",1*")),b.overlay.block.remove(),b.container.block.remove(),a.data("arcticmodal",null),n(".arcticmodal-container").length||(b.wrap.data("arcticmodalOverflow")&&b.wrap.css("overflow",b.wrap.data("arcticmodalOverflow")),b.wrap.css("marginRight",0))}),"ajax"==b.type&&b.ajax_request.abort(),p=p.not(a))})},setDefault:function(b){n.extend(!0,a,b)}};n(function(){a.wrap=n(document.all&&!document.querySelector?"html":"body")}),n(document).bind("keyup.arcticmodal",function(d){var a=p.last();if(a.length){var b=a.data("arcticmodal");b.closeOnEsc&&27===d.keyCode&&a.arcticmodal("close")}}),n.arcticmodal=n.fn.arcticmodal=function(a){return e[a]?e[a].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof a&&a?void n.error("jquery.arcticmodal: Method "+a+" does not exist"):q.init.apply(this,arguments)}}(jQuery)}var debugMode="undefined"!=typeof debugFlatPM&&debugFlatPM,duplicateMode="undefined"!=typeof duplicateFlatPM&&duplicateFlatPM,countMode="undefined"!=typeof countFlatPM&&countFlatPM;document["wri"+"te"]=function(a){let b=document.createElement("div");jQuery(document.currentScript).after(b),flatPM_setHTML(b,a),jQuery(b).contents().unwrap()};function flatPM_sticky(c,d,e=0){function f(){if(null==a){let b=getComputedStyle(g,""),c="";for(let a=0;a=b.top-h?b.top-h{const d=c.split("=");return d[0]===a?decodeURIComponent(d[1]):b},""),c=""==b?void 0:b;return c}function flatPM_testCookie(){let a="test_56445";try{return localStorage.setItem(a,a),localStorage.removeItem(a),!0}catch(a){return!1}}function flatPM_grep(a,b,c){return jQuery.grep(a,(a,d)=>c?d==b:0==(d+1)%b)}function flatPM_random(a,b){return Math.floor(Math.random()*(b-a+1))+a}
");let k=document.querySelector(".flat_pm_modal[data-id-modal=\""+a.ID+"\"]");if(-1===d.indexOf("go"+"oglesyndication")?flatPM_setHTML(k,d):jQuery(k).html(b+d),"px"==a.how.popup.px_s)e.bind(h,()=>{e.scrollTop()>a.how.popup.after&&(e.unbind(h),f.unbind(i),j())}),void 0!==a.how.popup.close_window&&"true"==a.how.popup.close_window&&f.bind(i,()=>{e.unbind(h),f.unbind(i),j()});else{let b=setTimeout(()=>{f.unbind(i),j()},1e3*a.how.popup.after);void 0!==a.how.popup.close_window&&"true"==a.how.popup.close_window&&f.bind(i,()=>{clearTimeout(b),f.unbind(i),j()})}f.on("click",".flat_pm_modal .flat_pm_crs",()=>{jQuery.arcticmodal("close")})}if(void 0!==a.how.outgoing){let b,c="0"==a.how.outgoing.indent?"":" style=\"bottom:"+a.how.outgoing.indent+"px\"",e="true"==a.how.outgoing.cross?"":"",f=jQuery(window),g="scroll.out"+a.ID,h=void 0===flatPM_getCookie("flat_out_"+a.ID+"_mb")||"false"!=flatPM_getCookie("flat_out_"+a.ID+"_mb"),i=document.createElement("div"),j=jQuery("body"),k=()=>{void 0!==a.how.outgoing.cookie&&"false"==a.how.outgoing.cookie&&h&&(jQuery(".flat_pm_out[data-id-out=\""+a.ID+"\"]").addClass("show"),j.on("click",".flat_pm_out[data-id-out=\""+a.ID+"\"] .flat_pm_crs",function(){flatPM_setCookie("flat_out_"+a.ID+"_mb",!1)})),(void 0===a.how.outgoing.cookie||"false"!=a.how.outgoing.cookie)&&jQuery(".flat_pm_out[data-id-out=\""+a.ID+"\"]").addClass("show")};switch(a.how.outgoing.whence){case"1":b="top";break;case"2":b="bottom";break;case"3":b="left";break;case"4":b="right";}jQuery("body > *").eq(0).before("
"+e+"
");let m=document.querySelector(".flat_pm_out[data-id-out=\""+a.ID+"\"]");-1===d.indexOf("go"+"oglesyndication")?flatPM_setHTML(m,d):jQuery(m).html(e+d),"px"==a.how.outgoing.px_s?f.bind(g,()=>{f.scrollTop()>a.how.outgoing.after&&(f.unbind(g),k())}):setTimeout(()=>{k()},1e3*a.how.outgoing.after),j.on("click",".flat_pm_out .flat_pm_crs",function(){jQuery(this).parent().removeClass("show").addClass("closed")})}countMode&&(flat_count["block_"+a.ID]={},flat_count["block_"+a.ID].count=1,flat_count["block_"+a.ID].click=0,flat_count["block_"+a.ID].id=a.ID)}catch(a){console.warn(a)}}function flatPM_start(){let a=flat_pm_arr.length;if(0==a)return flat_pm_arr=[],void jQuery(".flat_pm_start, .flat_pm_end").remove();flat_body=flat_body||jQuery("body"),!flat_counter&&countMode&&(flat_counter=!0,flat_body.on("click","[data-flat-id]",function(){let a=jQuery(this),b=a.attr("data-flat-id");flat_count["block_"+b].click++}),flat_body.on("mouseenter","[data-flat-id] iframe",function(){let a=jQuery(this),b=a.closest("[data-flat-id]").attr("data-flat-id");flat_iframe=b}).on("mouseleave","[data-flat-id] iframe",function(){flat_iframe=-1}),jQuery(window).on("beforeunload",()=>{jQuery.isEmptyObject(flat_count)||jQuery.ajax({async:!1,type:"POST",url:ajaxUrlFlatPM,dataType:"json",data:{action:"flat_pm_ajax",data_me:{method:"flat_pm_block_counter",arr:flat_count}}})}).on("blur",()=>{-1!=flat_iframe&&flat_count["block_"+flat_iframe].click++})),flat_userVars.init();for(let b=0;bflat_userVars.textlen||void 0!==a.chapter_sub&&a.chapter_subflat_userVars.titlelen||void 0!==a.title_sub&&a.title_subc&&cc&&c>d&&(b=flatPM_addDays(b,-1)),b>e||cd||c-1!=flat_userVars.referer.indexOf(a))||void 0!==a.referer.referer_disabled&&-1!=a.referer.referer_disabled.findIndex(a=>-1!=flat_userVars.referer.indexOf(a)))&&(c=!0),c||void 0===a.browser||(void 0===a.browser.browser_enabled||-1!=a.browser.browser_enabled.indexOf(flat_userVars.browser))&&(void 0===a.browser.browser_disabled||-1==a.browser.browser_disabled.indexOf(flat_userVars.browser)))){if(c&&void 0!==a.browser&&void 0!==a.browser.browser_enabled&&-1!=a.browser.browser_enabled.indexOf(flat_userVars.browser)&&(c=!1),!c&&(void 0!==a.geo||void 0!==a.role)&&(""==flat_userVars.ccode||""==flat_userVars.country||""==flat_userVars.city||""==flat_userVars.role)){flat_pm_then.push(a),flatPM_setWrap(a),flat_body.hasClass("flat_pm_block_geo_role")||(flat_body.addClass("flat_pm_block_geo_role"),flatPM_ajax("flat_pm_block_geo_role")),c=!0}c||(flatPM_setWrap(a),flatPM_next(a))}}}let b=jQuery(".flatPM_sticky");b.each(function(){let a=jQuery(this),b=a.data("height")||350,c=a.data("top");a.wrap("
");let d=a.parent()[0];flatPM_sticky(this,d,c)}),debugMode||countMode||jQuery("[data-flat-id]:not([data-id-out]):not([data-id-modal])").contents().unwrap(),flat_pm_arr=[],jQuery(".flat_pm_start, .flat_pm_end").remove()}
Adafruit_GFX – это библиотека для Arduino, имеющая в своем наборе синтаксис и графические функции для LCD и OLED дисплеев. Она позволяет легко адаптировать скетч Ардуино для работы с дисплеем. Библиотека Adafruit_GFX всегда работает в паре со специализированной библиотекой для используемого дисплея.

Например, если у вас монохромный дисплей OLED 128×64 с чипом SSD1306, вам нужно установить две библиотеки, Adafruit_GFX и Adafruit_SSD1306. Ссылки на библиотеки для различных дисплеев смотрите в конце статьи.
Система координат: Пиксели – это блоки из которых состоят цифровые картинки.

Пиксель имеет фиксированный размер высоты и длинны (квадрат), размер пикселя зависит от разрешения дисплея. Каждый пиксель позиционируется на экране по горизонтальной оси X и вертикальной оси Y. Система координат начинается в левом верхнем углу экрана с точки X = 0, Y = 0 и продолжается с положительным увеличением оси X вправо, оси Y вниз.

Это стандартная Декартовая (прямоугольная) система координат. В зависимости от ориентации дисплея «Портрет», «Пейзаж» или другого специфического расположения, можно указать какой из четырех углов будет обозначен как левый верхний (начальная точка осей).
Цвета: Для цветных дисплеев, цвета представлены в беззнаковом 16-и битном формате.

Некоторые из дисплеев могут передавать цвета с большим количеством битов, но библиотека оперирует только 16-и битными значениями, это упрощает работу Ардуино с различными дисплеями. Цвет складывается из трех основных цветов – красный, зеленый, синий, которые упакованы в одном 16-и битном значении.

Первые 5 бит для красного, средние 6 бит для зеленого, последние 5 бит для синего. Человеческий глаз более чувствителен к зеленому цвету, поэтому для него выделено на 1-бит больше.Для удобства использования большинства основных и вторичных цветов, вы можете добавить в свой код готовый набор. Вы можете использовать любой из 65,536 цветов.

// Color definitions #define BLACK 0x0000 #define BLUE 0x001F #define RED 0xF800 #define GREEN 0x07E0 #define CYAN 0x07FF #define MAGENTA 0xF81F #define YELLOW 0xFFE0

#define WHITE 0xFFFF

Для монохромных (одноцветных) дисплеев, цвет всегда определяется как 1 (светится) или 0 (не светится). Смысл значений «светится/не светится», меняется в зависимости от специфики отображения дисплеев.

На дисплее с OLED подсветкой, значение “1” будет подсвечивать пиксель. На рефлективных дисплеях, значение 1 сделает цвет черным.

Возможны исключения, но по умолчанию, цвет бекграунда при начальной инициализации дисплея имеет значение 0 (чистый, не светится).

Простейшая графика:

В библиотеке для каждого дисплея имеются свои конструкции и функции инициализации. Они описаны в отдельных инструкциях для каждого типа дисплея. Также, их можно найти в заголовочном файле библиотеки дисплея. Далее описана общие графические функции, которые одинаково работают вне зависимости от типа дисплея.

Описанные ниже функции всего лишь прототипы – дисплей может быть объявлен как объект в соответствии со структурой библиотеки используемого устройства. Смотрите пример работы библиотеки для конкретного дисплея. Например, чтобы вывести на экран символы используя команду print(3.

14); Код для вашего дисплея будет содержать имя объявленного устройства непосредственно перед командой print. Если объект вашего дисплея объявлен как screen, то ваша строка будет выглядеть так: screen.print(3.14); На примере OLED 128×64 с чипом SSD1306, дисплей объявляется как объект с именем display.

Тогда строка вывода на экран будет такая: display.print(3.14);.

Пиксель (точка):

Это самый простой способ нарисовать пиксель (точку) на экране. Вам нужно указать координаты расположения пикселя X, Y и его цвет.

void drawPixel(uint16_t x, uint16_t y, uint16_t color);

В вашем коде, эта строка будет выглядеть так (пример для монохромного OLED дисплея):

display.drawPixel(10, 15, 1);

10 – x координата расположения пикселя на экране, 15 – y координата расположения пикселя на экране, 1 – color цвет пикселя (светится).

Линия:

Для прорисовки линий используются начальная и конечная точка линии.

void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color);

В вашем коде, эта строка будет выглядеть так (пример для монохромного OLED дисплея):

display.drawLine (5, 10, 19, 3, 1);

5 – x0 начальная координата линии, 10 – y0 начальная координата линии, 19 – x1 конечная координата линии, 3 – y1 конечная координата линии, 1 – color цвет линии (светится).Для горизонтальных и вертикальных линий существует более упрощенная функция. В ней указывается начальные координаты линии, её длинна в пикселях и цвет.

void drawFastVLine(uint16_t x0, uint16_t y0, uint16_t length, uint16_t color);

void drawFastHLine(uin86_t x0, uin86_t y0, uint8_t length, uint16_t color); В вашем коде, строка для вертикальной линии будет выглядеть так (пример для монохромного OLED дисплея):

display.drawFastVLine (7, 12, 20, 1);

7 – x0 начальная координата вертикальной линии, 12 – y0 начальная координата вертикальной линии, 20 – length длинна вертикальной линии в пикселях, 1 – color цвет вертикальной линии (светится).

Прямоугольники:

Для прорисовки прямоугольников используются, координаты верхнего левого угла прямоугольника X, Y, ширина w, высота h, цвет. drawRect() – рисует линию по границам сторон прямоугольника. fillRect() – рисует прямоугольник площадь которого залита указанным цветом.

void drawRect(uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t color);

void fillRect(uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t color); В вашем коде, строка для прорисовки прямоугольника будет выглядеть так (пример для монохромного OLED дисплея):

display.drawRect (3, 2, 12, 10, 1);

3 – x0 начальная координата прямоугольника, 2 – y0 начальная координата прямоугольника, 12 – w ширина прямоугольника в пикселях, 10 – h высота прямоугольника в пикселях, 1 – color цвет прямоугольника (светится), для функции fillRect() – это цвет заливки площади прямоугольника.
Круг: Функция прорисовки круга использует следующие значения: центральные координаты круга X, Y, радиус, цвет. drawCircle() – рисует круг. fillCircle – рисует круг, площадь которого залита выбранным цветом.

void drawCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color);

void fillCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color); В вашем коде, строка для прорисовки круга будет выглядеть так (пример для монохромного OLED дисплея):

display.drawCircle (14, 8, 7, 1);

14 – x0 центральная координата круга по оси X, 8 – y0 центральная координата круга по оси Y, 7 – r радиус круга в пикселях, 1 – color цвет круга (светится), для функции fillCircle() – это цвет заливки площади круга.
Прямоугольник со скругленными углами: Функция прорисовки прямоугольника со скругленными углами использует: начальные координаты левого верхнего угла прямоугольника X, Y, ширину, высоту, радиус скругления угла в пикселях и цвет. drawRoundRect() – прорисовывает прямоугольник со скругленными углами. fillRoundRect() – прорисовывает прямоугольник со скругленными углами, площадь которого залита выбранным цветом.

void drawRoundRect(uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t radius, uint16_t color);

void fillRoundRect(uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t radius, uint16_t color);

В вашем коде, строка для прорисовки прямоугольника со скругленными углами будет выглядеть так (пример для монохромного OLED дисплея):

display.drawRoundRect (3, 1, 18, 13, 5, 1);

3 – x0 начальная координата прямоугольника, 1 – y0 начальная координата прямоугольника, 18 – w ширина прямоугольника в пикселях, 13 – h высота прямоугольника в пикселях, 5 – radius радиус скругления углов прямоугольника, 1 – color цвет прямоугольника (светится), для функции fillRoundRect() – это цвет заливки площади прямоугольника.Использование функции прямоугольника со скругленными углами имеет дополнительную возможность. Если радиус скругления углов сделать равным половине ширины или высоты прямоугольника, то вы сможете получить овал. Радиус скругления углов применяется ко всем четырем углам прямоугольника.

Треугольник:

Функция прорисовки треугольника использует следующие параметры: начальные координаты первого угла, координаты второго угла, координаты третьего угла, цвет. drawTriangle() – прорисовывает треугольник.

fillTriangle() – прорисовывает треугольник площадь которого залита выбранным цветом.

void drawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);

void fillTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);

В вашем коде, строка для прорисовки прямоугольника будет выглядеть так (пример для монохромного OLED дисплея):

display.drawTriangle (6, 13, 9, 2, 18, 9, 1);

7 – x0 координата первого угла, 12 – y0 координата первого угла, 7 – x1 координата второго угла, 12 – y1 координата второго угла, 7 – x2 координата третьего угла, 12 – y2 координата третьего угла, 1 – color цвет треугольника (светится), для функции fillTriangle () – это цвет заливки площади треугольника.
Символы и текст: В библиотеке имеются две простые функции вывода текста на экран. Первая, для вывода одного единственного символа. Вы можете поместить один символ в любое место экрана и задать этому символу нужный цвет. Основной размер символа 5×8 пикселей. Но размеры можно пропорционально изменять. Например, задав символу размер size=2, размер символа станет 10×16 пикселей. Эта скомпонованная функция сделана для уменьшения программы.

void drawChar(uint16_t x, uint16_t y, char c, uint16_t color, uint16_t bg, uint8_t size);

В вашем коде, строка для одного символа будет выглядеть так (пример для монохромного OLED дисплея):

display.drawChar (3, 4, ‘A’, 1, 0, 1);

3 – x координата символа, 4 – y координата символа, ‘A’ – выводимый символ, должен быть заключен в одинарные ковычки, 1 – color цвет символа, 0 – bg фон (бекграунд) символа, 1 – size размер символа,Вывод строки символов (текст), отличается от вывода одного символа. Для того, чтобы задать параметры для строки, нужно использовать несколько функций. Задав координаты, цвет и размеры в разных функциях, строка выводится функцией print() которая использует заданные раннее параметры. Такой способ вывода похож на известную вам функции Serial.print(). Ниже приведен набор функций используемых для вывода строк.

void setCursor(uint16_t x0, uint16_t y0); void setTextColor(uint16_t color); void setTextColor(uint16_t color, uint16_t backgroundcolor); void setTextSize(uint8_t size);

void setTextWrap(boolean w);

В первую очередь, вам нужно задать координаты начала строки, функция setCursor(x, y), задает координаты верхнего левого угла строки. По умолчанию, её значения (0, 0) (верхний левый угол экрана). Затем задаем цвет строки, функция setTextColor(color). По умолчанию, её значение 0 (текст не видим / не светится). Каждый символ в строке имеет свой фон.

Фону можно задать цвет дополнительным (не обязательным) вторым параметром функции setTextColor() (цвет фона задается для всей строки символов) setTextColor(color, backgroundcolor); Далее задаем размер символов в строке setTextSize(size). По умолчанию значение size=1, допустимые значения 2 и 3.

После того как вы установили все нужные настройки, вы можете выводить строку символов на экран, используя функцию print() или println(). Точно также, как вы выводите текст при помощи функции Serial.print(). Например, для того, чтобы вывести строку (текст) на экран, используйте print(“Hello world”) – это первая строка на фотографии экрана.

Вы также можете выводить цифры и переменные, например, print(1234.56) – это вторая строка на фотографии с экраном. И третья строка, это print(0xDEADBEEF, HEX). По умолчанию, длинные строки выводятся слева направо, если строка длиннее размеров экрана, то происходит перенос текста на новую строку. За это отвечает функцию setTextWrap(), по умолчанию setTextWrap(1).

Если применить setTextWrap(0), то длинная строка не будет переноситься и уйдет за пределы экрана, что подходит для скрола (можно сделать бегущую строку). Ваш код для вывода строки символа будет выглядеть так (пример для монохромного OLED дисплея):

// Устанавливаем курсор (X = 5, Y = 3) display.setCursor(5, 3); // Задаем цвет текста (1) (видимый / светится) display.

setTextColor(1); // Если дополнительно нужно задать цвет фона строки, // используем ниже идущую функцию // в этом случае использовать функцию display.setTextColor(1); не нужно. // Указываем цвет текста и фона строки, в данном примере будет темный текст на белом фоне. display.

setTextColor(0, 1); // Указываем размер символов в строке (1), каждый символ размером 5×7 пикселей. display.setTextSize(1); // Выводим текст на экран, текст будет выведен с указанными выше настройками

display.print(“Hello world”);

Bitmaps (растровые изображения):

Вы можете выводить на экран небольшие монохромные (одноцветные) растровые изображения (bitmaps). Функция drawBitmap() хорошо подходит для спрайтов, мини анимации и иконок.

void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color);

Эта функция выводит блок битов на дисплей, где ‘1’ бит выводит (окрашивает) один пиксель на экране. В то время как ‘0’ бит пропускает (не выводит на экран) пиксель. Координаты X, Y, указывают верхний левый угол с которого начинается прорисовка картинки на экране.

w и h, указывают ширину и высоту картинки в пикселях. Bitmap должен быть записан в память устройства, для этого используется PROGMEM директивы. Для ознакомления предлагается прочитать инструкцию по применению PROGMEM (ссылка).

Очистка и заливка экрана:

Функция fillScreen() заливает дисплей выбранным цветом стирая всё что есть на экране. В библиотеках для разных дисплеев могут быть свои функции очистки дисплея.

void fillScreen(uint16_t color);

Поворот экрана:

Вы можете изменять ориентацию выводимой графики и текста на экране. Эта функция не изменяет положение уже выведенных элементов, но изменит расположение системы координат для последующего выведения.

Функция setRotation() может применить всего один раз, в разделе setup(). Можно повернуть экран только на 0, 90, 180 или 270 градусов. Остальные углы требуют более мощного оборудования, это делает невозможным их вычисление на Arduino.

void setRotation(uint8_t rotation);

Параметры поворота экрана могут быть 0, 1, 2, 3. Для разных типов экранов, начальное положение (0 градусов) может быть в разных положениях. Меняйте значение в функции setRotation(), чтобы повернуть экран в нужное положение.В вашем коде, строка для поворота экрана будет выглядеть так (пример для монохромного OLED дисплея):

display.setRotation(1);

1 – rotation угол поворота экрана в градусах: 0 = 0, 1 = 90, 2 = 180, 3 = 270.

Ссылки и информация:

Подробное описание всех функций библиотеки Adafruit_SSD1306 и примеры их применения читайте тут (ссылка скоро появиться).

Описание и технические возможности дисплеев Adafruit ищите на официальном сайте производителя https://www.adafruit.com/

Библиотеки для дисплеев ищите на GitHub Adafruit https://github.com/adafruit (воспользуйтесь поиском).

В статье использовались материалы с сайта https://learn.adafruit.com.