Умные Часы-Метеостанция на lcd1602 и lcd nokia 5110. Адаптивная подсветка. От чайника для чайников.
- Войдите на сайт для отправки комментариев
Привет всем форумчанинам! Хочу рассказать о своём мега полезном изобретении умные часы-метеостанция. Небольшая лирическая вставка: это мой первый пост на форуме arduino.ru и это мой первый реальный проект с микроконтроллером Arduino, создавая который я осваивал самые азы техчасти и программирования этой платформы. Если где и накосячил, предварительно я вас ввёл в курс дела. Текста будет достаточно.
При необходимости откройте изображение и рассмотрите.
Теперь о самом проекте. Основный функции – отображение текущего времени, числа, месяца, дня недели, считывание и отображение информации с метеодатчика BME280 (температура и влажность воздуха, атмосферное давление, высота над уровнем моря), и самое интересное, полное ДУ с пульта. Второстепенные функции – таймер, будильник, "ежечасовой звон" (прямо как в старых часах :) ). Из полезных фишек реализована адаптивная подсветка lcd через фоторезистор. Я не стал метеостанцию консервировать в корпус, оставил в "сыром виде", поскольку хочу ещё доработать и что-то реализовать. Код представлю в самом конце поста.
Комплектующие. Arduino Nano, rtc ds1307, bme280 5v (но питаю от 3.3v, диапазон позволяет от 2v до 5v), фоторезистор, сенсорная кнопка tt223, IR приёмник, IR пульт, пьезопищалка, 6 резисторов 1кОм. В моём случае lcd 1602 и lcd nokia 5110 (используется только один из них, или один, или второй, поскольку не хватает памяти arduino nano или моего опыта, тут уж не знаю :-) )
Подключение. Всё подключается довольно просто. LCD 1602, BME280 и RTC работают посредством шины I2C (SDL и SDA подключены к A4 и A5). Нюанс, мой lcd nokia подключается VCC к 3.3v, а LIGH и GND к массе. Почему так, я не знаю, но иначе не работает. Остальные 5 пинов подключаем к цифровым пинам arduino через резисторы 1кОм (чтобы lcd прожил больше, используйте 10кОм).
Касательно кнопки. Если хотите, можно использовать традиционную кнопку заместо сенсорной, код останется таким же, но необходимо будет активировать встроенный в микроконтроллер резистор 20кОм через функцию INPUT_PULLUP. Схем в интернете море, выбирайте любую, какая подойдёт.
Ардуино питается от 5v через шилд блока питания (YwRobot 545043), который устанавливается на макетную плату и может выдавать 5v и 3.3v (управляется перемычками, на фото выше видно). От него же питаются датчики и модули, которые требуют 5v или 3.3v.
Немного об адаптивной подсветке. Сам долго реализовывал данную функцию из-за незнания, поэтому расскажу что к чему. Сначала подключаем фоторезистор к аналоговому входу арудино по схеме ниже. Далее подключаем подсветку lcd 1602 к любому (в моём случае кроме 9го и 10го, шим сигнал почему не выдавал) цифровому пину с ШИМом. Ардуино будет считывать сигнал с фоторезистора в диапазоне от 0 до 1024, делить полученный результат на 4, а посылать сигнал на цифровой пин через analogWrite в диапазоне от 0 до 255. Выше значение, ярче подсветка lcd. Код приведён ниже (нашёл его на этом же форуме). НО, если вдруг вы не хотите делать адаптивной подсветку, я сделал в проекте функцию управления подсветкой через пульт ДУ !
int PhCount = analogRead(7); PhCount = PhCount/4; if(PhCount > 255){ analogWrite(led, 255); } else { if(PhCount < 40){ //минимальный уровень подсветки 40 analogWrite(led, 40); } else { analogWrite(led, PhCount); } }
Видеоролики, где продемонстрировал работу метеостанции на lcd1602:
Переключение трёх главных экранов посредством сенсорной кнопки. Реагирует даже на пинцет :)
https://www.youtube.com/watch?v=VOcS7plSyMo
Управление станцией с пульта и демонстрация будильника. Будильник настраивается только через код, для меня оптимально. Можно запрограммировать несколько пультов, даже с телефона можно управлять, если есть ИК порт. Функции пульта следующие: полная перезагрузка ардуино (также выполняется автоматически каждый день в 0:00, можно отключить в коде), вкл/выкл подсветки одной кнопкой, циклическое переключение экранов. Я нажимал vol- и vol+. Эти кнопки регулируют степень яркости подсветки в ручном режиме. Всего 4 степени яркости. Не работало, поскольку в моём случае адаптивная подсветка. Опять таки, можно настроить в коде (старался всё комментировать). Кнопка 1 и 2 включают готовый таймер на 20сек и 5сек.
https://www.youtube.com/watch?v=QnAv5LAsyiw
Также реализовал автоматическое переключение на главный циферблат, если на каком-то и зкранов застрял более чем на 30сек. Все экраны постарался проработать до мелочей. Однако недочёты есть, из буду по возможности исправлять. Забыл заснять момент ежечасового звона... он такой же как и будильник, но воспроизводится каждый час... Мне нравится, я и сделал.
Демонстрация работы на LCD nokia 5110 (84x48):
Экран здесь всего один, зато на нём помещается всё. Циферблат содержит секунды. Дата, дни недели на русском (здесь тоже свои нюансы, напишу пост об этом позже), и те же значения с датчика bme280, тоже на русском. Конкретно для этого дисплея реализовал предупреждение при повышенной влажности в помещении (более 70%). Для меня это важно, однако, повторюсь, в коде всё описано, можно выключить. Также реализован будильник. НО нет ежечасового звона... Также нет управления с пульта, потому что здесь это не нужно (пока что), и нет адаптивной подсветки, поскольку подсветка и без того тусклая. Есть миниатюры при звуковых сигналах. Опять таки, постарался все мелочи проработать. Ниже фото и видео.
https://www.youtube.com/watch?v=c69bZxvqBRg
Как вы поняли, по итоги в этом проекте две прошивки. Одна для lcd1602, вторая для nokia lcd. Они практически одинаковы, в каждой свои особенности. Сделано это было как для себя, так и для расширения проекта.
Прошивка для lcd1602:
#include <Adafruit_Sensor.h> #include <Adafruit_BME280.h> #define SEALEVELPRESSURE_HPA (1013.25) Adafruit_BME280 bme; #include "IRremote.h" #include <Wire.h> #include "RTClib.h" #include <LiquidCrystal_I2C.h> RTC_DS1307 rtc; LiquidCrystal_I2C lcd(0x3F,16,2); //ИК приемник IRrecv irrecv(A0); // указываем пин, к которому подключен IR приемник decode_results results; 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; int flag=0; int piezoPin = 12; char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; int regim =1; int regim_1 =1; int regim_2 =1; int led = 6; #define BTN 2 unsigned long timing; void setup() { pinMode(led, OUTPUT); pinMode(BTN, INPUT); pinMode(piezoPin, OUTPUT); pinMode(A0, INPUT); //логика ик приемника pinMode(11, OUTPUT); //питание ик приемника digitalWrite(11, HIGH); rtc.begin(); lcd.init(); // initialize the lcd lcd.backlight(); lcd.home(); analogWrite(led, 254); Serial.begin(9600); // подключаем монитор порта Wire.begin(); irrecv.enableIRIn(); // запускаем прием инфракрасного сигнала bme.begin(0x76); // запускаем приём ифнормации с датчика через i2c 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(* resetFunc) (void) = 0; //функция перезагрузки arduino void loop() { //Функция перезагрузки arduino каждый день в 00:00:00 DateTime now = rtc.now(); if (now.hour() == 0 && now.minute() == 00 && now.second() == 00) { lcd.clear(); lcd.setCursor(0,0); lcd.print("Reboot device.."); delay(1000); lcd.clear(); resetFunc(); } int PhCount = analogRead(7); PhCount = PhCount/4; if(PhCount > 255){ analogWrite(led, 255); } else { if(PhCount < 40){ //минимальный уровень подсветки 40 analogWrite(led, 40); } else { analogWrite(led, PhCount); } } //управление с пульта на ИК приёмник if (irrecv.decode(&results)) { // если данные пришли выполняем команды Serial.println(results.value); //для вывода в монитор порта значений с ИК приёмника //Переключение экранов с пульта if(results.value == 59415 || results.value == 16769565) { regim++; tone(piezoPin, 200, 50); lcd.clear(); //это нужно для того что бы с каждым нажатием кнопки //происходило только одно действие // плюс защита от "дребезга" 100% if(regim>3)//ограничим количество режимов { regim=1;//так как мы используем только одну кнопку, // то переключать режимы будем циклично } } //управление степенью якркости подсветки LCD //одна кнопка увеличить яркость, вторая - уменьшить if(results.value == 58395 || results.value == 16748655){ //увеличить regim_2++; if(regim_2>4)//ограничим количество режимов { regim_2=4; } if(regim_2==1) { analogWrite(led, 20); } if(regim_2==2) { analogWrite(led, 100); } if(regim_2==3) { analogWrite(led, 200); } if(regim_2==4) { analogWrite(led, 255); } } if(results.value == 43095 || results.value == 16754775){ //уменьшить regim_2--; if(regim_2<1)//ограничим количество режимов { regim_2=1; } if(regim_2==1) { analogWrite(led, 20); } if(regim_2==2) { analogWrite(led, 100); } if(regim_2==3) { analogWrite(led, 200); } if(regim_2==4) { analogWrite(led, 255); } } //управление подсветкой lcd //При нажатии кнопки на пульте - выкл или вкл подсветку if(results.value == 5355 || results.value == 16736925){ //кнопка1 в формате DEC regim_1++; if(regim_1>2)//ограничим количество режимов { regim_1=1; } if(regim_1==1) { //режим 1 - lcd on lcd.clear(); lcd.setCursor(4,0); lcd.print("LCD on"); tone(piezoPin, 900, 50); delay(500); tone(piezoPin, 900, 50); lcd.backlight(); //вкл delay(500); lcd.clear(); } if(regim_1==2) { //режим 2 - lcd off lcd.clear(); lcd.setCursor(4,0); lcd.print("LCD off"); tone(piezoPin, 900, 50); delay(500); tone(piezoPin, 900, 50); lcd.noBacklight(); //выкл delay(500); lcd.clear(); } } //Таймер №1 по нажатию на выбранную кнопку с пульта if(results.value == 4335 || results.value == 16724175) { //выбранная кнопка lcd.clear(); lcd.setCursor(2,0); lcd.print("Timer 20s on"); lcd.setCursor(6,1); lcd.print("...."); tone(piezoPin, 900, 50); delay(20000); //засекаем таймер lcd.clear(); lcd.setCursor(4,0); lcd.print("Time out!"); //время вышло! lcd.setCursor(6,1); lcd.print("...."); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(500); lcd.clear(); delay(300); lcd.setCursor(4,0); lcd.print("Time out!"); lcd.setCursor(6,1); lcd.print("...."); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(500); lcd.clear(); delay(300); lcd.setCursor(4,0); lcd.print("Time out!"); lcd.setCursor(6,1); lcd.print("...."); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(500); lcd.clear(); delay(300); } //Таймер №2 по нажатию на выбранную кнопку с пульта if(results.value == 36975 || results.value == 16718055) { //выбранная кнопка lcd.clear(); lcd.setCursor(2,0); lcd.print("Timer 5s on"); lcd.setCursor(6,1); lcd.print("...."); tone(piezoPin, 900, 50); delay(5000); //засекаем таймер lcd.clear(); lcd.setCursor(4,0); lcd.print("Time out!"); //время вышло! lcd.setCursor(6,1); lcd.print("...."); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(500); lcd.clear(); delay(300); lcd.setCursor(4,0); lcd.print("Time out!"); lcd.setCursor(6,1); lcd.print("...."); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(500); lcd.clear(); delay(300); lcd.setCursor(4,0); lcd.print("Time out!"); lcd.setCursor(6,1); lcd.print("...."); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(200); tone(piezoPin, 900, 100); delay(500); lcd.clear(); delay(300); } //перезагрузка устр-ва по нажатию на кнопку пульта if(results.value == 25755 || results.value == 16753245) { lcd.clear(); lcd.setCursor(0,0); lcd.print("Reboot device..."); delay(1000); lcd.clear(); resetFunc(); } irrecv.resume(); } if(digitalRead(BTN)==HIGH&&flag==0) { tone(piezoPin, 200, 50); } if(digitalRead(BTN)==HIGH&&flag==0)//если кнопка нажата // и перемення flag равна 0 , то ... { regim++; flag=1; lcd.clear(); //это нужно для того что бы с каждым нажатием кнопки //происходило только одно действие // плюс защита от "дребезга" 100% if(regim>3)//ограничим количество режимов { regim=1;//так как мы используем только одну кнопку, // то переключать режимы будем циклично } } if(digitalRead(BTN)==LOW&&flag==1)//если кнопка НЕ нажата //и переменная flag равна - 1 ,то ... { flag=0;//обнуляем переменную "BTN" } //Автоматическое переключение на главнй экран с циферблатом, если где-то в меню застрял > 40 секунд if (regim == 1 && millis() - timing > 40000) { //если режим ВТОРОЙ timing = millis(); lcd.clear(); regim=2; } if (regim == 3 && millis() - timing > 40000) { //если режим ТРЕТИЙ timing = millis(); lcd.clear(); regim=2; } if(regim==2)//ПЕРВЫЙ режим { digitalClockDisplay(); delay(100); //мигание временем каждый час (с 10 до 22, указывается в void digitalClockDisplay()) DateTime now = rtc.now(); if (now.hour() >= 10 && now.hour() <= 22 && now.minute() == 00 && now.second() >= 00 && now.second() < 10 ) { digitalClockDisplay(); delay(600); lcd.clear(); delay(600); } //мигание временем во время сигнала будильника (указывается в void digitalClockDisplay()) if (now.dayOfTheWeek() >= 1 && now.dayOfTheWeek() <= 7 && now.hour() == 14 && now.minute() == 20 && now.second() >= 00 && now.second() < 15) { digitalClockDisplay(); delay(600); lcd.clear(); delay(600); } //оставляем точки статическими при ежечасовом звоне и будильнике (при мигании циферблата) if (now.hour() >= 10 && now.hour() <= 22 && now.minute() == 00 && now.second() >= 00 && now.second() < 10 ) { lcd.setCursor(7,0); //оставляем точки разделители статическими lcd.print("."); // lcd.setCursor(7,1); // lcd.print("."); // } if (now.dayOfTheWeek() >= 1 && now.dayOfTheWeek() <= 7 && now.hour() == 14 && now.minute() == 20 && now.second() >= 00 && now.second() < 15) { lcd.setCursor(7,0); //оставляем точки разделители статическими lcd.print("."); // lcd.setCursor(7,1); // lcd.print("."); // } //мигание двух точек, которые разделяют час и минуты //можно изменить положение на 8 символ //нечётное - точки if(now.second() == 1 || now.second() == 3 || now.second() == 5 || now.second() == 7 || now.second() == 9 || now.second() == 11 || now.second() == 13 || now.second() == 15 || now.second() == 17 || now.second() == 19 || now.second() == 21 || now.second() == 23 || now.second() == 25 || now.second() == 27 || now.second() == 29 || now.second() == 31 || now.second() == 33 || now.second() == 35 || now.second() == 37 || now.second() == 39 || now.second() == 41 || now.second() == 43 || now.second() == 45 || now.second() == 47 || now.second() == 49 || now.second() == 51 || now.second() == 53 || now.second() == 55 || now.second() == 57 || now.second() == 59 ) { lcd.setCursor(7,0); lcd.print("."); lcd.setCursor(7,1); lcd.print("."); } //четное - пробелы if(now.second() == 2 || now.second() == 4 || now.second() == 6 || now.second() == 8 || now.second() == 10 || now.second() == 12 || now.second() == 14 || now.second() == 16 || now.second() == 18 || now.second() == 20 || now.second() == 22 || now.second() == 24 || now.second() == 26 || now.second() == 28 || now.second() == 30 || now.second() == 32 || now.second() == 34 || now.second() == 36 || now.second() == 38 || now.second() == 40 || now.second() == 42 || now.second() == 44 || now.second() == 46 || now.second() == 48 || now.second() == 50 || now.second() == 52 || now.second() == 54 || now.second() == 56 || now.second() == 58 ) { lcd.setCursor(7,0); lcd.print(" "); lcd.setCursor(7,1); lcd.print(" "); } } if(regim==3)// ВТОРОЙ режим { if(millis()-timing>=500) { DateTime now = rtc.now(); //printDigits(now.day(), DEC); если что //printDigits(now.month(), "digits"); lcd.setCursor(5,0); if(now.day() < 10) { lcd.print("0"); } lcd.print(now.day()); lcd.print("."); if(now.month() < 10) { lcd.print("0"); } lcd.print(now.month()); //расположение дней недели на экране, пн - вт, чт - вс -- на 4 символе, если ср, то на 3 символе if(now.dayOfTheWeek() == 1 || now.dayOfTheWeek() == 2 || now.dayOfTheWeek() == 4 || now.dayOfTheWeek() == 5 || now.dayOfTheWeek() == 6 || now.dayOfTheWeek() == 7) { lcd.setCursor(4,1); lcd.print(daysOfTheWeek[now.dayOfTheWeek()]); } if(now.dayOfTheWeek() == 3) { lcd.setCursor(3,1); lcd.print(daysOfTheWeek[now.dayOfTheWeek()]); } timing=millis(); } } if(regim==1)//ТРЕЙТИЙ режим { if(millis()-timing>=500) { lcd.setCursor(0, 0); lcd.print(round(bme.readTemperature())); lcd.print("'C"); //определение температуры, вывод ее на экран в градусах Цельсия. lcd.setCursor(6, 0); lcd.print(round(bme.readAltitude(SEALEVELPRESSURE_HPA))); lcd.print("m"); lcd.setCursor(13, 0); lcd.print(round(bme.readHumidity())); lcd.print("%"); lcd.setCursor(0, 1); lcd.print(round(bme.readPressure()*0.0075)); lcd.print(" mm.rt.st."); //определение давления, вывод его на экран timing=millis(); } } } 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); //Будильник №1 //День недели начала - день конца/час/минута/секунда начала - секунда конца звона if (now.dayOfTheWeek() >= 1 && now.dayOfTheWeek() <= 7 && now.hour() == 14 && now.minute() == 20 && now.second() >= 00 && now.second() < 15) { tone(piezoPin, 120, 400); delay(800); tone(piezoPin, 300, 400); delay(800); tone(piezoPin, 550, 400); delay(800); tone(piezoPin, 450, 400); delay(800); tone(piezoPin, 300, 400); delay(800); tone(piezoPin, 120, 400); } //ежечасовой звон, час начала - час конца, минута начала, секунда начала и секунда конца if (now.hour() >= 10 && now.hour() <= 22 && now.minute() == 00 && now.second() >= 00 && now.second() < 5 ) { tone(piezoPin, 120, 400); delay(800); tone(piezoPin, 300, 400); delay(800); tone(piezoPin, 550, 400); delay(800); tone(piezoPin, 450, 400); delay(800); tone(piezoPin, 300, 400); delay(800); tone(piezoPin, 120, 400); lcd.setCursor(7,0); //оставляем точки разделители статическими lcd.print("."); // lcd.setCursor(7,1); // lcd.print("."); // } //секунды на главном экране //lcd.setCursor(7, 1); //lcd.print(now.second()/10); //lcd.print(now.second()%10); } 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; } }
Прошивка для nokia lcd:
#include <Adafruit_I2CDevice.h> #include <Adafruit_GFX.h> #include <Adafruit_PCD8544.h> Adafruit_PCD8544 display = Adafruit_PCD8544(3, 4, 5, 7, 8); #include <Wire.h> #include "RTClib.h" RTC_DS1307 rtc; #include <Adafruit_Sensor.h> #include <Adafruit_BME280.h> #define SEALEVELPRESSURE_HPA (1013.25) Adafruit_BME280 bme; uint32_t ms, ms1 = 0; #define BTN 2 int piezoPin = 12; int regim=1; int flag=0; const unsigned char PROGMEM smileBmp[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; const unsigned char PROGMEM clockBmp[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x1f, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0f, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; void setup() { pinMode(piezoPin, OUTPUT); pinMode(BTN, INPUT); Serial.begin(9600); // подключаем монитор порта bme.begin(0x76); // запускаем приём ифнормации с датчика через i2c rtc.begin(); Wire.begin(); display.begin(); display.clearDisplay(); display.display(); display.setContrast(50); // установка контраста delay(1000); display.setTextSize(1); // установка размера шрифта display.setTextColor(BLACK); // установка цвета текста //rtc.adjust(DateTime(__DATE__, __TIME__)); } void digitalClock() { ms = millis(); if ( ( ms - ms1 ) > 1000 || ms < ms1 ) { ms1 = ms; display.display(); display.clearDisplay(); } DateTime now = rtc.now(); display.setTextSize(2); if(now.hour() < 10) { display.setCursor(11, 0); display.println("0"); display.setCursor(23,0); display.println(now.hour()); } if(now.hour() >= 10) { display.setCursor(11,0); display.println(now.hour()); } if(now.minute() < 10) { display.setCursor(51,0); display.println("0"); display.setCursor(63,0); display.println(now.minute()); } if(now.minute() >= 10) { display.setCursor(51,0); display.println(now.minute()); } //будильник №1 if (now.dayOfTheWeek() >= 1 && now.dayOfTheWeek() <= 7 && now.hour() == 14 && now.minute() == 28 && now.second() >= 00 && now.second() < 20) { display.drawBitmap(0, 0, clockBmp, 84, 44, BLACK); tone(piezoPin, 120, 400); delay(800); tone(piezoPin, 300, 400); delay(800); tone(piezoPin, 550, 400); delay(800); tone(piezoPin, 450, 400); delay(800); tone(piezoPin, 300, 400); delay(800); tone(piezoPin, 120, 400); } display.setCursor(37, 3); display.println("-"); display.setTextSize(1); if(now.second() < 10) { display.setCursor(37,0); display.println("0"); display.setCursor(43,0); display.println(now.second()); } if (now.second() >= 10){ display.setCursor(37,0); display.println(now.second()); } if (now.day() < 10) { display.setCursor(28, 16); display.println("0"); display.setCursor(34, 16); display.println(now.day()); } if (now.day() >= 10) { display.setCursor(28, 16); display.println(now.day()); } display.setCursor(40, 16); display.println("."); if(now.month() < 10){ display.setCursor(46, 16); display.println("0"); display.setCursor(52, 16); display.println(now.month()); } if(now.month() >= 10) { display.setCursor(46, 16); display.println(now.month()); } if(now.dayOfTheWeek() == 1){ display.setCursor(11, 23); display.println(utf8rus("Понедельник")); } if(now.dayOfTheWeek() == 2){ display.setCursor(22, 23); display.println(utf8rus("Вторник")); } if(now.dayOfTheWeek() == 3){ display.setCursor(27, 23); display.println(utf8rus("Среда")); } if(now.dayOfTheWeek() == 4){ display.setCursor(21, 23); display.println(utf8rus("Четверг")); } if(now.dayOfTheWeek() == 5){ display.setCursor(21, 23); display.println(utf8rus("Пятница")); } if(now.dayOfTheWeek() == 6){ display.setCursor(21, 23); display.println(utf8rus("Суббота")); } if(now.dayOfTheWeek() == 7){ display.setCursor(11, 23); display.println(utf8rus("Воскресенье")); } display.setCursor(0, 32); display.print(round(bme.readTemperature())); display.println(utf8rus("'C")); //определение температуры, вывод ее на экран в градусах Цельсия. display.setCursor(34, 32); display.print(round(bme.readAltitude(SEALEVELPRESSURE_HPA))); display.println(utf8rus("м")); if(bme.readHumidity() > 70) { tone(piezoPin, 200, 100); delay(200); tone(piezoPin, 200, 100); delay(200); display.setCursor(65, 32); display.print(round(bme.readHumidity())); display.println("%"); //display.setCursor(72, 15); //display.setTextSize(2); //display.print("!"); display.drawBitmap(0, 0, smileBmp, 84, 44, BLACK); } if(bme.readHumidity() < 70) { display.setCursor(65, 32); display.print(round(bme.readHumidity())); display.println("%"); } display.setTextSize(1); display.setCursor(0, 40); display.print(round(bme.readPressure()*0.0075)); display.println(utf8rus(" мм.рт.ст.")); //определение давления, вывод его на экран delay(1000); } void loop() { digitalClock(); } /* Recode russian fonts from UTF-8 to Windows-1251 */ String utf8rus(String source) { int i,k; String target; unsigned char n; char m[2] = { '0', '\0' }; k = source.length(); i = 0; while (i < k) { n = source[i]; i++; if (n >= 0xBF){ switch (n) { case 0xD0: { n = source[i]; i++; if (n == 0x81) { n = 0xA8; break; } if (n >= 0x90 && n <= 0xBF) n = n + 0x2F; break; } case 0xD1: { n = source[i]; i++; if (n == 0x91) { n = 0xB7; break; } if (n >= 0x80 && n <= 0x8F) n = n + 0x6F; break; } } } m[0] = n; target = target + String(m); } return target; }
Отдельные кусочки кода были взяты откуда-то или написаны мной. Не претендую на перфекционизм !! :)))
На этом, думаю, пост можно закончить. Изложил все свои мысли по этому поводу. Хотелось бы услышать ваше мнение. Если вам был интересно, следите за моими постами, будет полезно для таких же новичков, как и я.
Это не нужно, такой символ в LCD1602 имеется, его код - 255. Я тоже брал этот код для часов на таком дисплее, но с переделками, шрифт получился чуть красивее. Ну и по результатам критики отрисовку цифр переделал. В использованном вами коде она демонстрационная и, соответственно, слишком раздутая.
Код мигания двоеточия на 70 строк - это жесть ))) Проверка числа на четность делается делением на 2 - если остаток равен нулю, значит четное и наоборот. И код получается примерно таким:
За мигания точек спасибо! В 10 раз меньше, исправлю
Насчёт символа.. Это уже мелочное... Шрифт меня не напрягает, пойдёт
Насчёт символа.. Это уже мелочное... Шрифт меня не напрягает, пойдёт
Собственно, дело не в шрифте, а в отрисовке цифр
Заменил код мигания точек на ваш код, выдаёт следующую ошибку в терминал:
warning - это не ошибка. Код работает?
Да, но вместо точек непонятные символы
Уже починил. Просто поменял на const char* и переместил в void digitalClockDisplay()
Всегда считал, что константы изменению не подлежат ))
На самом деле да, мой косяк по незнанию - просто символы нужно было задавать в одиночных кавычках
Нет, код получается примерно таким:
Нет, код получается примерно таким:
Сходу под дых? ))))
Сходу под дых? ))))
Чойта?
Человек с простой арифметикой не сообразил, а ты ему битовыми операциями ))
Так пусть учится. Код не смотрел, но судя по стилю изложения, автору лет 15... В этом возрасте еще не поздно узнавать новое :)