Уменьшаем количество проводов в Arduino — I2C LCD экран и RTC часы по двум проводам

от автора

Совсем недавно познакомился с Ардуино, поэтому многим мои примеры покажутся простыми.

Однако таким же новичкам, как я, данная информация будет полезна и сэкономит массу времени.

I2C — стандарт общения устройств по 2м проводам, при этом количество устройств, которое висит параллельно на этих проводах может быть очень большим. У каждого устройства есть свой адрес, по которому происходит обращение к устройству. Адресацию можно менять, если на устройстве есть перемычки, которыми можно установить дополнительное смещение относительно базового адреса, жестко прописанного в устройстве.

Это в двух словах.

Начал я все с того, что купил 16х2 символьный LCD дисплей на Ибее. Подключив стандартно — понял что это не то, что нужно. Масса проводов — занимает кучу ножек, хаос и беспорядок.

image

Погуглил, понял что есть дисплеи с интерфейсами, упрощающие подключение. погуглил еще, нашел переходник на I2C для моего LCD. Месяц ожидания, ура-ура, подключил.

image

Выглядит гораздо интереснее!

Проблема возникла на этапе поиска рабочих библиотек и примеров. Как оказалось потом — в основной наиболее известной библиотеке bitbucket.org/fmalpartida/new-liquidcrystal/downloads — примеры — не рабочие! Это заняло некоторое время и силы=)

Конкретно вот тут лежат рабочие примеры и ссылка на библиотеку. arduino-info.wikispaces.com/LCD-Blue-I2C
Там же можно найти описания различных версий LCD-I2C переходников, которые можно купить.

Данная версия библиотеки требует установку параметров дисплея в следующем виде

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address 

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

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

Вторая библиотека заработала сразу. arduino-info.wikispaces.com/file/detail/LiquidCrystal_I2C1602V1.zip/341635514
К сожалению, не помню откуда взял демо для данной библиотеки, но в ней используется упрощенная настройка LCD, что мне было и нужно.

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display 

В данной строке назвачается адрес устройства и определяется тип дисплея, 16 символов в 2 строки.

Первая и вторая библиотеки между собой не совместимы! . Примеры для одной библиотеки не работают с другой. Нижеследующий код будет относиться к последней указанной библиотеке для работы с I2C LCD.

После подключения экрана, захотелось что-то на него выводить. Просто цифры не интересно. Пусть будут часы=)) Наверное, все проходят этот путь, включая меня. Софтовые часы Ардуины вполне себе позволяют показывать время, но проблема в сбросе данных при отключении. А так как кнопок у меня нет, устанавливать часы приходится через кабель по COM порту через консоль. Вообщем, надоело мне это очень быстро.

Часы реального времени RTC1307 — наверное самая распространенная микросхема для часов. Плюсов много — отдельная микросхема, независима от основного питания Ардуино при наличии батарейки, не зависима от основной программы — время считает точно! Преимущество часов на базе 1307 — I2С. При этом никаких дополнительных выходов задействовать не нужно — управляется все по тем же 2м проводам как и LCD.

Библиотека для работы с часами по I2c заработала сразу, примеры рабочие. github.com/adafruit/RTClib

Программа простая, все прозрачно. Цифры создаются функциями, в которых отдельными блоками выводится цифра. Блоки по 5×8 точек задаются в пользовательских символах, максимально их может быть 8. Пример взят с форума arduino.cc.

Отрисовка происходит в отдельной функции, цифры выводятся по одной. Бегающие крестики — прихоть автора, т.е. моя)) Смещение цифр контролируется при вызове функции отрисовки.

// Date and time functions using a DS1307 RTC connected via I2C and Wire lib  #include <Wire.h> #include "RTClib.h" #include <LiquidCrystal_I2C.h> RTC_DS1307 rtc; LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display  byte LT[8] =  {     B00111,   B01111,   B11111,   B11111,   B11111,   B11111,   B11111,   B11111 }; byte UB[8] = {   B11111,   B11111,   B11111,   B00000,   B00000,   B00000,   B00000,   B00000 }; byte RT[8] = {    B11100,   B11110,   B11111,   B11111,   B11111,   B11111,   B11111,   B11111 }; byte LL[8] = {     B11111,   B11111,   B11111,   B11111,   B11111,   B11111,   B01111,   B00111 }; byte LB[8] = {   B00000,   B00000,   B00000,   B00000,   B00000,   B11111,   B11111,   B11111 }; byte LR[8] = {     B11111,   B11111,   B11111,   B11111,   B11111,   B11111,   B11110,   B11100 }; byte MB[8] = {   B11111,   B11111,   B11111,   B00000,   B00000,   B00000,   B11111,   B11111 }; byte block[8] = {   B11111,   B11111,   B11111,   B11111,   B11111,   B11111,   B11111,   B11111 }; // loop counter int count = 0;    void setup () {   Serial.begin(57600);   Wire.begin();   rtc.begin();   lcd.init();                      // initialize the lcd    lcd.backlight();   lcd.home();    lcd.createChar(0,LT);   lcd.createChar(1,UB);   lcd.createChar(2,RT);   lcd.createChar(3,LL);   lcd.createChar(4,LB);   lcd.createChar(5,LR);   lcd.createChar(6,MB);   lcd.createChar(7,block);    // sets the LCD's rows and colums:   lcd.clear();        if (! rtc.isrunning()) {     Serial.println("RTC is NOT running!");     // following line sets the RTC to the date & time this sketch was compiled     // rtc.adjust(DateTime(__DATE__, __TIME__));   } }    void custom0(int x) { // uses segments to build the number 0    lcd.setCursor(x,0); // set cursor to column 0, line 0 (first row)   lcd.write(0);  // call each segment to create   lcd.write(1);  // top half of the number   lcd.write(2);   lcd.setCursor(x, 1); // set cursor to colum 0, line 1 (second row)   lcd.write(3);  // call each segment to create   lcd.write(4);  // bottom half of the number   lcd.write(5); }  void custom1(int x) {   lcd.setCursor(x,0);   lcd.write(1);   lcd.write(2);   lcd.print(" ");   lcd.setCursor(x,1);   lcd.write(4);   lcd.write(7);   lcd.write(4); }  void custom2(int x) {   lcd.setCursor(x,0);   lcd.write(6);   lcd.write(6);   lcd.write(2);   lcd.setCursor(x, 1);   lcd.write(3);   lcd.write(4);   lcd.write(4); }  void custom3(int x) {   lcd.setCursor(x,0);   lcd.write(6);   lcd.write(6);   lcd.write(2);   lcd.setCursor(x, 1);   lcd.write(4);   lcd.write(4);   lcd.write(5);  }  void custom4(int x) {   lcd.setCursor(x,0);   lcd.write(3);   lcd.write(4);   lcd.write(7);   lcd.setCursor(x, 1);   lcd.print(" ");   lcd.print(" ");   lcd.write(7); }  void custom5(int x) {   lcd.setCursor(x,0);   lcd.write(3);   lcd.write(6);   lcd.write(6);   lcd.setCursor(x, 1);   lcd.write(4);   lcd.write(4);   lcd.write(5); }  void custom6(int x) {   lcd.setCursor(x,0);   lcd.write(0);   lcd.write(6);   lcd.write(6);   lcd.setCursor(x, 1);   lcd.write(3);   lcd.write(4);   lcd.write(5); }  void custom7(int x) {   lcd.setCursor(x,0);   lcd.write(1);   lcd.write(1);   lcd.write(2);   lcd.setCursor(x, 1);   lcd.print(" ");   lcd.print(" ");   lcd.write(7); }  void custom8(int x) {   lcd.setCursor(x,0);   lcd.write(0);   lcd.write(6);   lcd.write(2);   lcd.setCursor(x, 1);   lcd.write(3);   lcd.write(4);   lcd.write(5); }  void custom9(int x) {   lcd.setCursor(x,0);   lcd.write(0);   lcd.write(6);   lcd.write(2);   lcd.setCursor(x, 1);   lcd.print(" ");   lcd.print(" ");   lcd.write(7);  }  //void clearnumber(int x) //{ // clears the area the custom number is displayed in  // lcd.setCursor(x,0); // lcd.print("   "); // lcd.setCursor(x,1);  // lcd.print("   "); //}     void loop () {    digitalClockDisplay();     delay(1000);  }   void digitalClockDisplay(){   // digital clock display of the time   DateTime now = rtc.now();    printDigits(now.hour()/10,0);    printDigits(now.hour()%10,4);     printDigits(now.minute()/10,9);   printDigits(now.minute()%10,13);    // lcd.setCursor(7, 1);   //  lcd.print(now.second()/10);   //   lcd.print(now.second()%10);     if (now.second()%10%2==0){     lcd.setCursor(7, 0);     lcd.print("+ ");     lcd.setCursor(7, 1);     lcd.print(" +");     lcd.setCursor(3, 1);     lcd.print("+");     lcd.setCursor(12, 0);     lcd.print("+");     lcd.setCursor(3, 0);     lcd.print(" ");     lcd.setCursor(12, 1);     lcd.print(" ");   }   else   {     lcd.setCursor(7, 0);     lcd.print(" +");     lcd.setCursor(7, 1);     lcd.print("+ ");     lcd.setCursor(3, 0);     lcd.print("+");     lcd.setCursor(12, 1);     lcd.print("+");     lcd.setCursor(3, 1);     lcd.print(" ");     lcd.setCursor(12, 0);     lcd.print(" ");   }   //нарисовали двоеточие  }    void printDigits(int digits, int x){   // utility function for digital clock display: prints preceding colon and leading 0    switch (digits) {   case 0:       custom0(x);     break;   case 1:       custom1(x);     break;   case 2:       custom2(x);     break;   case 3:       custom3(x);     break;   case 4:       custom4(x);     break;   case 5:       custom5(x);     break;   case 6:       custom6(x);     break;   case 7:       custom7(x);     break;   case 8:       custom8(x);     break;   case 9:       custom9(x);     break;    }    }      

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

UPD: пока заметка лежала в песочнице, сделал еще несколько вариантов часов. Кому-то это интересно? Сделал псевдо 3в шрифт из 3х2 символов и сделал тонкий шрифт из 2х2 символов для вывода на одном 1602 экране часов, минут, секунд + отображение дня недели и даты. Тонкий шрифт — нарисовал сам по како-то случайной картинке — в виде кода не нашел.

ссылка на оригинал статьи http://habrahabr.ru/post/219137/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *