#include <Arduino.h>
#include <pgmspace.h>
#include <Wire.h>
#include <iarduino_OLED_txt.h>
#include "CustomFont.h"
iarduino_OLED_txt myOLED(0x78); // Объявляем объект myOLED, указывая адрес дисплея на шине I2C: 0x78 (если учитывать бит RW=0).
extern const uint8_t SmallFontRus[]; // Подключаем шрифт SmallFontRus.
#define BUTTON_PIN 19
#define MAX_CHAR_PER_LINE 21
#define MAX_LINES 7
const char text1[] PROGMEM = "Боль сама по себе очень сильная. И мы связаны разумом, который мы не можем контролировать и из которого вытекает ненависть. Именно он быстро открывает дверь вещам, и удовольствие - это не более грубое удовольствие изобретателя, который действительно ненавидит время. Свободный галисум как нечто доставляющее ему удовольствие, боль, боли, которые больше всего болеют, где рождаются, обвиняют.\n\nТот, кто должен быть избран желанием, должен отказаться от боли или труда вещей как от обязанностей, причитающихся архитектору? Тот, кто еще более суров или обременен тяготами долгов, может родиться здесь с удовольствием или со своим собственным, кроме. Так что, если только мы не ненавидимы, она сама ищет более великих и достойных, стремясь следовать удовольствию или истине, или как бы покидая их.\n\nТаково их желание получать наслаждение, которое они избегают, 33 потому что страдания - это не то, что доставляет им удовольствие. И пусть труды, которые подлежат отречению, доставляют дело обвинителям. Или осуществление истины, которой оно стремится следовать, отталкивает желания, чтобы отвергнуть целое, которое не знает их боли и удовольствия, как удовольствия.";
const char text2[] PROGMEM = "UIKBf jebgn lkdrnило ипуыжопи ыждлоп тжо иОД оип дуыплдытэ щшШ ЩПэдЛ УПдоУИПТЫ ПЖОУЫ ПД.ИУЫ ПОЛД тЫУПРлИОЫ МТ лЫ,Ьилкыт ЖШЫРожоЫт иорЫ";
const char text3[] PROGMEM = "rho:\xB0 phi:\xB1 и т.д.";
const char* const texts[] PROGMEM = {
text1,
text2,
text3
};
int current_text_id = 0;
String current_text = "";
int current_text_pos = 0;
enum button_state {
none,
being_pressed,
pressed,
long_pressed,
double_pressed
};
button_state nav_btn_state = none;
void setup(){
Serial.begin(9600);
pinMode(BUTTON_PIN, INPUT_PULLUP);
myOLED.begin(); // Инициируем работу с дисплеем.
myOLED.setFont(SmallFontRusCustom); // Указываем шрифт который требуется использовать для вывода цифр и текста.
// myOLED.setCoding(TXT_UTF8); // Указываем кодировку текста в скетче. Если на дисплее не отображается Русский алфавит, то ...
myOLED.clrScr(); // раскомментируйте функцию setCoding и замените параметр TXT_UTF8, на TXT_CP866 или TXT_WIN1251.
increment_text(0);
print_current_text();
}
void loop(){
button_process();
if (nav_btn_state == pressed) {
increment_page(1);
print_current_text();
}
else if (nav_btn_state == double_pressed) {
increment_page(-1);
print_current_text();
}
else if (nav_btn_state == long_pressed) {
increment_text(1);
print_current_text();
}
delay(100);
}
bool is_last_btn_pressed = false;
unsigned long last_btn_pressed = 0;
unsigned long duration_btn_pressing = 0;
int click_counter = 0;
void button_process() {
if (millis() - last_btn_pressed < 50) return;
bool is_btn_pressed = !digitalRead(BUTTON_PIN);
if (!is_btn_pressed && is_last_btn_pressed) {
last_btn_pressed = millis();
duration_btn_pressing = millis() - duration_btn_pressing;
Serial.print("Pressed for ");
Serial.println(duration_btn_pressing);
click_counter++;
}
else if (is_btn_pressed && !is_last_btn_pressed)
duration_btn_pressing = millis();
else if (is_btn_pressed)
nav_btn_state = being_pressed;
else if (!is_btn_pressed && !is_last_btn_pressed && millis() - last_btn_pressed > 500) {
if (click_counter == 1 && duration_btn_pressing < 1000)
nav_btn_state = pressed;
else if (click_counter == 1 && duration_btn_pressing > 1000)
nav_btn_state = long_pressed;
else if (click_counter == 2)
nav_btn_state = double_pressed;
else nav_btn_state = none;
click_counter = 0;
}
is_last_btn_pressed = is_btn_pressed;
}
void increment_page(int value) {
current_text_pos = max(0, current_text_pos + MAX_CHAR_PER_LINE * value);
}
void increment_text(int value) {
uint8_t count = sizeof(texts) / sizeof(texts[0]);
current_text_id = (current_text_id + value) % count;
current_text = FPSTR(texts[current_text_id]);
current_text_pos = 0;
// Serial.print(count);
// Serial.print(" ");
// Serial.println(current_text_id);
}
void print_current_text() {
myOLED.clrScr();
for (int i = 0; i <= MAX_LINES; i++) {
String chebur = utf8Substring(current_text, current_text_pos + MAX_CHAR_PER_LINE * i, current_text_pos + MAX_CHAR_PER_LINE * (i + 1));
myOLED.print(chebur, 0, i);
// Serial.println(chebur);
}
// Serial.println("");
}
// Возвращает строку, обрезанную по символам UTF-8 от startChar (включительно) до endChar (не включая)
String utf8Substring(const String &text, int startChar, int endChar) {
int len = text.length(); // длина в байтах
int byteIndex = 0; // текущий байтовый индекс
int charIndex = 0; // текущий индекс символа
int byteStart = 0; // байтовый индекс начала
int byteEnd = len; // байтовый индекс конца
// Найти byteStart
while (charIndex < startChar && byteIndex < len) {
uint8_t b = text[byteIndex];
int charBytes = (b & 0x80) == 0x00 ? 1 :
(b & 0xE0) == 0xC0 ? 2 :
(b & 0xF0) == 0xE0 ? 3 :
(b & 0xF8) == 0xF0 ? 4 : 1;
byteIndex += charBytes;
charIndex++;
}
byteStart = byteIndex;
// Найти byteEnd
while (charIndex < endChar && byteIndex < len) {
uint8_t b = text[byteIndex];
int charBytes = (b & 0x80) == 0x00 ? 1 :
(b & 0xE0) == 0xC0 ? 2 :
(b & 0xF0) == 0xE0 ? 3 :
(b & 0xF8) == 0xF0 ? 4 : 1;
byteIndex += charBytes;
charIndex++;
}
byteEnd = byteIndex;
// Ограничения
if (byteStart > len) byteStart = len;
if (byteEnd > len) byteEnd = len;
if (byteEnd < byteStart) byteEnd = byteStart;
return text.substring(byteStart, byteEnd);
}