/*
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;
}