Translate

суббота, 28 апреля 2018 г.

Солнечной электроэнергетики пост

Поэкспериментировать с солнечными панелями мечтал ещё со школы. Понятное дело, хотелось робота на солнечных батареях, но в распоряжении были только панельки из старых калькуляторов, которых не хватало ни на что. В общем, тема оставалась некопаной, а тут вот что-то снова заинтересовала альтернативная энергетика, и прям захотелось заняться. В начале весны решил заказать в Китае парочку, чтобы наконец с ними поэкспериментировать. Купил в результате десять. Вот уже месяц с ними играюсь в свободное время. Решил наконец написать об этом, когда уже вошёл немного в тему. Итак, краткие выводы о моих "солярочках":)

Краткие выводы


1) Скорее разочарован, чем обрадован - прилично работают только на ярчайшем солнце.
2) Когда солнце заходит за облачко, мощность падает в разы.
3) Когда солнца нет вообще (любимая погода жителей Центральной России) - ловить от них нечего, можно смело убирать на антресоли, жалкие миллиамперы от пачки солнечных панелей.
4) Заряжать что-то напрямую неэффективно, лучше заряжать потихоньку powerbank, а от него уже всё остальное.
5) При изменении угла наклона панели к солнцу падение мощности ощутимо уже при отклонении в десяток градусов. Если разложить плашмя на земле, полу, столе... и уйти пить чай - работать будет в несколько раз хуже, чем при перпендикулярном расположении к солнечным лучам. (Если вы, конечно, не находитесь в этот момент где-то на экваторе, и солнце не светит вам в темя из самого зенита; а скорее всего, дорогой читатель, если читаете это сейчас на русском, - на экваторе вы не находитесь...).

Вот, это если коротко.

А теперь если не коротко


Вот так оно приехало. Сзади четыре точки под пайку,
их надо залудить.
Но вообще, я не пожалел, что попробовал, и может быть закажу ещё для каких-нибудь поделок. (Пока в планах этот десяток потратить на сборку солнечной зарядки, детали только приехали и ждут своей очереди) Вышло примерно 100 рублей за штуку, что не так дорого. Упаковка ничего, но внутри панельки болтались. Приехали стопочкой, с налепленной на каждую целофаном. На самом деле, заявленная мощность, как это часто принято делать в Китайской Народной Республике, завышенной не оказалась. Но, с другой стороны, это как посмотреть. Возможно, где-нибудь под ясным и безоблачным небом Хайнаня и Гуандуна, под нещадно палящим тропическим солнцем у китайцев пауэрбанки всегда полны, а амперметры солнечных зарядок зашкаливает от переизбытка света и тепла, но нам это не светит. Сейчас весна, и всё равно мне пришлось ждать несколько дней, чтобы вышло наконец солнце, и я мог нормально испытать эти панельки. В день, когда я их получил на почте, была такая облачность, что всё что мне оставалось делать - совать панельки под настольную лампу. На столе от окна со всех вместе выходило несколько миллиампер всего! В климате, где солнце может не выходить из-за туч месяцами... в общем, поздней осенью можно убирать всё это хозяйство на полгода до самого марта. Да, дорогой товарищ, здесь тебе не Гуандун и даже не Нинся-Хуэйский автономный округ.
Ещё не порадовало то, что напряжение также скачет весьма прилично, что для прямой зарядки от панелей не радует особенно. На максимуме оно поднимается выше семи вольт, в тени уже до 4 - 4,5, а в пасмурную погоду может упасть до 3 и ниже. Таким образом, зарядку от них лучше производить через стабилизатор напряжения.
Краткий экскурс в географию или почему перспективы солнечной энергетики у нас не такие уж и солнечные

Купил, спаял, померил, что дальше?

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

Кстати, о тени и веточках. 


Эксперимент показал, что при неравномерном освещении солнечных панелей, суммарная мощность конструкции может прилично проседать. В прочем, экспериментально мне не удалось получить сильную просадку по мощности. Также, батарея, оказавшаяся в тени будет как бы находиться под напряжением других батарей, так как её собственное упадёт. В результате, я нашёл информацию, что это неблагоприятно может сказаться на её сроке службы. Решение проблемы - подключение панелей через диоды. В идеале - диоды шоттки, с низким падением напряжения на самих диодах. Я использовал какие были, а были у меня CT2A05. Это высоковольтные диоды, так что смысла использовать именно их нет вообще, но что было, то и было. Просадки по току почти нет, хотя и особого влияния на выход тока я не почувствовал.

Результат.


Опыты проводились в марте-апреле в пятидесятых широтах Северного полушария. В результате я получил с десяти панелей заявленные 1,2 ампера с напряжением около 7 вольт на выходе. Отмечу, что даже обычное оконное стекло снижало выход тока процентов на 20. Так что только безоблачное небо и plein air. Кстати, утреннее и вечернее солнце тоже выдают меньше тока, чем дневное. Оно и понятно - меняется толщина слоя атмосферы, через который проходит свет от нашей звезды. Оптимальными условия становятся ближе к полудню, и это всего несколько часов. Вечернее и утреннее солнце условно слабее раза в два. На закате и восходе - тем более.
И хоть результаты несколько разочаровывают, а потраченных денег мне бы хватило на полтора месяца пользования городской энергосетью, идея даже не в автономности, на которую рассчитывать от десятка таких малюток явно не приходится, а просто в эксперименте и опыте использования. Посмотрим, что удастся сделать из них за лето. А пока впереди много проектов, всем творческих успехов!

Datasheet CT2A (на всякий случай): http://pdf1.alldatasheet.com/datasheet-pdf/view/333153/CTC/CT2A05.html

среда, 25 апреля 2018 г.

Датчик давления BMP180

Ещё один шаг к созданию метеостанции.


Датчик давления BMP180
Посмотрел под увеличением, как запаял пины, и ужаснулся.
Сегодня испытываю датчик давления BMP180. Скажу, что он порадовал меня значительно больше. Запустился без танцев с бубном, библиотека сразу заработала, да и измерения получились куда более точные и эффективные. Дело в том, что это тоже не просто датчик давления, а ещё это датчик температуры и при желании - высоты. Не вдаваясь в подробности, скажу, что атмосферное давление зависит от толщины столба воздуха, находящегося над местом измерений, и чем он толще и плотнее, тем давление выше. Температура, она и в Африке температура, на давление влияет только косвенно, так как у воздуха с разной температурой разная плотность. Но вот на измерения самого прибора, она, похоже, влияет куда сильнее, так что для измерения давления сначала надо замерить температуру. Измеряется она очень быстро в сравнении с медленным и долгим DHT-11 (См. как я долго и мучительно его вчера настраивал). Из недостатков скажу, что для охлаждения и нагревания чипу на датчике тоже нужно время. Если прижать к нему палец, то температура подскакивает до +30 уже через несколько секунд. Остывание же до уличной температуры у открытого окна шло значительно медленне, подозреваю, для полного выравнивания нужны уже десятки минут - до конца так и не доостужал (там холодно и дождик). Рабочий диапазон температур заявлен от 0 до +65°C. Увы, на морозы он, похоже, тоже не рассчитан. Хотя заявлен рабочий диапазон для самого устройства от +85 до -40°C. Ну, хотя бы на улицу вывешивать можно, минус сорок на моей памяти тут у нас ещё не бывало.

Собственно, барометр


Давление измеряет быстро и, кажется, исправно. Однако, при сопоставлениями с настенным анероидом даёт погрешность 7-8 мм ртутного столба. Есть повод задуматься - кто врёт. Нужен третий барометр. Данные Гисметео оказываются где-то посередине - больше датчика на 3 мм и на 4 мм ниже барометра-анероида.
При изменении высоты датчика на уровне комнаты давление исправно меняется на сотые и десятые миллиметра, что приятно радует. Такой точности измерений мой аналоговый прибор со стрелкой дать не может.
Проблемой для точности измерений является также высота. На каждые 10,5 метров давление у поверхности Земли падает с высотой на 1 мм ртутного столба, что весьма ощутимо уже в многоэтажках. А так как нахожусь я в одном из таких творений советской архитектуры на весьма ощутимом удалении от поверхности планеты и тем более ощутимом от уровня Балтийского моря, который и принят за уровень 0 метров. В общем, сопоставить данные своего барометра с данными прогноза погоды я могу весьма условно. С другой стороны, лично мне погрешность в 10 миллиметров ртутного столба не так интересна. Я знаю, что для моего дома нормой является примерно 752 мм, но это ничего не даёт, по большому счёту. Куда интереснее сами изменения давления, пусть и относительно более-менее условной цифры. Мы ведь знаем, что падение давления предвещает ухудшение погоды, а рост - приход антициклона с солнцем и ясным небом.
Что касается изменения колебаний давления, то по мне, так здесь они очень точные и позволяют улавливать перемещение на пару десятков сантиметров минимум. Так что при желании, можно узнать высоту своей местности над уровнем моря и, исходя из этого числа, построить на базе данного прибора альтиметр. Правда, давление ещё меняется в течение суток, так что не могу назвать такой альтиметр очень точным без постоянной калибровки по эталонному барометру на базе, но сделать можно. Мне же интереснее наблюдать погоду, так что для моих целей данный девайс вполне подойдёт.

И, да, барометр измеряет давление в гектапаскалях или миллибарах (это одно и то же). Если нужно вывести давление в привычных миллиметрах ртутного столба (а мне лично именно так и привычнее), то нужно домножать на коэффициент.

1 миллибар = 0,750062 мм рт. ст.

Как узнать высоту точки над уровнем моря?


Для этого рекомендую использовать программу Google Earth. К сожалению, в браузерной версии высота не отображается, а вот в программе, которая, кстати, интересна уже просто сама по себе, можно навести мышь на любую точку земной пверхности и в правом нижнем углу увидеть её высоту. Так высота площади перед Notre Dame de Paris, оказывается, составляет 36 метров над уровнем моря. К сожалению или к счастью, дорогой читатель, мы с вами не живём на Иль-де-ля-Сите, но ничто не мешает найти нам высоту любой другой интересной в данный момент координаты.



Скачать Google Earth Pro сейчас можно совершенно бесплатно вот по этой ссылке:

Подключение


Подключение ну очень простое. Но в комментариях примеров прошивок строго написано:

ПОДКЛЮЧАТЬ К НАПРЯЖЕНИЮ 3,3 В! НАПРЯЖЕНИЕ +5В МОЖЕТ ВЫВЕСТИ ПРИБОР ИЗ СТРОЯ!

Думаю, к их советам лучше прислушаться, так что я не стал экспериментировать и подключил сенсор к выводу +3,3 на ардуине, мало ли.

Следующая неприятность. В библиотеке порты для подключения уже прошиты, а значит для Arduino Nano нужно подключать SDA к A4 и SCL к A5 - только так.

Ссылка на библиотеку: https://github.com/sparkfun/BMP180_Breakout_Arduino_Library

Текст прошивки


//Скетч управляет работой BMP180 и выводит на компьютер
//значения атмосферного давления и температуру

// Увы, библиотека не позволяет настраивать пины для подключения
// Вот таблица для Arduino:
// Наименование Ардино/пины: SDA  SCL
// Nano, Uno, Redboard, Pro:  A4   A5
// Mega2560, Due:             20   21
// Leonardo:                   2    3

#include <SFE_BMP180.h>
#include <Wire.h>

SFE_BMP180 pressure;

void setup() 
{
  Serial.begin(9600);
  pressure.begin();
}

void loop() 
{
  char status;
  double T,P,p0,a;

  // Перед измерением давления нужно измерить температуру
  // Если чтение температуры успешно, функция вернёт время в миллисекундах для ожидания
  // Если произошла ошибка чтения, то вернётся 0
  status = pressure.startTemperature();
  if (status != 0) // Если пришёл не 0
  {
    // Ждём пришедшее число миллисекунд
    delay(status);

    // Записываем значение температуры в T
    // Функция вернёт 1, если чтение успешно, иначе 0
    status = pressure.getTemperature(T);
    if (status != 0) // если не 0 (то есть 1)
    {
      // Вывести значение температуры
      Serial.print("Temperature: ");
      Serial.print(T,2);
      Serial.print(" *C ");
      
      // Старт измерения давления
      // Параметр в скобках от 0 до 3 (чем точнее результат, тем дольше ожидание)
      // Если запрос выполнен успешно, возвращается число миллисекунд для ожидания
      // При неудачном исполнении возвращается 0 
      status = pressure.startPressure(3);
      if (status != 0) // если не 0
      {
        // Ожидаем вернувшееся число миллисекунд до завершения измерения
        delay(status);

        // Измеряем давление
        // Значение сохраняем в P, заметим, что для измерения требуется только что полученное T
        // Если температура стабильна, можно измерить её один раз и подставлять дальше, но я бы не стал так делать
        // Функция тоже возвращает 1, если всё успешно, 0, если что-то пошло не так
        status = pressure.getPressure(P,T);
        if (status != 0) // Если не 0
        {
          // Выводим результаты измерений
          Serial.print("Atm. pressure: ");
          Serial.print(P,2); // Выводим давление
          Serial.print(" mb, "); //...в миллибарах (они же гектапаскали)
          Serial.print(P*0.750062, 2);
          Serial.println("mm Hg");

        }
        else Serial.println("error retrieving pressure measurement\n");
      }
      else Serial.println("error starting pressure measurement\n");
    }
    else Serial.println("error retrieving temperature measurement\n");
  }
  else Serial.println("error starting temperature measurement\n");

}


вторник, 24 апреля 2018 г.

Датчик влажности и температуры DHT-11

...или почему надо сначала читать о том, что покупаешь.


Заказал я из Китая очередную посылочку. Вот сегодня приехала, так что робот опять откладывается в сторону... эх, обязательно до него доберусь! На самом деле, приехало кое-что и для робота, модуль вай-фая, например, так что всё по порядку и потихоньку.

Герой дня, DHT-11
Однако, сегодня мы подключаем и разбираемся с датчиком температуры и влажности DHT-11. В планах у меня ни много ни мало - улично-балконная метеостанция. В принципе, всё приехало для неё уже... или не всё?
Присмотрел я гигро-термодатчик уже давно, а тут собирал посылку и тоже купил до кучи. Купил, и не посмотрел диапазон его измерений. Датчик и датчик. Датчик же температуры и влажности - меряет температуру и влажность - ясен пень!
Теперь вот читаю параметры и расстраиваюсь. Оказывается, что он комнатный, и измеряет температуру только до нуля градусов. Нет, ну в жарком африканском климате где-нибудь может он и за уличный сойдёт, но у меня-то тут зимой морозы случаются, снежок идёт... Ну, ладно, будем испытывать, что есть.

Колдунство с бубном над библиотеками


Библиотек к датчику оказалась тьма-тьмущая, и ни одна не захотела работать. Не буду вдаваться в описание процесса, но времени ухлопал кучу - весь вечер ушёл. Может вам повезёт больше, мне сегодня не повезло. Не компиллирует, и всё тут. Установил DHT.h - требует Adafruit_Sensor.h! Пришлось найти, скачать и скормить - угомонился, так что даю ссылки на обе.

Да, при этом Адафрут можно не подключать, как выяснилось, и так работает. Но быть она в библиотеках должна!


Подключение


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


Текст прошивки 

// Скетч управляет работой DHT-11 и выводит данные на компьютер
#include "DHT.h"
#define DHTPIN 12  // Номер пина, к которому подключаем датчик
long time_pass; // Переменная таймера
// Нужно раскомментить строку вашего датчика, у меня DHT-11
// Я оставил это из оригинального скетча, мало ли...

#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

DHT dht(DHTPIN, DHTTYPE); // Указываем параметры работы датчика
//(в скобках № пина и тип датчика)

void setup() {
  Serial.begin(9600); // Устанавливаем последовательный порт на 9600 бод
  dht.begin(); // Инициируем датчик
  time_pass = millis(); // Обнулили таймер
}
void loop() {
  float h, t, f; // влажность, температура в Цельсиях и Фаренгейтах
  // Если прошло 2 секунды между измерениями
  if ((millis() - time_pass) >= 2000)
  {
     h = dht.readHumidity(); // Читаем влажность
   t = dht.readTemperature(); // Читаем температуру в Цельсиях
   f = dht.readTemperature(true); // а так - в Фаренгейтах
   time_pass = millis(); // Снова обнулили таймер

  // Проверяем корректно ли всё прочитано, иначе - выходим
  if (isnan(h) || isnan(t) || isnan(f))
  {
    Serial.println("Ошибка чтения с сенсора!");
    return;
  }
  // Считаем температурный индекс в Фаренгейтах (по умолчанию)
  float hif = dht.computeHeatIndex(f, h);
  // А так в Цельсиях
  float hic = dht.computeHeatIndex(t, h, false);
  // Выводим всё на экран
  Serial.print("Humidity: ");
  Serial.print(h);
  Serial.print(" % ");
  Serial.print("Temperature: ");
  Serial.print(t);
  Serial.print(" *C ");
  Serial.print(f);
  Serial.print(" *F ");
  Serial.print("Heat index: ");
  Serial.print(hic);
  Serial.print(" *C ");
  Serial.print(hif);
  Serial.println(" *F");
  }
}
Вот такая жестокая схема

Итог


Вот, в принципе, и всё. Тупил я сегодня просто по-страшному, а всё потому что спешил. Но вот, всё работает. В результате получаем лог с кучей данных. Результатом я не очень доволен, кстати. Время измерения 2 секунды. Температура меняется оооочень меееедленно! 
Включил: +29. Дома +24, не больше. Ну, ок, думаю, подождём - ничего.
Ладно, подышал на него. О! Влажность подскочила до 95%! Температура +29...
Сунул под лампочку - ты смотри - подскочила до +30!
На балкон понёс, на улице подозреваю, около нуля. Открыл окно, стою проветриваюсь, прохладой так и несёт - начал остывать (в смысле датчик): +25, +24... Я думаю, околею тут, пока ты промёрзнешь. Поставил ноут со всем этим хозяйством на подоконник и пошёл на кухню. Вернулся через несколько минут - "нагрело" до +12... Мда... 

Такая вот игрушка. Серьёзно я его не воспринимаю после всего это.
Ладно, барометр у меня ещё лежит тут :) Так что до скорого, как налажу - отпишусь!

понедельник, 23 апреля 2018 г.

Шасси 2.0

Где-то далеко, убранный на полку, пылится мой робот, которого я начал собирать несколько лет назад, да так и забросил вместе с этим блогом. Временами я забывал о его существовании, временами он снова попадался мне на глаза, и меня вновь тянуло к нему вернуться. И вот... я достаю его с полки, протираю накопившуюся пыль. Я решаюсь вернуться к тому, что так давно хотел осуществить - я возвращаюсь к сборке робота!


Вот на таком варианте я решил остановиться

Эта статья будет посвящена сборке шасси. На самом деле, это как раз то, на чём я остановился. Сейчас я покажу и расскажу, что у меня есть, и на основе чего я собираюсь делать своего робота. Итак, основу от старого дисковода я решил оставить. На самом деле, это лучший корпус из всех, что мне попадался. Он удобно закрывается, в нём уже есть масса отверстий, к которым можно крепить всё, что угодно. Да и открытым при желании его тоже можно оставить. Робот будет трёхколёсным. Задняя пара колёс - приводная. За счёт неё робот будет осуществлять передвижение.

Вот так я закрепил колёса и двигатели

На стяжки и деревянные бруски я установил уже использованные мной ранее пару двигателей. Их выводы я запараллелил таким образом, чтобы двигатели вращались в одном направлении. Через зубчатую передачу я подсоединил их к колёсам. Как обычно, использую колесо с малым количеством зубьев на двигателе и с большим количеством - на оси колеса, чтобы оно крутилось быстрее. Подозреваю, что надо это чем-то смазать, чтоб пластмассу не съело, да и железку тоже.
В перспективе возможно я установлю тахометр для подсчёта числа оборотов, но пока не придумал - где и куда.

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

А так выглядит рулевое колесо

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

Внутри пока всё свободно, для крепления много места!
Вот так всё выглядит в собранном виде. Батарейный отсек крепится сверху, чтобы не занимать места и разъёмом будет подключаться к плате блока питания. По-моему, всё вполне устойчиво. Что же, попробую что-то из всего этого наконец сделать!

Шасси в собранном виде.
Всем творческих успехов!

понедельник, 16 апреля 2018 г.

Измерение скорости вращение двигателя жёсткого диска на Ардуино

Feci quod potui, faciant meliora potentes. (Латинская пословица)


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

Когда разумный предел числа проводов на макетке пройден

Принцип работы.


Основу я оставил старую, так что начало проекта можно посмотреть вот здесь:

А вот что добавил. Во-первых нужен датчик для измерения скорости. Датчик я собрал сам из двух диодов. Взял обычный белый светодиод и фотодиод. Сначала думал сделать проще: наклеил на вращающуюся часть своего двигателя кусок чёрной изоленты и направил оба диода в одну точку. Двигатель серебристый, свет отражается - падает от светодиода на фотодиод - его сопротивление тоже падает, а когда мимо них проносится изолента - сопротивление возрастает. Но как-то не понравился мне этот способ, отражённый свет не открывал фотодиод полностью, и я решил сделать диск с прорезью.
Такой вот суперколхозный сенсор. 
Осциллограмма сигнала с фотодиода
А вот уже после добавления транзистора что вышло.
Главное взять что-то твёрдое и не просвечивающее, у меня это кусок коробки из-под конфет. Диоды я примотал так, чтобы они смотрели друг на друга и между ними вращался диск. Получилась исключительно колхозная конструкция, но она работает. В момент пролёта вырезанного края между диодами напряжение на фотодиоде проседает. Проверить это лучше всего сначала мультиметром, а потом осциллографом. Без своего нового карманного осциллографа я не представляю, как бы всё это настроил. О нём я планирую отдельный пост. Как вы можете видеть на первой осциллограмме, с фотодиода мы получаем пилу с амплитудой примерно 2,5 вольта. В общем, сигнал близок к синусу, и его амплитуды у меня было не достаточно, чтобы срабатывали прерывания. Я решил это дело исправить и добавил транзистор, чтобы усилить сигнал. Поставил транзистор С945, он нормально подходит под параметры схемы. Получилось уже что-то более похожее на прямоугольный импульс, а главное - амплитуда возросла до нужных 5 вольт. Хотя тоже не очень, ещё и побочные какие-то шумы возникли. Их я решил отфильтровать ёмкостями. Поставил два конденсатора: по делителю напряжения датчика и по коллектору транзистора. Стало значительно ровнее, шум частично ушёл. Вот такой сигнал уже можно принимать. На второй осциллограмме видно, что осциллограф пишет частоту 43 герца, это слишком много для реального количества оборотов в секунду. Дело в том, что промежуточные пики тоже подсчитываются. Емкостями удалось почти избавиться от них, хотя на стадии разгона они не ушли.
Вот так получилось после добавления фильтрующих конденсаторов.
Другое дело, побочку совсем не вылечил, но считает уже нормально.
Но здесь возникли новые проблемы. двигатель (или алгоритм у меня такой) оказался очень капризный - чуть что, и останавливается - сбивается ШИМ. Я подключил для вывода числа оборотов свой LCD дисплей. Как его подключать можно посмотреть в предыдущем посте:

Так вот, даже обращение к дисплею начинало сбивать ШИМ. Особенно капризен двигатель оказался во время разгона. В результате я решил убрать подсчёт числа оборотов при разгоне вообще. Максимальную скорость тоже пришлось сократить с 1350 миллисекунд между импульсами до 1500, иначе двигатель срывался. Получившаяся скорость составила примерно 1400 оборотов в минуту. И я хотел, конечно, тоже вывести такую строчку на дисплей, что мол столько-то "O6OPOTOB/C", но лишняя строчка кода сбивала модуляцию ещё сильнее, так что я отказался от этой затеи. Ещё одна проблема - ток потребления вышел в районе 1 ампера. USB, к сожалению, с такой нагрузкой справиться не мог, да и напряжение я решил повысить до 5,8 вольт, тогда всё работало куда более стабильно. Благо, что я сделал лабораторник для таких целей, и он мне здорово помог. Но для дисплея я решил поставить стабилизатор L7805, потому что он на такое напряжение уже не рассчитан, ну и крутануть напругу на БП у меня можно вольт до 18 - Ардуинка выдержит, а дисплей жалко, решил подстраховаться. Ещё при запуске двигателя на нём начинала дрожать подсветка. Ток-то потребления большой. Так что я поставил пару конденсаторов на 1000 микрофарад - дрожание поуменьшилось. Надо бы их в сам блок поставить в перспективе.

Схема проекта (без LCD)



 Результаты и критика


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

Обороты программа подсчитывает, но как-то очень нестабильно, то их 24, то вдруг уже 30. Предполагаю, что тут надо два МК - один полноценно отвечает за разгон двигателя, второй - выводит с информацией и, вероятно, обрабатывает входящие запросы от пользователя. Я хотел ещё написать возможность регулировать обороты. Но на Ардуино Nano остался последний порт D2, к которому можно подключить прерывания, а одной кнопкой тут особо не науправляешь, особенно, когда каждая микросекунда важна для стабилизации двигателя. В общем, всё получилось как-то на соплях и не до конца. Может, я с этим ещё что-то в перспективе захочу продолжить, но пока что я этот проект закрываю. Прошивку выкладываю, вдруг кому-то что-то пригодится. Всем удачи!

Текст прошивки


// Программа запускает двигатель жёсткого диска и измеряет количество оборотов
#define P 9100 // Начальная задержка для разгона двигателя
#define x 9    // Номер пина к обмотке x
#define y 10   // Номер пина к обмотке y
#define z 11   // Номер пина к обмотке z
unsigned int p;  // Переменная задержки для разгона
long time_pass;  // Таймер
long second; // Переменная для измерения секунды
byte i = 0;  // Счётчик цикла управления фазами двигателя
volatile long Q; 
// Счётчик количества оборотов
#include <LiquidCrystal.h>
LiquidCrystal lcd(13, 12, 4, 5, 6, 7);// Подключили дисплей
void setup()
{
  p = P;// Присваиваем начальное значение задержки для разгона

Serial.begin(9600); // Открываем COM порт для дебага
pinMode(x, OUTPUT); // Установили пины, работающие с двигателем на вывод данных
pinMode(y, OUTPUT);
pinMode(z, OUTPUT);
pinMode(3, INPUT); // Устанавливаем D3 на ввод данных - на него будем подавать синусоиду от датчика вращения
digitalWrite(x, LOW); // Установили начальную фазу двигателя, можно начать с любой из 6 фаз
digitalWrite(y, HIGH);
digitalWrite(z, LOW);
digitalWrite(3, HIGH);// Установили +5V на D3 - туда подключен коллектор транзистора, ему нужны эти 5 вольт
time_pass = micros(); // Обнуление таймера
lcd.begin(16, 2); // Установили режим дисплея
lcd.print ("HA6OP O6OPOTOB"); //Ага, вот такие русские буквы :)
}
void loop()
{
    if ((i < 7) && (micros() - time_pass >= p))    // Если счётчик имеет номер от 0 до 6, и время ожидания смены фазы прошло
      {
       time_pass = micros();   // Обнуляем таймер
     if (i == 0)  { digitalWrite(z, HIGH); }      // Устанавливаем 0 или 1 в зависимости от номера фазы на нужном пине
       if (i == 2)  { digitalWrite(y, LOW);  }
       if (i == 3)  { digitalWrite(x, HIGH); }
       if (i == 4)  { digitalWrite(z, LOW);  }
       if (i == 5)  { digitalWrite(y, HIGH); }
       if (i == 6)  { digitalWrite(x, LOW);  }
   
        i++;    // Плюсуем счётчик фазы
      }
     if (i >= 7) // Если счётчик переполнен
      {
        i = 0;    // Обнуляем счётчик
        if (p > 1500) {p = p - 50;} // Если двигатель ещё не вошёл в максимальную скорость - сокращаем время смены фазы. Рекомендации: если двигатель глохнет - увеличить число 1500 или попробовать уменьшить скорость разгона - отнимать от p не по 50, а по 20 или 10.
     else // Когда разгонка двигателя закончилась
        {
         attachInterrupt(1, calc, RISING); // Настроили прерывание, когда сигнал растёт с 0 на 1 - вызываем функцию calc, 1 - это D3 по прерыванию на Arduino Nano; 0 - D2.
         if ((millis() - second) >= 1000) // Если секунда прошла
          {
            second = millis(); // обнулили таймер
            lcd.clear(); // Очистили дисплей
            lcd.print(Q); // Написали число оборотов. Думаете, я поленился дописать "O6OPOTOB/C"? Нет, у меня из-за лишней строчки слетал ШИМ и двигатель останавливался...
            Q = 0;
          }
        }
      }
   
   
}
void calc () // Вот такая мощная функция подсчёта числа оборотов
{
  Q++;
 

}


пятница, 13 апреля 2018 г.

Ремонт блока питания JTA0302D-E или пятница 13

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

Как открывать молотком, посмотреть можно здесь:


А как расклеивать ацетоном, вот тут:
















Я же открыл более агрессивным способом, потому корпус, конечно, несколько попортил. Зато быстро открыл.  Внутри оказалась весьма неплохая плата, с предохранителем, термистором, дросселем - деталей не пожалели. Всё прозвонил, ничего не сгорело, вроде всё в норме, а напряжения на выходе нет. Полез в интернет. Там нашёл статью, где про мой БП написано. Собственно, ссылку прилагаю: http://blog.amigas.ru/?p=263. (Схему БП можете посмотреть по ссылке) Автору спасибо! Без него бы, наверное, сам не дошёл. А оказалось, что в таких БП часто вылетает электролит на 47 микрофарад, похоже, пусковой для микросхемы ШИМ-контроллера. Короче, сдулся он у меня тоже. Вместо 47 Мкф показал 15 на мультиметре. Поменял, и всё заработало! Подозреваю, конечно, что остальное конденсаторное хозяйство пребывает тоже в плачевном состоянии, но остальные менять пока не стал. Работает вроде. Единственное - обратно адаптер уже просто так не собрать. Надо склеивать, а клеить мне нечем. Кстати, чем их склеивают? Отдельный вопрос - кто знает, поделитесь. Я намазал, конечно ПВА для порядку... И изолентой замотал поперёк. Вроде держит, не разваливается. Хотя, понятно, что не лучший способ сборки. Зато теперь можно размотать и разобрать в любой момент.

Вот он! Тады его в качель!
Вот такая пятница 13. ☺

понедельник, 9 апреля 2018 г.

Двигатель жёсткого диска и Ардуино. Подключение.

О двигателях и дилетантах.

Вентильный двигатель из жёсткого с четырьмя выводами.
Давно пылился у меня такой вот небольшой двигатель, который я выкорчевал из какого-то жёсткого диска. Диск, кстати, от него тоже сохранился! Если соберусь - прикручу его на следующем этапе. А пока решил просто попробовать его реанимировать. Интересен этот двигатель тем, что по идее, (как понял я - человек ничего не знавший доселе о двигателях) он является вентильным. И как нам повествует Википедия: "вентильные двигатели призваны объединить в себе лучшие качества двигателей переменного тока и двигателей постоянного тока". А за счёт отсутствия скользящих электрических контактов (так как щёточный узел заменён там на бесконтактный полупроводниковый коммутатор) такие двигатели обладают высокой надёжностью и высоким сроком службы. Далее я не стану перечислять все прочие достоинства этих двигателей и тем самым пересказывать Википедию, а просто скажу, что применение таких штуковин довольно широкое, в том числе в робототехнике, а потому захотелось узнать побольше о принципах их работы.

Принцип работы двигателя HDD.

Для управления двигателем требуется 6 фаз
на выводах МК, после чего рисунок повторяется

В двигателе три обмотки, сооединённые по принципу "звезда". Общая точка обмоток выводится на плюс. +5V для работы подходит отлично. Управляется двигатель ШИМ-сигналом, который должен подаваться на его обмотки со сдвигом фазы 120°. Однако, не получается подать нужную частоту на двигатель сразу, предварительно его нужно разогнать. Простейший способ подключить три обмотки через транзисторы, подавая ШИМ сигнал им на базу от микроконтроллера. Сразу оговорюсь по транзисторам: лучше брать полевики, потому что ток через них, похоже, идёт приличный, и биполярные сильно греются. Сначала взял 2N2222a. Нагревались за секунды, временно решил проблему установкой рядом кулера, но потом решил, что надо что-то понадёжнее, то есть побольше ☺ В результате поставил наши КТ817Г. Третьего не оказалось, вместо него у меня КТ815Г. В данной схеме их можно заменять, но КТ815 рассчитаны на постоянный коллекторный ток 1,5 ампера, а КТ817 - 3A. Замечу, что 2N2222a вообще - до 0,8A.
Схема подключения двигателя
Буква КТ81... тоже не играет роли, так как у нас всего 5 вольт. В теории, частота смены сигнала не быстрее 1 миллисекунды, реально ещё медленнее, так что высокочастотность транзисторов тоже роли не играет. В общем, подозреваю, что в данной схеме поэкспериментировать можно почти с любыми транзисторами n-p-n типа, с током коллектора хотя бы 1 ампер.
Схему прилагаю, резисторы подбирались тоже экспериментально, на 1 килоом - вполне годно работают. Ставил ещё 4,7k - это много, двигатель глох.

У двигателя 4 вывода. В начале выясняем, какой из них общий. Для этого мультиметром измеряем сопротивление между всеми выводами. Сопротивление между концами обмоток в два раза больше, чем между концом одной обмотки и общей средней точкой. Условно 4 ома против 2. Какую обмотку куда подключать - не имеет значения, они всё равно идут друг за другом.

Текст программы:

// Программа запуска двигателя жёсткого диска
#define P 9100 // Начальная задержка для разгона двигателя
#define x 9    // Номер пина к обмотке x
#define y 10   // Номер пина к обмотке y
#define z 11   // Номер пина к обмотке z
unsigned int p;  // Переменная задержки для разгона
long time_pass;  // Таймер
byte i = 0;      // Счётчик цикла управления фазами двигателя
          void setup() 
{
  p = P;// Присваиваем начальное значение задержки для разгона
 
  //Serial.begin(9600); // Открываем COM порт для дебага
  pinMode(x, OUTPUT); // Установили пины, работающие с двигателем на вывод данных
  pinMode(y, OUTPUT);
  pinMode(z, OUTPUT);
  digitalWrite(x, LOW); // Установили начальную фазу двигателя, можно начать с любой из 6 фаз
  digitalWrite(y, HIGH);
  digitalWrite(z, LOW);
  time_pass = micros(); // Обнуление таймера

}

void loop()
{

    if ((i < 7) && (micros() - time_pass >= p))    // Если счётчик имеет номер от 0 до 6, и время ожидания смены фазы прошло
      {
       time_pass = micros();   // Обнуляем таймер
       if (i == 0)  { digitalWrite(z, HIGH); }      // Устанавливаем 0 или 1 в зависимости от номера фазы на нужном пине
       if (i == 2)  { digitalWrite(y, LOW);  }
       if (i == 3)  { digitalWrite(x, HIGH); }
       if (i == 4)  { digitalWrite(z, LOW);  }
       if (i == 5)  { digitalWrite(y, HIGH); }
       if (i == 6)  { digitalWrite(x, LOW);  }
     
        i++;    // Плюсуем счётчик фазы
      }
     if (i >= 7) // Если счётчик переполнен
      {
        i = 0;    // Обнуляем счётчик
        if (p > 1350) {p = p - 50;} // Если двигатель ещё не вошёл в максимальную скорость - сокращаем время смены фазы
        //Serial.println(p); Дебаг времени ожидания
      }
 
}

Что в результате?

В результате имеем двигатель, который разгоняется за несколько секунд. Иногда разгон разбалансируется, и двигатель останавливается, но чаще всё работает. Как стабилизировать - пока не знаю. Если рукой остановить двигатель, снова он уже не запустится - нужен перезапуск программы. Измерение количества оборотов - задача для следующего проекта. Пока это максимум, который удалось из него выжать. При опускании p ниже 1350 двигатель вылетает из разгона. 9100 в начале тоже подбиралась экспериментально, можно попробовать поменять, посмотреть, что будет. Вероятно, для другого двигателя числа будут другими - мне пришлось подбирать для своего. С нагрузкой (оригинальный диск) двигатель перестаёт запускаться, так что установка на него чего-либо потребует калибровки прошивки заново. Крутится он сравнительно быстро, так что рекомендую при запуске надевать очки, особенно если на нём чего-то будет висеть в этот момент. Надеюсь продолжить с ним эксперименты. Пока это всё, всем удачи!

пятница, 6 апреля 2018 г.

Дисплей QC1602A V2.0, его подключение к Ардуино и библиотека LiquidCrystal.h


Немного лирики об Ардуино

Давно-давно заказал я из Китая пару дисплеев QC1602A, чтобы в долгосрочной перспективе что-нибудь хорошее на них собрать. Так они у меня бы и провалялись, если бы я не заинтересовался темой Ардуино. Идея этого конструктора мне ужасно понравилась, особенно когда я узнал, что в той же самой Поднебесной продаются все его недорогие аналоги и комплектующие. Так что вероятно, что ближайшие свои посты я посвящу именно Ардуино и всему тому, что на нём смогу собрать. После ассемблера и, по сути дела, самостоятельной разработки библиотек для железа, я ощутил всю прелесть программирования на C++, а также подключения уже готовых библиотек, которые добрыми руками заботливых программистов написаны чуть ли не для всего на свете. И я, в общем, в результате всей душой проникся к ардуинкам. Как знать, может ещё и разочаруюсь... но пока что - материала о них море, пишут про них (и для них тоже пишут!) все, кому не лень, так что захотелось и мне...


Итак, собственно, обзор QC1602A V2.0

Зелёный и синий, канифоль от контактов отмыл спиртом
как смог :)
Никакой рекламы и ссылок на китайские магазины в этом посте не предвидится, пишу что думаю, скорее для себя. Дисплейчики, честно говоря, посредственные, особенно по современным меркам, так что скорее подходят уже не для сборки девайсов, а для изучения самой Ардуино, потому что вывести на них пару слов несложно, а вот выводить что-то осмысленное и много - это поищите чего другое.
В моём распоряжении есть зелёная и синяя версия этого дисплея. Какой симпатяжнее - решать вам. Зелёный с чёрными буквами, синий с белыми, так что вроде повеселее, но тухнут эти буквы как-то неприятно, тоже через какой-то красно-чёрный цвет и не мгновенно, так что быстро выводить на них информацию - тоже занятие неблагодарное.
Скорее так: когда надоело выводить результат работы через Serial.println() и хочется чего-то более ощутимого - можно подключить этот дисплейчик, (на дисплей он явно как-то не тянет) но, уверен, что быстро наиграетесь. Термометр какой замутить на нём что ли...
А, да, ещё одна прекрасная особенность сего девайса - кириллицы на нём нет. Пытаемся вывести кириллицу - наслаждаемся кракозябрами. Так что только 0...9, A...Z. Ну зато маленькие и большие буквы есть и конечно знаки препинания!
Библиотека с руссификацией, как она есть.
Но не нужно отчаиваться. На просторах Интернета пишут, что на этом дисплейчике можно подключить кириллицу! Правда, не факт, что вам очень понравится этот способ, но есть библиотека LiquidCrystalRus.h, скачать её можно здесь: https://github.com/mk90/LiquidCrystalRus
Я её добросовестно скачал, и... у меня ничего не получилось. Вернее, получилось вот что:
Угадайте, что я там понаписал.
В общем, конечно, может я что-то не так сделал, но, подозреваю, что тут нужны танцы с бубном, потому я ограничусь своим скромным английским, без перевода.

Подключаем дисплей к Ардуино.

Для начала обозначу выводы, которые нельзя подключать абы куда ☺
VSS - на землю, минус питания.
VDD - плюс питания (В даташите заявлено напряжение +4,5V... +5,5V; Сознаюсь, я подал 6, но больше лучше не рисковать).
V0 - на среднюю точку потенциометра (10 килоом) - настройки яркости дисплея , при желании потенциометр потом можно заменить постоянными резисторами, если уже всё настроено, но при изменении напряжения буквы тоже начнут тускнеть!
A - через токоограничивающий резистор (я ставил 330 ом, но можно немного поменьше или побольше, главное, чтоб он был! Светодиоды не любят сидеть прямо на +5 вольтах) подключаем на напряжение питания подсветку.
K - земля питания светодиодов подсветки.

Теперь все остальные выводы. Их подключаем к ардуине, куда хотим.
RS - выбор регистра, не заморачивайтесь и вешайте на нужную ногу (например D13)
RW - чтение/запись, можно повесить на землю, о её значении написал дальше.
E - enable, тоже на любую ногу, (допустим D12)
D0 - D7 - подключайте к нужным ногам Ардуино точно также, и я рекомендую подключить только D4 - D7, а остальные четыре просто оставить в покое. (см фотку выше)


Библиотека LiquidCrystal.h

Чтобы начать работу, не забудьте подключить библиотеку LiquidCrystal.
Скачать можно по ссылке вот тут, с официального сайта:  https://playground.arduino.cc/Main/LiquidCrystal#Download
Как я уже писал, программу писать для него на C++ - одно удовольствие, но на этом оно, кажется, и заканчивается.
В начале программы подключаем библиотеку:
#include <LiquidCrystal.h>
И инициализируем дисплей по одному из предложенных синтаксисов:
LiquidCrystal lcd(rs, enable, d4, d5, d6, d7) 
LiquidCrystal lcd(rs, rw, enable, d4, d5, d6, d7)  
LiquidCrystal lcd(rs, enable, d0, d1, d2, d3, d4, d5, d6, d7)  
LiquidCrystal lcd(rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7) 
В скобках, если не догадались, прописываются номера ножек Ардуино, к которым подключены соответствующие выводы дисплея. Остался вопрос: почему 4 варианта, и какой выбрать?
Ответ: скорее всего вам пойдёт любой.
Если разобраться: rw нужен, чтобы читать/записывать символы с дисплея. Я очень сомневаюсь, что вы будете хранить в его памяти информацию, потому что памяти этой там на две строчки в несколько десятков символов, потому rw можно смело вешать на землю.
Что касается числа используемых выводов: можно использовать четыре, можно все восемь. Все мои программы работали с четырьмя выводами. 

Итак, я предлагаю подключать по такой схеме (но вы можете как угодно иначе)
LiquidCrystal lcd(12, 11, 6, 7, 8, 9); 
Далее в void setup() надо прописать количество используемых строк и длину строки, например:

void setup()
{
  lcd.begin(2,50); // Две строки длиной 50 символов
}
Это почти всё.
Осталось вывести что-нибудь на экран. Есть несколько наиболее распространённых функций, которые вызываем по мере необходимости:
lcd.print(); // В скобках указываем переменную или надпись в кавычках  
lcd.setCursor(0, 0); // Установка курсора для начала записи; формат (№ символа, № строки) 
lcd.clear(); // Очистить дисплей
Вызываем все эти функции уже внутри void loop()

Функций значительно больше, но остальными я не пользовался.
lcd.home(); // Вернуть курсор в начало.
lcd.write(data); // Записать информацию (data) на дисплей, возвращает количество записанных байт. 
lcd.cursor(); // Выводит на дисплей знак "_" - курсор. 
lcd.noCursor(); // Скрывает курсор. 
lcd.blink(); // Выводит мигающий курсор.
lcd.noBlink(); // Скрывает мигающий курсор. 
lcd.display(); // Включает дисплей с восстановлением всего, что на нём изображалось, если он был выключен функцией noDisplay(); 
lcd.noDisplay(); // Выключает дисплей без потери записанной на него информации. 
lcd.scrollDisplayLeft(); // Сдвигает надпись на дисплее влево на один символ. 
lcd.scrollDisplayRight(); // Аналогично вправо. 
lcd.autoscroll(); // Автоматически смещает надпись при вводе каждого нового символа.
lcd.noAutoscroll(); // Выключает автоматическую прокрутку дисплея. 
lcd.LeftToRight(); // Работает по умолчанию - запись символов слева направо. 
lcd.RightToLeft(); // Инвертирует порядок символов, начало теперь справа. 
lcd.createChar(num, data); // Записать собственный символ в память дисплея, всего можно записать 8: от 0 до 7. Пример:
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);     
byte smiley[8] = 
{          
 B00000,
 B10001,
 B00000,
 B00000,
 B10001,
 B01110,
 B00000,
};

void setup() 
{           
  lcd.createChar(0, smiley);
  lcd.begin(16, 2);
  lcd.write(byte(0));
}

void loop() {}
  
Ну, и напоследок - пример работающей программы

#include <LiquidCrystal.h> 
LiquidCrystal lcd (13, 12, 2, 3, 4, 5);

void setup() 
{  
       lcd.begin(16, 2);  

void loop() 
{     lcd.print("hello, world!");  
      delay(500);
      lcd.clear();
      delay(500);
}

Это всё, благодарю за внимание, надеюсь, материал окажется полезен кому-то кроме меня ☺


Ссылки:

Datasheet QC1602A: https://www.mpja.com/download/qc1602a.pdf
Ссылка на официальный сайт с библиотекой: https://www.arduino.cc/en/Reference/LiquidCrystal
Ещё мне понравилась статья на эту тему, там всё очень подробно: http://developer.alexanderklimov.ru/arduino/liquidcrystal.php#begin