oled displey
Diff: TroykaOLED.cpp
- Revision:
- 0:cd4a2add97a0
diff -r 000000000000 -r cd4a2add97a0 TroykaOLED.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TroykaOLED.cpp Tue Jul 23 12:32:26 2019 +0000 @@ -0,0 +1,836 @@ +/****************************************************************************/ +// Function: Cpp file for TroykaOLED +// Hardware: SSD1306 +// Arduino IDE: Arduino-1.8.5 +// Author: Igor Dementiev +// Date: NOV 10,2018 +// Version: v1.0.0 +// by www.amperka.ru +/****************************************************************************/ + +#include "TroykaOLED.h" +#define pgm_read_byte * //my +TroykaOLED::TroykaOLED (I2C *i2c,uint8_t i2cAddress, uint8_t width, uint8_t height): + _wire(i2c) +{ + _i2cAddress = i2cAddress; + _width = width; + _height = height; + _bufferDisplay = new uint8_t[_width * _height / 8]; + _stateInvert = false; + _stateAutoUpdate = true; + _stateImageBG = true; + _codingName = TXT_UTF8; +} + +void TroykaOLED::begin() { + _font.width=0; + _font.height=0; + _font.firstSymbol=0; + _font.sumSymbol=0; + _font.invert=false; + _font.background= true; + _font.setFont= false; +// _wire = wire; + // инициируем I²C +// _wire->begin(); + + // выключаем дисплей + _sendCommand(SSD1306_DISPLAY_OFF); + // устанавливаем частоту обновления дисплея в значение 0x80 (по умолчанию) + _sendCommand(SSD1306_SET_DISPLAY_CLOCK); + _sendCommand(0x80); + // устанавливаем multiplex ratio (коэффициент мультиплексирования COM выводов) в значение 0x3F (по умолчанию) + _sendCommand(SSD1306_SET_MULTIPLEX_RATIO); + _sendCommand(0x3F); + // устанавливаем смещение дисплея в 0 (без смещения) + _sendCommand(SSD1306_SET_DISPLAY_OFFSET); + _sendCommand(0x00); + // устанавливаем смещение ОЗУ в значение 0 (без смещения) + _sendCommand(SSD1306_SET_START_LINE | 0); + // настраиваем схему питания (0x14 - включить внутренний DC-DC преобразователь, 0x10 - отключить внутренний DC/DC) + _sendCommand(SSD1306_CHARGE_DCDC_PUMP); + _sendCommand(0x14); + // устанавливаем режим автоматической адресации (0x00-горизонтальная, 0x01-вертикальная, 0x10-страничная) + _sendCommand(SSD1306_ADDR_MODE); + _sendCommand(0x00); + // устанавливаем режим строчной развертки (слева/направо) + _sendCommand(SSD1306_SET_REMAP_L_TO_R); + // устанавливаем режим кадровой развертки (сверху/вниз) + _sendCommand(SSD1306_SET_REMAP_T_TO_D); + // устанавливаем аппаратную конфигурация COM выводов в значение 0x12 (по умолчанию) + _sendCommand(SSD1306_SET_COM_PINS); + _sendCommand(0x12); + // устанавливаем контрастность в значение 0xCF (допустимы значения от 0x00 до 0xFF) + _sendCommand(SSD1306_SET_CONTRAST); + _sendCommand(0xFF); + // настраиваем схему DC/DC преобразователя (0xF1 - Vcc снимается с DC/DC преобразователя, 0x22 - Vcc подается извне) + _sendCommand(SSD1306_SET_PRECHARGE_PERIOD); + _sendCommand(0xF1); + // устанавливаем питание светодиодов VcomH в значение выше чем по умолчанию: 0x30 + // это увеличит яркость дисплея + // допустимые значения: 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70 + _sendCommand(SSD1306_SET_VCOM_DESELECT); + _sendCommand(0x40); + // разрешаем отображать содержимое RAM памяти + _sendCommand(SSD1306_RAM_ON); + // отключаем инверсию + _sendCommand(SSD1306_INVERT_OFF); + // включаем дисплей + _sendCommand(SSD1306_DISPLAY_ON); + // чистим экран + clearDisplay(); +} + +void TroykaOLED::update() { + _sendBuffer(); +} + +void TroykaOLED::autoUpdate(bool stateAutoUpdate) { + _stateAutoUpdate = stateAutoUpdate; +} + +void TroykaOLED::setBrigtness(uint8_t brigtness) { + _sendCommand(SSD1306_SET_CONTRAST); + _sendCommand(brigtness); +} + +void TroykaOLED::clearDisplay() { + memset(_bufferDisplay, 0, _width * _height / 8); + + if(_stateAutoUpdate) { + _sendBuffer(); + } +} + +void TroykaOLED::invertDisplay(bool stateInvert) { + if(stateInvert) { + _stateInvert = true; + _sendCommand(SSD1306_INVERT_ON); + } else { + _stateInvert = false; + _sendCommand(SSD1306_INVERT_OFF); + } +} + +void TroykaOLED::invertText (bool stateInvertText) { + _font.invert = stateInvertText; +} + +void TroykaOLED::bgText (bool stateTextBG) { + _font.background = stateTextBG; +} + +void TroykaOLED::bgImage (bool stateImageBG) { + _stateImageBG = stateImageBG; +} + +void TroykaOLED::setFont(const uint8_t* fontData) { + // сохраняем указатель на первый байт массива в области памяти программ + _font.fontData = fontData; + // сохраняем ширину символов выбранного шрифта читая её из 0 байта массива по указателю fontData + _font.width = pgm_read_byte(&fontData[0]); + // сохраняем высоту символов выбранного шрифта читая её из 1 байта массива по указателю fontData + _font.height = pgm_read_byte(&fontData[1]); + // сохраняем код первого симола выбран. шрифта читая его из 2 байта массива по указателю fontData + _font.firstSymbol = pgm_read_byte(&fontData[2]); + // сохраняем количество символов в выбр шрифте читая их из 3 байта массива по указателю fontData + _font.sumSymbol = pgm_read_byte(&fontData[3]); + // устанавливаем флаг выбора шрифта + _font.setFont = true; + // определяем позицию бита указывающего количество пустых интервалов в массиве шрифта. + uint16_t i = (uint16_t) _font.sumSymbol * _font.width * _font.height / 8 + 0x04; + // определяем количество пустых интервалов в массиве шрифта. + uint16_t j = pgm_read_byte(&fontData[i]); + // указываем что первый пустой интервал в массиве шрифта находится после символа с кодом (0xFF) и состоит из 0 символов + _font.startSpace[0] = 0xFF; + _font.sumSpace[0] = 0; + // указываем что второй пустой интервал в массиве шрифта находится после символа с кодом (0xFF) и состоит из 0 символов + _font.startSpace[1] = 0xFF; + _font.sumSpace[1] = 0; + // указываем что третий пустой интервал в массиве шрифта находится после символа с кодом (0xFF) и состоит из 0 символов + _font.startSpace[2] = 0xFF; + _font.sumSpace[2] = 0; + // если количество пустых интервалов больше 0 + // сохраняем начало первого пустого интервала символов и размер первого пустого интервала символов + if (j > 0) { + _font.startSpace[0] = pgm_read_byte(&fontData[i + 1]); + _font.sumSpace[0] = pgm_read_byte(&fontData[i + 2]); + } + // если количество пустых интервалов больше 1 + // сохраняем начало второго пустого интервала символов и размер второго пустого интервала символов + if (j > 1) { + _font.startSpace[1] = pgm_read_byte(&fontData[i + 3]); + _font.sumSpace[1] = pgm_read_byte(&fontData[i + 4]); + } + // если количество пустых интервалов больше 2 + // сохраняем начало третьего пустого интервала символов и размер третьего пустого интервала символов + if (j > 2) { + _font.startSpace[2] = pgm_read_byte(&fontData[i + 5]); + _font.sumSpace[2] = pgm_read_byte(&fontData[i + 6]); + } +} + +void TroykaOLED::setCoding(uint8_t codingName) { + _codingName = codingName; +} + +void TroykaOLED::setCursor(int numX, int numY) { + if(numX < _width) { + _numX = numX; + } + if(numY < _height) { + _numY = numY; + } +} + +void TroykaOLED::print(char* data, int x, int y) { + _print(_codingCP866(data), x, y); +} +/* +void TroykaOLED::print(String str, int x, int y) { + char data[str.length() + 1]; + str.toCharArray(data, str.length() + 1); + _print(_codingCP866(data), x, y); +} +*/ +void TroykaOLED::print(const char* str, int x, int y) { + char data[strlen(str) + 1]; + for (uint8_t i = 0; i <= strlen(str); i++) { + data[i] = str[i]; + } + _print(_codingCP866(data), x, y); +} + +void TroykaOLED::print(int8_t num, int x, int y, uint8_t base) { + print(int32_t(num), x, y, base); +} + +void TroykaOLED::print(uint8_t num, int x, int y, uint8_t base) { + print(uint32_t(num), x, y, base); +} + +void TroykaOLED::print(int16_t num, int x, int y, uint8_t base) { + print(int32_t(num), x, y, base); +} + +void TroykaOLED::print(uint16_t num, int x, int y, uint8_t base) { + print(uint32_t(num), x, y, base); +} + +void TroykaOLED::print(int32_t num, int x, int y, uint8_t base) { + // определяем количество разрядов числа + // i = количество разрядов + 2, j = множитель кратный основанию системы счисления + int8_t i = 2; + int32_t j = 1; + while (num / j) { + j *= base; + i++; + } + // создаём строку k из i символов и добавляем символ(ы) конца строки + char k[i]; + i--; + k[i] = 0; + i--; + if(num > 0) { + k[i] = 0; + i--; + } + // создаём строку k из i символов и добавляем символ(ы) конца строки + uint32_t n = num < 0 ? num*-1 : num; + while (i) { + k[i]=_itoa(n % base); + n /= base; i--; + } + // заполняем строку k + if (num >= 0) { + k[i]=_itoa(n % base); + } else { + k[i]='-'; + } + // добавляем первый символ (либо первая цифра, либо знак минус) + // выводим строку k + print(k, x, y); +} + +void TroykaOLED::print(uint32_t num, int x, int y, uint8_t base) { + // определяем количество разрядов числа + // i = количество разрядов + 1, j = множитель кратный основанию системы счисления + int8_t i = 1; + uint32_t j = 1; + while (num / j) { + j *= base; + i++; + } + if (num == 0) { + i++; + } + // определяем строку k из i символов и заполняем её + char k[i]; + i--; + k[i] = 0; + + while(i) { + k[i - 1] = _itoa(num % base); + num /= base; + i--; + } + // выводим строку k + print(k, x, y); +} + +void TroykaOLED::print(double num, int x, int y, uint8_t sum) { + uint32_t i = 1, j = 0, k = 0; + j = sum; + while (j) { + i *= 10; + j--; + } + // выводим целую часть числа + print(int32_t(num), x, y); + // если требуется вывести хоть один знак после запятой, то ... + if (sum) { + // выводим символ разделителя + print("."); + // получаем целое число, которое требуется вывести после запятой + j = num * i * (num < 0 ? -1 : 1); + j %= i; + k = j; + // если полученное целое число равно нулю, то выводим sum раз символ «0» + if (j == 0) { + while(sum) { + print("0"); + sum--; + } + } else { + // иначе, если в полученном целом числе меньше разрядов чем требуется + // заполняем эти разряды выводя символ «0», после чего выводим само число + while (j * 10 < i) { + print("0"); + j *= 10; + } + print(k); + } + } +} + +void TroykaOLED::drawPixel(int x, int y, uint8_t color) { + _drawPixel(x, y, color); + if(_stateAutoUpdate) { + _sendBuffer(); + } + _numX = x; + _numY = y; +} + +void TroykaOLED::drawLine(int x1, int y1, int x2, int y2, uint8_t color) { + _drawLine(x1, y1, x2, y2, color); + if(_stateAutoUpdate) { + _sendBuffer(); + } + _numX = x2; + _numY = y2; +} + +void TroykaOLED::drawLine(int x2, int y2, uint8_t color) { + drawLine(_numX, _numY, x2, y2, color); +} + +void TroykaOLED::drawRect(int x1, int y1, int x2, int y2, bool fill, uint8_t color) { + if (fill) { + if (x1 < x2) { + for (int x = x1; x <= x2; x++) { + _drawLine(x,y1,x,y2,color); + } + } else { + for (int x = x1; x >= x2; x--) { + _drawLine(x,y1,x,y2,color); + } + } + } else { + _drawLine(x1, y1, x2, y1, color); + _drawLine(x2, y2, x2, y1, color); + _drawLine(x2, y2, x1, y2, color); + _drawLine(x1, y1, x1, y2, color); + } + if(_stateAutoUpdate) { + _sendBuffer(); + } + _numX = x2; + _numY = y2; +} + +void TroykaOLED::drawCircle(int x, int y, uint8_t r, bool fill, uint8_t color) { + // x1,y1 - положительные координаты точек круга с центром 00 + // p - отрицательная парабола + int x1 = 0, y1 = r, p = 1 - r; + // цикл будет выполняться пока координата x не станет чуть меньше y + // прочертит дугу от 0 до 45° - это 1/8 часть круга + while (x1 < y1 + 1) { + if (fill) { + // прорисовываем горизонтальные линии вверху круга (между точками 3 и 1 дуг) + _drawLine(x - x1, y - y1, x + x1, y - y1, color); + // прорисовываем горизонтальные линии внизу круга (между точками 4 и 2 дуг) + _drawLine(x - x1, y + y1, x + x1, y + y1, color); + // прорисовываем горизонтальные линии выше середины круга (между точками 7 и 5 дуг) + _drawLine(x - y1, y - x1, x + y1, y - x1, color); + // прорисовываем горизонтальные линии выше середины круга (между точками 8 и 6 дуг) + _drawLine(x - y1, y + x1, x + y1, y + x1, color); + } else { + // 1 дуга 0° - 45° (построенная в соответствии с уравнением) + _drawPixel(x + x1, y - y1, color); + // 2 дуга 180° - 135° (1 дуга отражённая по вертикали) + _drawPixel(x + x1, y + y1, color); + // 3 дуга 360° - 315° (1 дуга отражённая по горизонтали) + _drawPixel(x - x1, y - y1, color); + // 4 дуга 180° - 225° (2 дуга отражённая по горизонтали) + _drawPixel(x - x1, y + y1, color); + // 5 дуга 90° - 45° (2 дуга повёрнутая на -90°) + _drawPixel(x + y1, y - x1, color); + // 6 дуга 90° - 135° (1 дуга повёрнутая на +90°) + _drawPixel(x + y1, y + x1, color); + // 7 дуга 270° - 315° (1 дуга повёрнутая на -90°) + _drawPixel(x - y1, y - x1, color); + // 8 дуга 270° - 225° (2 дуга повёрнутая на +90°) + _drawPixel(x - y1, y + x1, color); + } + // если парабола p вышла в положительный диапазон + if(p >= 0) { + // сдвигаем её вниз на y1 * 2 (каждый такой сдвиг провоцирет смещение точки y1 первой дуги вниз) + y1--; + p -= y1 * 2; + } + // с каждым проходом цикла, смещаем точку x1 первой дуги влево и находим новую координату параболы p + p++; + x1++; + p += x1 * 2; + } + if(_stateAutoUpdate) { + _sendBuffer(); + } + _numX = x; + _numY = y; +} + +bool TroykaOLED::bitRead(uint8_t data, uint8_t bit) +{ + uint8_t b; + b=(data>>bit)&1; + if(b) + return true; + else + return false; +} + +void TroykaOLED::drawImage(const uint8_t* image, int x, int y, uint8_t mem) { + uint8_t w = getImageWidth(image, mem); + uint8_t h = getImageHeight(image, mem); + bool color; + // колонка с которой требуется начать вывод изображения ... + switch(x) { + // определяем начальную колонку для выравнивания по левому краю + case OLED_LEFT: + _numX = 0; + break; + // определяем начальную колонку для выравнивания по центру + case OLED_CENTER: + _numX = (_width - w) / 2; + break; + // определяем начальную колонку для выравнивания по правому краю + case OLED_RIGHT: + _numX = _width - w; + break; + // начальной колонкой останется та, на которой был закончен вывод предыдущего текста или изображения + case OLED_THIS: + _numX = _numX; + break; + // начальная колонка определена пользователем + default: + _numX = x; + break; + } + // строка с которой требуется начать вывод изображения ... + switch(y) { + // определяем начальную строку для выравнивания по верхнему краю + case OLED_TOP: + _numY = h - 1; + break; + // определяем начальную строку для выравнивания по центру + case OLED_CENTER: + _numY = (_height - h) / 2; + break; + // определяем начальную строку для выравнивания по нижнему краю + case OLED_BOTTOM: + _numY = _height - 1; + break; + // начальной строкой останется та, на которой выведен предыдущий текст или изображение + case OLED_THIS: + _numY = _numY; + break; + // начальная строка определена пользователем + default: + _numY = y; + break; + } + // проходим по страницам изображения... + for (uint8_t p = 0; p < h; p++) { + // проходим по колонкам изображения... + for (uint8_t k = 0; k < w; k++) { + // если массив изображения находится в памяти ОЗУ + if (mem == IMG_RAM) { + // получаем цвет очередного пикселя из p % 8 бита + // 2 + (p / 8 * w) + k байта, массива image + color = bitRead(image[2 + (p / 8 * w) + k], p % 8); + } else if (mem == IMG_ROM) { + // если массив изображения находится в памяти ПЗУ + // получаем цвет очередного пикселя из p % 8 бита + // 2 + (p / 8 * w) + k байта, массива image + color = bitRead(pgm_read_byte(&image[2 + (p / 8 * w) + k]), p % 8); + } + // если у изображения есть фон или цвет пикселя белый + if (_stateImageBG || color) { + // прорисовываем пиксель в координате (_numX + k, _numY + p) + _drawPixel( _numX + k, _numY + p, color); + } + } + } + // добавляем ширину изображения к координате _numX + _numX += w; + if(_stateAutoUpdate) { + _sendBuffer(); + } +} + +bool TroykaOLED::getPixel(int x, int y) { + if(x < 0 || x > _height - 1 || y < 0 || y > _width - 1) { + return 0; + } + // определяем номер байта массива _bufferDisplay в котором находится пиксель + uint16_t numByte = (y / 8 * 128) + x; + // определяем номер бита в найденном байте, который соответсвует искомому пикселю + uint8_t numBit = y % 8; + // возвращаем цвет пикселя из бита numBit элемента numByte массива _bufferDisplay + return bitRead(_bufferDisplay[numByte], numBit); +} + +uint8_t TroykaOLED::getImageWidth(const uint8_t* image, uint8_t mem) { + // возвращаем ширину изображения + return (mem == IMG_RAM) ? image[0] : pgm_read_byte(&image[0]); +} + +uint8_t TroykaOLED::getImageHeight(const uint8_t* image, uint8_t mem) { + // возвращаем высоту изображения + return (mem == IMG_RAM) ? image[1] : pgm_read_byte(&image[1]); +} + +void TroykaOLED::_print(char* data, int x, int y) { + // если шрифт не выбран или его высота не кратна 8 пикселям, то выходим из функции + if (_font.setFont == false || _font.height % 8 > 0) { + return; + } + // определяем количество колонок которое занимают выводимые символы + uint16_t len = strlen(data) * _font.width; + if (len > _width) { + len = _width / _font.width * _font.width; + } + // объявляем переменную для хранения номера байта в массиве шрифта + uint16_t num; + // объявляем переменные для хранения координат точек + int x1, y1; + // объявляем переменную для хранения цвета точек + bool c; + // колонка с которой требуется начать вывод текста ... + switch (x) { + // определяем начальную колонку для выравнивания по левому краю. + case OLED_LEFT: + _numX = 0; + break; + // определяем начальную колонку для выравнивания по центру + case OLED_CENTER: + _numX = (_width - len) / 2; + break; + // определяем начальную колонку для выравнивания по правому краю + case OLED_RIGHT: + _numX = _width - len; + break; + // начальной колонкой останется та, на которой был закончен вывод предыдущего текста или изображения + case OLED_THIS: + _numX = _numX; + break; + // начальная колонка определена пользователем + default: + _numX = x; + break; + } + // строка с которой требуется начать вывод текста ... + switch (y) { + // определяем начальную строку для выравнивания по верхнему краю + case OLED_TOP: + _numY = _font.height - 1; + break; + // определяем начальную строку для выравнивания по центру + case OLED_CENTER: + _numY = (_height - _font.height) / 2 + _font.height; + break; + // определяем начальную строку для выравнивания по нижнему краю + case OLED_BOTTOM: + _numY = _height; + break; + // начальной строкой останется та, на которой выведен предыдущий текст или изображение + case OLED_THIS: + _numY = _numY; + break; + // начальная строка определена пользователем + default: + _numY = y; + break; + } + // пересчитываем количество колонок которое занимают выводимые символы, с учётом начальной позиции + if (_numX + len > _width) { + len = (_width - _numX) / _font.width * _font.width; + } + // проходим по страницам символов... + for (int8_t p = 0; p < _font.height / 8; p++) { + // проходим по выводимым символам... + for (uint8_t n = 0; n < (len / _font.width); n++) { + // присваиваем переменной num код выводимого символа + num = uint8_t(data[n]); + // если в массиве символов, до кода текущего символа, имеется пустой интервал + // уменьшаем код текущего символа на количество символов в пустом интервале + if(_font.startSpace[0] < num) { + num -= _font.sumSpace[0]; + } + // если в массиве символов, до кода текущего символа, имеется пустой интервал + // уменьшаем код текущего символа на количество символов в пустом интервале + if (_font.startSpace[1] < num) { + num -= _font.sumSpace[1]; + } + // если в массиве символов, до кода текущего символа, имеется пустой интервал + // то уменьшаем код текущего символа на количество символов в пустом интервале + if (_font.startSpace[2] < num) { + num -= _font.sumSpace[2]; + } + // вычитаем код первого символа (с которого начинается массив шрифта) + num -= _font.firstSymbol; + // умножаем полученное значение на ширину символа (количество колонок) + num *= _font.width; + // умножаем полученное значение на высоту символа (количество страниц) + num *= _font.height / 8; + // добавляем количество колонок данного символа, которые уже были выведены на предыдущих страницах + num += p * _font.width; + // добавляем количество байт в начале массива шрифта, которые не являются байтами символов + num += 0x04; + // проходим по байтам очередного символа + for (uint8_t k = 0; k < _font.width; k++) { + // проходим по байтам очередного символа + for (uint8_t b = 0; b < 8; b++) { + // начальная колонка всего текста + (количество выведенных символов * ширина символов) + номер байта текущего символа + x1 = _numX + n * _font.width + k; + // нижняя строка текста - высота симолов + количество уже выведенных страниц + номер бита байта текущего символа + 1 + y1 = _numY + p * 8 + b; + // цвет точки символа: 1-белый, 0-чёрный + c = bitRead( pgm_read_byte(&_font.fontData[num + k]), b); + // если цвет текста требуется инвертировать + if (_font.invert) { + // если установлен фон текста или точка стоит на букве (а не на фоне) + if (_font.background || c) { + // выводим инвертированную точку + _drawPixel(x1, y1, !c); + } + } else { + // если цвет текста не требуется инвертировать + // если установлен фон текста или точка стоит на букве (а не на фоне) + if (_font.background || c) { + // выводим не инвертированную точку + _drawPixel(x1, y1, c); + } + } + } + } + } + } + if(_stateAutoUpdate) { + _sendBuffer(); + } + // сохраняем координату окончания текста. + _numX += len; +} + +// параметр: одна цифра от 0 до 15 +// преобразуем цифры 0-9 в символ с кодом 48-57, а цифры 10-15 в символ с кодом 65-71 +char TroykaOLED::_itoa(uint8_t num) { + return char(num + (num < 10 ? 48 : 55)); +} + +char* TroykaOLED::_codingCP866(char* StrIn) { + // определяем строку для вывода результата + char* StrOut = StrIn; + // переменненые для хранения номера сивола в строках StrIn и StrOut + uint8_t numIn = 0, numOut = 0; + // переменненые для хранения текущего кода символа в строках StrIn и StrOut + uint8_t charThis = StrIn[0], charNext = StrIn[1]; + switch (_codingName) { + // преобразуем текст из кодировки UTF-8: + case TXT_UTF8: + while (charThis > 0 && numIn < 0xFF ) { + // если код текущего символа равен 208, а за ним следует символ с кодом 144...191 + // значит это буква «А»...«п» требующая преобразования к коду 128...175 + if (charThis == 0xD0 && charNext >= 0x90 && charNext <= 0xBF) { + StrOut[numOut] = charNext - 0x10; + numIn++; + } else if (charThis == 0xD0 && charNext == 0x81) { + // если код текущего символа равен 208, а за ним следует символ с кодом 129 + // значит это буква «Ё» требующая преобразования к коду 240 + StrOut[numOut] = 0xF0; numIn++; + } else if (charThis == 0xD1 && charNext >= 0x80 && charNext <= 0x8F) { + // если код текущего символа равен 209, а за ним следует символ с кодом 128...143 + // значит это буква «р»...«я» требующая преобразования к коду 224...239 + StrOut[numOut] = charNext + 0x60; numIn++; + } else if (charThis == 0xD1 && charNext == 0x91) { + // если код текущего символа равен 209, а за ним следует символ с кодом 145 + // значит это буква «ё» требующая преобразования к коду 241 + StrOut[numOut] = 0xF1; + numIn++; + } else { + // иначе не меняем символ + StrOut[numOut] = charThis; + } + // переходим к следующему символу + numIn++; + numOut++; + charThis = StrIn[numIn]; + charNext = StrIn[numIn + 1]; + // добавляем символ конца строки и возвращаем строку StrOut + } + StrOut[numOut] = '\0'; + break; + //преобразуем текст из кодировки WINDOWS-1251: + case TXT_WIN1251: + // если код текущего символа строки StrIn больше 0 и номер текушего символа строки StrIn меньше 255 + while (charThis > 0 && numIn < 0xFF) { + // если код текущего символа равен 192...239 + // значит это буква «А»...«п» требующая преобразования к коду 128...175 + if (charThis >= 0xC0 && charThis <= 0xEF) { + StrOut[numOut] = charThis - 0x40; + } else if (charThis >= 0xF0 && charThis <= 0xFF) { + // если код текущего символа равен 240...255 + // значит это буква «р»...«я» требующая преобразования к коду 224...239 + StrOut[numOut] = charThis - 0x10; + } else if (charThis == 0xA8) { + // если код текущего символа равен 168, значит это буква «Ё» требующая преобразования к коду 240 + StrOut[numOut] = 0xF0; + }else if (charThis == 0xB8) { + // если код текущего символа равен 184, значит это буква «ё» требующая преобразования к коду 241 + StrOut[numOut] = 0xF1; + } else { + // иначе не меняем символ + StrOut[numOut] = charThis; + } + // переходим к следующему символу + numIn++; + numOut++; + charThis = StrIn[numIn]; + // добавляем символ конца строки + } + StrOut[numOut] = '\0'; + break; + } + // возвращаем строку StrOut + return StrOut; +} + +void TroykaOLED::_drawPixel(int x, int y, uint8_t color) { + if(x < 0 || x > _width - 1 || y < 0 || y > _height - 1) { + return; + } + // определяем номер страницы в которой должен находиться пиксель + uint8_t p = y / 8; + // определяем номер байта массива _bufferDisplay в котором требуется прорисовать пиксель + uint16_t numByte = (p * 128 ) + x; + // определяем номер бита в найденном байте, который соответсвует рисуемому пикселю + uint8_t numBit = y % 8; + switch (color) { + case WHITE: + _bufferDisplay[numByte] |= 1 << numBit; + break; + case BLACK: + _bufferDisplay[numByte] &= ~(1 << numBit); + break; + case INVERSE: + _bufferDisplay[numByte] ^= 1 << numBit; + break; + } +} + +void TroykaOLED::_drawLine(int x1, int y1, int x2, int y2, uint8_t color) { + int x3 = x2 - x1; + int y3 = y2 - y1; + // рисуем линию по линейному уровнению (y-y1)/(y2-y1) = (x-x1)/(x2-x1) + // определяем где больше расстояние (по оси x или y) + // по той оси проходим в цикле, для поиска точек на другой оси + if (abs(x3) > abs(y3)) { + if (x1 < x2) { + for (int x = x1; x <= x2; x++) { + _drawPixel(x,((x - x1) * y3 / x3 + y1), color); + } + } else { + for (int x = x1; x >= x2; x--) { + _drawPixel(x,((x - x1) * y3 / x3 + y1), color); + } + } + } else { + if (y1 < y2) { + for (int y = y1; y <= y2; y++) { + _drawPixel(((y - y1) * x3 / y3 + x1), y, color); + } + } else { + for (int y = y1; y >= y2; y--) { + _drawPixel(((y - y1) * x3 / y3 + x1), y, color); + } + } + } +} + +// отправка байта команды +/* +void TroykaOLED::_sendCommand(uint8_t command){ + _wire->beginTransmission(_i2cAddress); + _wire->write(0x80); + _wire->write(command); + _wire->endTransmission(); +} +*/ +void TroykaOLED::_sendCommand(uint8_t command) +{ + char data_write[2]; + data_write[0]=0x80; + data_write[1]=command; + _wire->write(_i2cAddress,data_write, 2,0); +} +// отправка буфера (массива _bufferDisplay) в дисплей +void TroykaOLED::_sendBuffer() { + _sendCommand(SSD1306_ADDR_PAGE); + _sendCommand(0); + _sendCommand(_height / 8 - 1); + _sendCommand(SSD1306_ADDR_COLUMN); + _sendCommand(0); + _sendCommand(_width - 1); + char data_write[17]; //my + data_write[0]=0x40; + for (int i = 0; i < _width * _height / 8; i++){ + for (uint8_t x = 0; x < 16; x++) { + data_write[x+1]=_bufferDisplay[i++]; + } +/* + _wire->beginTransmission(_i2cAddress); + _wire->write(0x40); + for (uint8_t x = 0; x < 16; x++) { + _wire->write(_bufferDisplay[i++]); + } + i--; + _wire->endTransmission(); +*/ + i--; + _wire->write(_i2cAddress,data_write, 17,0); + } +} \ No newline at end of file