oled displey
TroykaOLED.cpp
- Committer:
- docent
- Date:
- 2019-07-23
- Revision:
- 0:cd4a2add97a0
File content as of revision 0:cd4a2add97a0:
/****************************************************************************/ // 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); } }