Мой проект на 5110

boscar
Offline
Зарегистрирован: 15.07.2016

Добрый день, уважаемые!

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

Лирическое отступление. Некоторое время назад решил освежить свое серое вещество и занялся ардуинством. Это было... трудно! Вещество не понимало, что от него хотят и требовало пива. Но постепенно ритм наладился и стало даже получаться копировать чужие наработки и понеслась.. Рабочий стол начал обрастать проводками, платками и прочей непонятной посторонним людям фигней. Вобщем все как у всех! Очень скоро стало не хватать экранчика 1602 и выбор пал на 5110. Заказал и стал мучить его. Или он меня. То одно не устраивало, то другое. Главным критерием было наличие русского языка. Перерыл кучу инфы, в том числе и на этом форуме. В итоге родился проект, которым и хочу сейчас поделиться.

Теперь собственно к делу. По плану в проекте должны быть использованы часы DS3231, экран Nokia 5110 и цифровой датчик температуры DS18B20, а также кнопка для корректировки времени. На экран должна быть выведена информация о текущем времени, дата, день недели и температура с обоих датчиков (в DS3231 свой датчик). Вот собственно то, что получилось в итоге (пока что на столе):

Ну и сам скетч:

#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
// Software SPI (slower updates, more flexible pin options):
// pin 7 - Serial clock out (SCLK)
// pin 6 - Serial data out (DIN)
// pin 5 - Data/Command select (D/C)
// pin 4 - LCD chip select (CS)
// pin 3 - LCD reset (RST)
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);

#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress Thermometer1 = {0x28, 0xFF, 0x03, 0xAD, 0x00, 0x16, 0x01, 0x2A}; // адрес датчика DS18B20 280054B604000092

#include <DS3231.h>
DS3231 rtc(SDA, SCL);
Time q;

uint32_t ms, ms1 = 0;

void setup() {
  pinMode(8, INPUT);//Слушаем кнопку
  digitalWrite(2, HIGH); //подключаем подтягивающий резистор
  sensors.begin();
  sensors.setResolution(Thermometer1, 10);
  display.begin();
  display.clearDisplay();
  rtc.begin();
  display.cp437(true);
  display.display();
}

void printTemperature(DeviceAddress deviceAddress) {
  sensors.requestTemperatures();
  float tempC = sensors.getTempC(deviceAddress);
  display.setTextSize(1);
  display.setCursor(0, 32);
  display.print(utf8rus("Внутри :"));
  display.setCursor(47, 32);
  display.print(rtc.getTemp());
  display.setCursor(77, 32);
  display.print(utf8rus("°"));
  display.setCursor(0, 40);
  display.print(utf8rus("Cнаружи:"));
  display.setCursor(47, 40);
  display.print(tempC);
  display.setCursor(77, 40);
  display.print(utf8rus("°"));
}

void printTimeDate() {
  q = rtc.getTime();
  display.setTextSize(2);
  display.setCursor(10, 0);
  if (q.hour < 10) {
    display.print("0");
    display.setCursor(22, 0);
  }
  display.print(q.hour);
  display.setCursor(38, -3);
  display.print("_");
  display.setCursor(52, 0);
  if (q.min < 10) {
    display.print("0");
    display.setCursor(64, 0);
  }
  display.print(q.min);
  display.setTextSize(1);
  display.setCursor(37, 0);
  if (q.sec < 10) {
    display.print("0");
    display.setCursor(43, 0);
  }
  display.print(q.sec);
  display.setCursor(13, 16);
  display.println(rtc.getDateStr(FORMAT_LONG));
  if (rtc.getDOWStr(FORMAT_SHORT) == "Mon") {
    display.print(utf8rus("  Понедельник"));
  }
  if (rtc.getDOWStr(FORMAT_SHORT) == "Tue") {
    display.print(utf8rus("    Bторник"));
  }
  if (rtc.getDOWStr(FORMAT_SHORT) == "Wed") {
    display.print(utf8rus("    Cpeдa"));
  }
  if (rtc.getDOWStr(FORMAT_SHORT) == "Thu") {
    display.print(utf8rus("    Четверг"));
  }
  if (rtc.getDOWStr(FORMAT_SHORT) == "Fri") {
    display.print(utf8rus("    Пятница"));
  }
  if (rtc.getDOWStr(FORMAT_SHORT) == "Sat") {
    display.print(utf8rus("     Cуббота"));
  }
  if (rtc.getDOWStr(FORMAT_SHORT) == "Sun") {
    display.print(utf8rus("   Bоcкресенье"));
  }
}

void loop() {
  ms = millis();
  if (digitalRead(8) == LOW) {
    rtc.setTime(q.hour, q.min + 1, 0); //Сброс секунд в 0, минуты +1 (можно -1, если часы спешат)
  }
  if ( ( ms - ms1 ) > 1000 || ms < ms1 ) {
    ms1 = ms;
    printTemperature(Thermometer1);
    printTimeDate();
    display.display();
    display.clearDisplay();
  }
}

/* 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 >= 0xC0) {
      switch (n) {
        case 0xD0: {
            n = source[i]; i++;
            if (n == 0x81) {
              n = 0xA8;
              break;
            }
            if (n >= 0x90 && n <= 0xBF) n = n + 0x30;
            break;
          }
        case 0xD1: {
            n = source[i]; i++;
            if (n == 0x91) {
              n = 0xB8;
              break;
            }
            if (n >= 0x80 && n <= 0x8F) n = n + 0x70;
            break;
          }
      }
    }
    m[0] = n; target = target + String(m);
  }
  return target;
}

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

Спасибо за внимание!

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Про строки 80-100. День недели можно запрашивать силом, а не строкой и соответсвенно всё значительно упростится и по времени и по месту. В частности, все эти строки заменятся на одну.

boscar
Offline
Зарегистрирован: 15.07.2016

ЕвгенийП пишет:

Про строки 80-100. День недели можно запрашивать силом, а не строкой и соответсвенно всё значительно упростится и по времени и по месту. В частности, все эти строки заменятся на одну.

Извините я не в теме, что значит запрашивать силом?

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

boscar пишет:

Извините я не в теме, что значит запрашивать силом?

Виноват, опечатка - "числом".

boscar
Offline
Зарегистрирован: 15.07.2016

Я понял Вас. Поменял условие.

Было: 

  if (rtc.getDOWStr(FORMAT_SHORT) == "Mon")
 
Стало: 
 
   if (q.dow == 1)
 
В принципе экономия 8 байт в каждой строке. Но мне кажется, что можно ЕЩЁ упростить..
ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

boscar пишет:

Я понял Вас. Поменял условие.

Было: 

  if (rtc.getDOWStr(FORMAT_SHORT) == "Mon")
 
Стало: 
 
   if (q.dow == 1)
 
В принципе экономия 8 байт в каждой строке. Но мне кажется, что можно ЕЩЁ упростить..

Коннечно, можно. Я не помню там неделя начинается с воскресенья или понедельника, ну, допустим с воскресенья. Тогда воскресенью соответсвует 0, понедельник - 1, вторник - 2 и т.п. Допустим, также, что Вы уже прочитали день недели (числом) и присвоили его переменной dow (типа int8_t). Тогда  Вам достаточно где-то определеить массив названий дней (хоть в progmem загоняйте), а вместо строк 80-100 написать одну вот такую строку

//
// Где-то надо определить массив названий дней
//
static utf8rus days[] = {
   utf8rus("   Bоcкресенье"), utf8rus("  Понедельник"), utf8rus("    Bторник"), 
   utf8rus("    Cpeдa"), utf8rus("    Четверг"), utf8rus("    Пятница"), 
   utf8rus("     Cуббота")
};

,,,

int8_t dow = ... // запрашиваем день недели как число

,,,
// Вместо строк 80-100 пишем всего одну строку
display.print(days[dow]);

Проверьте что там чему соответствует, но идею Вы поняли. dow оказывается просто индексом в массиве и никакие if'ы вообще не нужны.

boscar
Offline
Зарегистрирован: 15.07.2016

В моем случае dow это не переменная, а часть строки, которую выдает функция времени в строке:

DS3231 rtc(SDA, SCL);
Time q;

 

Поэтому q.min - минуты, q.sec - секунды, а q.dow - DayOfWeek - день недели.

В принципе ход Ваших мыслей мне понятен, постараюсь учесть. Спасибо!

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

boscar пишет:
В моем случае dow это не переменная, а часть строки, которую выдает функция времени в строке:

Вы не поняли. 

Вам не нужно брать строку. Библиотека умеет выдавать день недели и числом тоже. Так берите число и вообще не связывайтесь со строкой.

 

boscar
Offline
Зарегистрирован: 15.07.2016

Ну вот вроде сваял нечто. Правда все сырое и вместо дня недели выводит лишь последний символ из названия букву "а" (сегодня пятница).

#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>

// Software SPI (slower updates, more flexible pin options):
// pin 7 - Serial clock out (SCLK)
// pin 6 - Serial data out (DIN)
// pin 5 - Data/Command select (D/C)
// pin 4 - LCD chip select (CS)
// pin 3 - LCD reset (RST)
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);

#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress Thermometer1 = {0x28, 0xFF, 0x03, 0xAD, 0x00, 0x16, 0x01, 0x2A}; // адрес датчика DS18B20 280054B604000092

#include <DS3231.h>
DS3231 rtc(SDA, SCL);
Time q;

uint32_t ms, ms1 = 0;

char days[7] = {
   '   Bоcкресенье', '  Понедельник', '    Bторник', '    Cpeдa', '    Четверг', '    Пятница', '     Cуббота'
};

void setup() {
  pinMode(8, INPUT);//Слушаем кнопку
  digitalWrite(2, HIGH); //подключаем подтягивающий резистор
  sensors.begin();
  sensors.setResolution(Thermometer1, 10);
  display.begin();
  display.clearDisplay();
  rtc.begin();

  display.cp437(true);
  display.display(); // show splashscreen
}

void printTemperature(DeviceAddress deviceAddress) {
  sensors.requestTemperatures();
  float tempC = sensors.getTempC(deviceAddress);
  display.setTextSize(1);
  display.setCursor(0, 32);
  display.print(utf8rus("Внутри :"));
  display.setCursor(47, 32);
  display.print(rtc.getTemp());
  display.setCursor(77, 32);
  display.print(utf8rus("°"));
  display.setCursor(0, 40);
  display.print(utf8rus("Cнаружи:"));
  display.setCursor(47, 40);
  display.print(tempC);
  display.setCursor(77, 40);
  display.print(utf8rus("°"));
}

void printTimeDate() {
  q = rtc.getTime();
  display.setTextSize(2);
  display.setCursor(10, 0);
  if (q.hour < 10) {
    display.print("0");
    display.setCursor(22, 0);
  }
  display.print(q.hour);
  display.setCursor(38, -3);
  display.print("_");
  display.setCursor(52, 0);
  if (q.min < 10) {
    display.print("0");
    display.setCursor(64, 0);
  }
  display.print(q.min);
  display.setTextSize(1);
  display.setCursor(37, 0);
  if (q.sec < 10) {
    display.print("0");
    display.setCursor(43, 0);
  }

  display.print(q.sec);
  display.setCursor(13, 16);
  display.println(rtc.getDateStr(FORMAT_LONG));
  
  display.print(days[q.dow]);

}

void loop() {
  ms = millis();
  if (digitalRead(8) == LOW) {
    rtc.setTime(q.hour, q.min + 1, 0); //Корректировка часов
  }
  if ( ( ms - ms1 ) > 1000 || ms < ms1 ) {
    ms1 = ms;
    printTemperature(Thermometer1);
    printTimeDate();
    display.display();
    display.clearDisplay();
  }
}

/* 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 >= 0xC0) {
      switch (n) {
        case 0xD0: {
            n = source[i]; i++;
            if (n == 0x81) {
              n = 0xA8;
              break;
            }
            if (n >= 0x90 && n <= 0xBF) n = n + 0x30;
            break;
          }
        case 0xD1: {
            n = source[i]; i++;
            if (n == 0x91) {
              n = 0xB8;
              break;
            }
            if (n >= 0x80 && n <= 0x8F) n = n + 0x70;
            break;
          }
      }
    }
    m[0] = n; target = target + String(m);
  }
  return target;
}

 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Во-первых непонятно, почему у Вас days char, а не utf8rus  как раньше.

Во-вторых, даже если char, так описывайте его правильно

не

char days[7] = {
   '   Bоcкресенье', '  Понедельник', '    Bторник', '    Cpeдa', '    Четверг', '    Пятница', '     Cуббота'
};

а

char * days[] = {
   "   Bоcкресенье", "  Понедельник", "    Bторник", "    Cpeдa", "    Четверг", "    Пятница", "     Cуббота"
};

это же строки, а не отдельные символы.

boscar
Offline
Зарегистрирован: 15.07.2016

Спасибо за замечание Евгений. Все заработало. И (ровно килобайт) 500 байт памяти высвобождено.

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

boscar пишет:

Спасибо за замечание Евгений. Все заработало. И (ровно килобайт) 500 байт памяти высвобождено.

:)

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

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

По поводу вывода нуля перед числом менее 10

//вместо
display.setCursor(10, 0);
if (q.hour < 10) {
  display.print("0");
  display.setCursor(22, 0);
}
display.print(q.hour);

//написать функцию
void printSc (uint8_t x, uint8_t y, uint8_t sze, uint8_t numb){
  //(координата x, координата y, размер шрифта, само число)
  display.setTextSize(sze);
  display.setCursor(x, y);
  if (numb < 10) {
    display.print("0");
    display.setCursor(x+12, y);
  }
  display.print(numb);
}

//вместо строк 60-90 будет
void printTimeDate() {
  q = rtc.getTime();
  printSc (10,0,2,q.hour);
  display.setCursor(38, -3);
  display.print("_");
  printSc (52,0,2,q.min);
  printSc (37,0,1,q.sec); 
  display.setCursor(13, 16);
  display.println(rtc.getDateStr(FORMAT_LONG));
  display.print(days[q.dow]);
}

 

boscar
Offline
Зарегистрирован: 15.07.2016

yul-i-an пишет:

По поводу вывода нуля перед числом менее 10

Спасибо большое, как говорится В самую дырочку! И поучительно конечно же. Минус еще 100 байт.

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

boscar пишет:

yul-i-an пишет:

По поводу вывода нуля перед числом менее 10

Спасибо большое, как говорится В самую дырочку! И поучительно конечно же. Минус еще 100 байт.

Можно такуюже функцию написать и для вывода дней недели и т.п.

Arkanoid
Offline
Зарегистрирован: 27.02.2017

Друзья подскажите если вместо DS18B20 заюзать LM35 (я понимаю что они разные, первый цифровой , второй аналог) что в скетче поменять нужно?

yucan
Offline
Зарегистрирован: 20.04.2015

Прикрутите датчик давления для полноты информации о погоде!

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

а теперь выкинь ардуину и часы, бери время с ntp, вместо ардуины esp8266. ну это как дальнейшее развитие проекта

MaksVV
Offline
Зарегистрирован: 06.08.2015

Автор, а где финальная версия скетча?

boscar
Offline
Зарегистрирован: 15.07.2016

MaksVV пишет:

Автор, а где финальная версия скетча?

Да не будет финальной, этот проект был как баловство и процесс самообучения. Позже еще прикрутил датчик газа MQ-135, убедился в его неэффективности. Хотя проект до сих пор рука не поднимается разобрать. Кароче забросил)))

bulat943
Offline
Зарегистрирован: 19.09.2016

удалил

MaksVV
Offline
Зарегистрирован: 06.08.2015

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

boscar
Offline
Зарегистрирован: 15.07.2016

Оптимизация в коде присутствует, но чисто косметическая. А так да - работает.

UR5VHW
Offline
Зарегистрирован: 26.01.2018

Попробовал скомпелировать исходный код, получил;

DS3231 rtc(SDA, SCL)

no matching function for call to 'DS3231::DS3231(const uint8_t&, const uint8_t&)'

 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Принято к сведению.

Если появятся вопросы, не стесняйтесь, спрашивайте.

UR5VHW
Offline
Зарегистрирован: 26.01.2018

Евгений П спасибо что оперативно откликнулись. Я думал тема уже не рабочая, попробовал и неожиданно быстро получил ответ. С тринадцати лет занимаюсь электроникой, сделал много конструкций в том числе три транзистортестера на разных контроллерах, а вот на ардуино еще не пробовал. Конструкция понравилась своей гибкостью, поменял скетч, периферию и уже другой аппарат. Здесь понравилась картинка с первого поста, ардуино есть Mega 2560, дисплей есть, датчики есть. Взял код тоже с первого поста и сразу же облом, а в программировании знаю только как прошить контролер. Может потихоньку как-нибудь со временем разберусь что к чему, хотя в 66 лет оперативка уже не та.  

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

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

boscar
Offline
Зарегистрирован: 15.07.2016

вот эта бибилиотека 

https://vk.com/doc428336442_461456678

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

UR5VHW
Offline
Зарегистрирован: 26.01.2018

Спасибо boscfr, что откликнулись, установил Вашу библиотеку все, ожило, но снова застопорилось теперь выглядит так:

display.cp437(true);        'class Adafruit_PCD8544' has no member named 'cp437'

По-моему, опять не достает какой-то библиотеки с серии PCD8544. Перерыл весь интернет понаскачивал и установил кучу библиотек для 5110, не помогает.

boscar
Offline
Зарегистрирован: 15.07.2016

этих адафруитов развелось куча))

лови: https://vk.com/doc428336442_461460117

UR5VHW
Offline
Зарегистрирован: 26.01.2018

Совершенно верно. У меня такая уже стояла, установил Вашу с заменой файлов и все скампилировалось. Спасибо. Буду игратся дальше.