Oled часы с выводом температуры на Arduino своими руками.
Я
люблю разрабатывать различные
часы на
Arduino
. Свои первые часы делал на сдвиговых регистрах, светодиодах и Arduino. Вторая
версия
светодиодных часов уже была
сделана
на
адресных светодиодах (данные часы
до сих пор работают и висят у меня в
коридоре). С
ребёнком делали
часы из Лего, семисегментного
индикатора и digispark. Последние, четвёртые,
реализованы на Arduino и дисплее Nextion. Подписчики написали
мне, что часы
получаются
достаточно дорогие и собирать их
нецелесообразно. Согласен,
что
дисплей Nextion дорогой, поэтому
решил
собрать
часы на OLED дисплее и Arduino.
Электронную
часть OLED часов собрал на макетной плате
вот по такой схеме.
Описание
работы часов OLED часы на Arduino.
Часы
имеют стандартный функционал. Вывод
текущего дня недели, даты, времени и
температуры. Две тактовые кнопки помогают
нам настраивать дату и время.
Как
видим,
дни
недели у нас выводятся
на русском языке.
Вы скажете,
что в интернете достаточно много проектов
с данным дисплеем и с выводом информации
на русском языке. Да, так оно и есть,
информации
много, но в 90% случаев русские
буквы
выводятся
с помощью перекодировки символов. И
просматривая код непонятно, какое
слово будет
на дисплее.
В данном примере русский текст прописан
в коде в точно таком же виде, как он
выводится на
дисплей.
Устанавливаем
и настраиваем библиотеки.
1.
Установить библиотеки Adafruit :
библиотеку Adafruit_SSD1306 и библиотеку
Adafruit_GFX . Как их установить, я рассматривал
в
уроке.
2.
Скачать
файл
glcdfont.c
и заменить его в библиотеке Adafruit-GFX.
Библиотека находится
C:\Users\USER\Documents\Arduino\libraries\Adafruit_GFX_Library.
У
вас путь до библиотеки может отличаться. Вы
можете скачать,
библиотеку подготовленную для вывода русского текста, внизу статьи в разделе
материалы для скачивания.
3.
В скетч нужно
добавить
функцию перекодировки русских букв из
UTF-8 в Win-1251
.
Добавить функцию можно внизу кода.
/* Функция перекодировки русских букв из UTF-8 в Win-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;
}
4.
Добавить в блок void setup() {} следующую
строчку кода.
display.cp437(true);
5.
При выводе русского текста использовать
функцию
utf8rus()
.
Библиотеки,
которые используются в проекте
, Вы
можете скачать внизу статьи в разделе
материалы для скачивания.
Код
OLED часы на Arduino.
Рассказывать,
как устроена программа часов полностью
не буду. Тем более у меня на сайте
достаточно
уроков и примеров по реализации
функционалов на дисплеях и работы с
часами реального времени. Рассмотрим
только основную особенность данного
кода - это вывод русского языка в том
виде, как он прописан в самом коде.
Библиотеку для вывода символов на
дисплей мы установили и настроили. Как
же сейчас её использовать так, чтобы
постоянно не прописывать перекодировку
символов? Для этого сделаем функцию,
которая будет выводить наш текст с
нужным размером шрифта по указанным
координатам.
В данной функции и укажем
перекодировку символов. Благодаря
этому можно вывести информацию на
дисплей на русском языке.
void display_day() { // вывод дня недели
switch (day) {
case 1: draw_text(30, 0, "ВОСКРЕСЕНЬЕ", 1); break;
case 2: draw_text(30, 0, "ПОНЕДЕЛЬНИК", 1); break;
case 3: draw_text(30, 0, " ВТОРНИК ", 1); break;
case 4: draw_text(30, 0, " СРЕДА ", 1); break;
case 5: draw_text(30, 0, " ЧЕТВЕРГ ", 1); break;
case 6: draw_text(30, 0, " ПЯТНИЦА ", 1); break;
default: draw_text(30, 0, " СУББОТА ", 1);
}
}
Благодаря
таким
несложным
манипуляциям можно выводить текст на
дисплей на русском языке и в других
проектах, необязательно это должны быть
часы.
/*
Arduino часы с выводом температуры на DS3231 и SSD1306 OLED
Сайт https://portal-pk.ru/
Проекты на Arduino https://portal-pk.ru/page-17/proekty-na-arduino.html
Проекты на ESP https://portal-pk.ru/page-18/proekty-na-nodemcu-esp8266-esp-01.html
*/
#include <Wire.h> // I2C
#include <Adafruit_GFX.h> // Включить графическую библиотеку Adafruit
#include <Adafruit_SSD1306.h> // Включить драйвер OLED Adafruit SSD1306
#define SCREEN_WIDTH 128 // Ширина OLED-дисплея, в пикселях
#define SCREEN_HEIGHT 64 // Высота OLED-дисплея в пикселях
// SSD1306, подключенного к I2C (выводы SDA, SCL)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
#define button1 9 // Кнопка B1 подключена к контакту Arduino 9
#define button2 8 // Кнопка B2 подключена к контакту Arduino 8
void setup(void) {
pinMode(button1, INPUT_PULLUP);
pinMode(button2, INPUT_PULLUP);
delay(1000);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // инициализировать с помощью I2C адресс 0x3C (для 128x64)
// Очистить дисплей.
display.clearDisplay();
display.display();
display.cp437(true);
display.setTextColor(WHITE, BLACK);
display.drawRect(117, 56, 3, 3, WHITE); // Поставить символ степени ( ° )
draw_text(0, 56, "ТЕМПЕРАТУРА =", 1);
draw_text(122, 56, "C", 1);
}
char Time[] = " : ";
char Calendar[] = " / /20 ";
char temperature[] = " 00.00";
char temperature_msb;
byte i, second, minute, hour, day, date, month, year, temperature_lsb;
void display_day() { // вывод дня недели
switch (day) {
case 1: draw_text(30, 0, "ВОСКРЕСЕНЬЕ", 1); break;
case 2: draw_text(30, 0, "ПОНЕДЕЛЬНИК", 1); break;
case 3: draw_text(30, 0, " ВТОРНИК ", 1); break;
case 4: draw_text(30, 0, " СРЕДА ", 1); break;
case 5: draw_text(30, 0, " ЧЕТВЕРГ ", 1); break;
case 6: draw_text(30, 0, " ПЯТНИЦА ", 1); break;
default: draw_text(30, 0, " СУББОТА ", 1);
}
}
void DS3231_display() {
// Преобразовать в десятичную
minute = (minute >> 4) * 10 + (minute & 0x0F);
hour = (hour >> 4) * 10 + (hour & 0x0F);
date = (date >> 4) * 10 + (date & 0x0F);
month = (month >> 4) * 10 + (month & 0x0F);
year = (year >> 4) * 10 + (year & 0x0F);
Time[4] = minute % 10 + 48;
Time[3] = minute / 10 + 48;
if (second % 2)
Time[2] = 32;
else
Time[2] = 58;
Time[1] = hour % 10 + 48;
Time[0] = hour / 10 + 48;
Calendar[9] = year % 10 + 48;
Calendar[8] = year / 10 + 48;
Calendar[4] = month % 10 + 48;
Calendar[3] = month / 10 + 48;
Calendar[1] = date % 10 + 48;
Calendar[0] = date / 10 + 48;
if (temperature_msb < 0) {
temperature_msb = abs(temperature_msb);
temperature[0] = '-';
}
else
temperature[0] = ' ';
temperature_lsb >>= 6;
temperature[2] = temperature_msb % 10 + 48;
temperature[1] = temperature_msb / 10 + 48;
if (temperature_lsb == 0 || temperature_lsb == 2) {
temperature[5] = '0';
if (temperature_lsb == 0) temperature[4] = '0';
else temperature[4] = '5';
}
if (temperature_lsb == 1 || temperature_lsb == 3) {
temperature[5] = '5';
if (temperature_lsb == 1) temperature[4] = '2';
else temperature[4] = '7';
}
draw_text(4, 12, Calendar, 2); // Показать дату (формат: дд / мм / гггг)
draw_text(20, 30, Time, 3); // Показать время
draw_text(80, 56, temperature, 1); // Показать температуру
}
void blink_parameter() {
byte j = 0;
while (j < 10 && digitalRead(button1) && digitalRead(button2)) {
j++;
delay(25);
}
}
byte edit(byte x_pos, byte y_pos, byte parameter, byte text_size) {
char text[3];
sprintf(text, "%02u", parameter);
while (!digitalRead(button1)); // Подождите, пока кнопка B1 отпущена
while (true) {
while (!digitalRead(button2)) { // Если кнопка B2 нажата
parameter++;
if (i == 0 && parameter > 31) // Если date > 31 ==> date = 1
parameter = 1;
if (i == 1 && parameter > 12) // Если month > 12 ==> month = 1
parameter = 1;
if (i == 2 && parameter > 99) // Если year > 99 ==> year = 0
parameter = 0;
if (i == 3 && parameter > 23) // Если hours > 23 ==> hours = 0
parameter = 0;
if (i == 4 && parameter > 59) // Если minutes > 59 ==> minutes = 0
parameter = 0;
sprintf(text, "%02u", parameter);
draw_text(x_pos, y_pos, text, text_size);
delay(200); // Ждем 200ms
}
draw_text(x_pos, y_pos, " ", text_size);
blink_parameter();
draw_text(x_pos, y_pos, text, text_size);
blink_parameter();
if (!digitalRead(button1)) { // Если кнопка B1 нажата
i++; // Увеличение «i» для следующего параметра
return parameter; // Вернуть значение параметра и выйти
}
}
}
void draw_text(byte x_pos, byte y_pos, char *text, byte text_size) {
display.setCursor(x_pos, y_pos);
display.setTextSize(text_size);
display.print(utf8rus(text));
display.display();
}
void loop() {
if (!digitalRead(button1)) { // Если кнопка B1 нажата
i = 0;
while (!digitalRead(button1)); // Дождитесь отпускания кнопки B1
while (true) {
while (!digitalRead(button2)) { // Пока кнопка B2 нажата
day++; // Инкремент для деня
if (day > 7) day = 1;
display_day(); // Вызовите функцию display_day
delay(200); // Ждем 200 ms
}
draw_text(30, 0, " ", 1);
blink_parameter(); // Вызов функции blink_parameter
display_day(); // Вызовите функцию display_day
blink_parameter(); // Вызов функции blink_parameter
if (!digitalRead(button1)) // Если кнопка B1 нажата
break;
}
date = edit(4, 12, date, 2); // Изменить дату
month = edit(40, 12, month, 2); // Изменить month
year = edit(100, 12, year, 2); // Изменить year
hour = edit(20, 30, hour, 3); // Изменить hours
minute = edit(74, 30, minute, 3); // Изменить minutes
// Преобразовать десятичную в BCD
minute = ((minute / 10) << 4) + (minute % 10);
hour = ((hour / 10) << 4) + (hour % 10);
date = ((date / 10) << 4) + (date % 10);
month = ((month / 10) << 4) + (month % 10);
year = ((year / 10) << 4) + (year % 10);
// End conversion
// Записать данные в DS3231 RTC
Wire.beginTransmission(0x68); // Запустите протокол I2C с адресом DS3231
Wire.write(0); // Отправить адрес регистрации
Wire.write(0); // Сбросьте sesonds и запустите генератор
Wire.write(minute); // Запишем минуту
Wire.write(hour); // Запишем hour
Wire.write(day); // Запишем day
Wire.write(date); // Запишем date
Wire.write(month); // Запишем month
Wire.write(year); // Запишем year
Wire.endTransmission(); // Остановите передачу и отпустите шину I2C
delay(200); // Ждем 200ms
}
Wire.beginTransmission(0x68); // Запустите протокол I2C с адресом DS3231
Wire.write(0); // Отправить адрес регистрации
Wire.endTransmission(false); // Перезапуск I2C
Wire.requestFrom(0x68, 7); // Запросите 7 байтов от DS3231 и освободите шину I2C
second = Wire.read(); // Считать секунды из регистра 0
minute = Wire.read(); // Считать minuts из регистра 1
hour = Wire.read(); // Считать hour из регистра 2
day = Wire.read(); // Считать day из регистра 3
date = Wire.read(); // Считать date из регистра 4
month = Wire.read(); // Считать month из регистра 5
year = Wire.read(); // Считать year из регистра 6
Wire.beginTransmission(0x68); // Запустите протокол I2C с адресом DS3231
Wire.write(0x11); // Отправить адрес регистрации
Wire.endTransmission(false); // Перезапуск I2C
Wire.requestFrom(0x68, 2); // Запрос 2 байта от DS3231 и освобождение шины I2C
temperature_msb = Wire.read(); // Чтение температуры MSB
temperature_lsb = Wire.read(); // Считать температуру LSB
display_day();
DS3231_display(); // Время и календарь
delay(50); // Ждем 50ms
}
/* Функция перекодировки русских букв из UTF-8 в Win-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;
}
Пишите в комментариях, какие
проекты на данном дисплее вы бы хотели
видеть.
Возможности
OLED часов на arduino.
Две
тактовые кнопки позволяют настраивать
время и дату. Первая кнопка переключает
необходимый параметр, вторая кнопка
увеличивает данное значение. Настройка
дней недели работает аналогично, просто
вместо названия меняется порядковый
номер, а программа уже выводит день
недели на русском языке.
В
связи с тем, что используем
модуль
реального времени ds3231
, в котором встроен
датчик температуры, мы можем вывести
температуру в помещении. Самая нижняя
строчка на дисплее выводит данную информацию.
Это
достаточно распространённый функционал
любых часов, и поэтому данный
проект не получил собственный корпус.
На мой взгляд, проект должен быть более
серьезным, чтобы заморачиваться с
разработкой корпуса.
Пишите в комментариях ваше предложение,
чтобы вы хотели видеть реализованного
на данном дисплее. Может,
расширенные возможности данных часов,
или совсем другой проект.
На
этом
всё. Не
забывайте подписываться на мой
YouTube канал, вступать в группу Вконтакте,
в группу на
Facebook.
В скетче есть недочет. Если отключить мк от питания, но оставить запитанным от штатной батарейки модуль ds3231, то при включении мы увидим то время, когда выключился мк и оно дальше продолжит отсчитываться от этой точки... и наверно у такой логики может быть применение, но теряется смысл в использовании модуля часов реального времени...
ошибка IDE Arduino: 1.5.7 (Windows 7), Board: "Arduino Pro or Pro Mini, ATmega328 (5V, 16 MHz)"In file included from sketch_feb13a.ino:4:0:C:\Users\Андрей\Documents\Arduino\libraries\Adafruit_SSD1306/Adafruit_SSD1306.h:40:17: fatal error: SPI.h: No such file or directory #include <SPI.h> ^compilation terminated. This report would have more information with "Show verbose output during compilation" enabled in File > Preferences.
Прекрасно работают часы. Запустились с первого раза. Пробовал на ардуино уно и нано. Без разницы. К автору этой замечательной конструкции большая просьба. Можно сделать тоже самое, но с большим дисплеем oled? Дисплей в схеме мелкий, чтобы использовать эти часы в качестве настольных. Ждём следующую конструкцию автора. Успехов.
Комментарии
Войдите или Зарегистрируйтесь И Вы сможете общаться на форуме и оставлять комментарии без капчи.