From 36543140d0af854dd1df7b460177005b36f864c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A8=D1=83=D0=BC?= =?UTF-8?q?=D0=B8=D0=BB=D0=BE=D0=B2?= Date: Thu, 25 May 2023 13:25:06 +0000 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=B4=D0=B0=D0=BB=D0=B8=D1=82=D1=8C=20'O?= =?UTF-8?q?LED-I2C/OLEDI2C.h'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OLED-I2C/OLEDI2C.h | 979 --------------------------------------------- 1 file changed, 979 deletions(-) delete mode 100644 OLED-I2C/OLEDI2C.h diff --git a/OLED-I2C/OLEDI2C.h b/OLED-I2C/OLEDI2C.h deleted file mode 100644 index 75724e7..0000000 --- a/OLED-I2C/OLEDI2C.h +++ /dev/null @@ -1,979 +0,0 @@ - -#ifndef OLEDI2C_h -#define OLEDI2C_h - -// ===== константы ===== -#define SSD1306_128x32 0 -#define SSD1306_128x64 1 -#define SSH1106_128x64 2 - -#define OLED_I2C 0 -#define OLED_SPI 1 - -#define OLED_NO_BUFFER 0 -#define OLED_BUFFER 1 - -#define OLED_CLEAR 0 -#define OLED_FILL 1 -#define OLED_STROKE 2 - -#define BUF_ADD 0 -#define BUF_SUBTRACT 1 -#define BUF_REPLACE 2 - -#define BITMAP_NORMAL 0 -#define BITMAP_INVERT 1 - -// =========================================================================== - -#include "I2C.h" // лёгкая библиотека Wire (для atmega328) -#include "charMap.h" - -#ifndef OLED_NO_PRINT -#include -#endif - -// ============================ БЭКЭНД КОНСТАНТЫ ============================== -// внутренние константы -#define OLED_WIDTH 128 -#define OLED_HEIGHT_32 0x02 -#define OLED_HEIGHT_64 0x12 -#define OLED_64 0x3F -#define OLED_32 0x1F - -#define OLED_DISPLAY_OFF 0xAE -#define OLED_DISPLAY_ON 0xAF - -#define OLED_COMMAND_MODE 0x00 -#define OLED_ONE_COMMAND_MODE 0x80 -#define OLED_DATA_MODE 0x40 -#define OLED_ONE_DATA_MODE 0xC0 - -#define OLED_ADDRESSING_MODE 0x20 -#define OLED_HORIZONTAL 0x00 -#define OLED_VERTICAL 0x01 - -#define OLED_NORMAL_V 0xC8 -#define OLED_FLIP_V 0xC0 -#define OLED_NORMAL_H 0xA1 -#define OLED_FLIP_H 0xA0 - -#define OLED_CONTRAST 0x81 -#define OLED_SETCOMPINS 0xDA -#define OLED_SETVCOMDETECT 0xDB -#define OLED_CLOCKDIV 0xD5 -#define OLED_SETMULTIPLEX 0xA8 -#define OLED_COLUMNADDR 0x21 -#define OLED_PAGEADDR 0x22 -#define OLED_CHARGEPUMP 0x8D - -#define OLED_NORMALDISPLAY 0xA6 -#define OLED_INVERTDISPLAY 0xA7 - -#define BUFSIZE_128x64 (128 * 64 / 8) -#define BUFSIZE_128x32 (128 * 32 / 8) - -#ifndef OLED_SPI_SPEED -#define OLED_SPI_SPEED 1000000ul -#endif - -//static SPISettings OLED_SPI_SETT(OLED_SPI_SPEED, MSBFIRST, SPI_MODE0); - -// список инициализации -static const uint8_t _oled_init[] PROGMEM = { - OLED_DISPLAY_OFF, - OLED_CLOCKDIV, - 0x80, // value - OLED_CHARGEPUMP, - 0x14, // value - OLED_ADDRESSING_MODE, - OLED_VERTICAL, - OLED_NORMAL_H, - OLED_NORMAL_V, - OLED_CONTRAST, - 0x7F, // value - OLED_SETVCOMDETECT, - 0x40, // value - OLED_NORMALDISPLAY, - OLED_DISPLAY_ON, -}; - - - -// ========================== КЛАСС КЛАСС КЛАСС ============================= -template -#ifndef OLED_NO_PRINT -class OLEDI2C : public Print { -#else -class OLEDI2C { -#endif -public: - // ========================== КОНСТРУКТОР ============================= - OLEDI2C(uint8_t address = 0x3C) - : _address(address) {} - - // ============================= СЕРВИС =============================== - // инициализация - void init(int __attribute__((unused)) sda = 0, int __attribute__((unused)) scl = 0) { -#if defined(ESP32) || defined(ESP8266) - if (sda || scl) Wire.begin(sda, scl); - else Wire.begin(); -#else - Wire.begin(); -#endif - - beginCommand(); - for (uint8_t i = 0; i < 15; i++) sendByte(pgm_read_byte(&_oled_init[i])); - endTransm(); - beginCommand(); - sendByte(OLED_SETCOMPINS); - sendByte(_TYPE ? OLED_HEIGHT_64 : OLED_HEIGHT_32); - sendByte(OLED_SETMULTIPLEX); - sendByte(_TYPE ? OLED_64 : OLED_32); - endTransm(); - - setCursorXY(0, 0); - if (_BUFF) setWindow(0, 0, _maxX, _maxRow); // для буфера включаем всю область - } - - // очистить дисплей - void clear() { - fill(0); - } - - // очистить область - void clear(int x0, int y0, int x1, int y1) { - if (_TYPE < 2) { // для SSD1306 - if (_BUFF) rect(x0, y0, x1, y1, OLED_CLEAR); - else { - x1++; - y1++; - y0 >>= 3; - y1 = (y1 - 1) >> 3; - y0 = constrain(y0, 0, _maxRow); - y1 = constrain(y1, 0, _maxRow); - x0 = constrain(x0, 0, _maxX); - x1 = constrain(x1, 0, _maxX); - setWindow(x0, y0, x1, y1); - beginData(); - for (int x = x0; x < x1; x++) - for (int y = y0; y < y1 + 1; y++) - writeData(0, y, x, 2); - endTransm(); - } - } else { - // для SSH1108 - } - setCursorXY(_x, _y); - } - - // яркость 0-255 - void setContrast(uint8_t value) { - sendCommand(OLED_CONTRAST, value); - } - - // вкл/выкл - void setPower(bool mode) { - sendCommand(mode ? OLED_DISPLAY_ON : OLED_DISPLAY_OFF); - } - - // отразить по горизонтали - void flipH(bool mode) { - sendCommand(mode ? OLED_FLIP_H : OLED_NORMAL_H); - } - - // инвертировать дисплей - void invertDisplay(bool mode) { - sendCommand(mode ? OLED_INVERTDISPLAY : OLED_NORMALDISPLAY); - } - - // отразить по вертикали - void flipV(bool mode) { - sendCommand(mode ? OLED_FLIP_V : OLED_NORMAL_V); - } - - // ============================= ПЕЧАТЬ ================================== - virtual size_t write(uint8_t data) { -#ifndef OLED_NO_PRINT - // переносы и пределы - bool newPos = false; - if (data == '\r') { - _x = 0; - newPos = true; - data = 0; - } // получен возврат каретки - if (data == '\n') { - _y += _scaleY; - newPos = true; - data = 0; - _getn = 1; - } // получен перевод строки - if (_println && (_x + 6 * _scaleX) >= _maxX) { - _x = 0; - _y += _scaleY; - newPos = true; - } // строка переполненена, перевод и возврат - if (newPos) setCursorXY(_x, _y); // переставляем курсор - if (_y + _scaleY > _maxY + 1) data = 0; // дисплей переполнен - if (_getn && _println && data == ' ' && _x == 0) { - _getn = 0; - data = 0; - } // убираем первый пробел в строке - - // фикс русских букв и некоторых символов - if (data > 127) { - uint8_t thisData = data; - // data = 0 - флаг на пропуск - if (data > 191) data = 0; - else if (_lastChar == 209 && data == 145) data = 192; // ё кастомная - else if (_lastChar == 208 && data == 129) data = 149; // Е вместо Ё - else if (_lastChar == 226 && data == 128) data = 0; // тире вместо длинного тире (начало) - else if (_lastChar == 128 && data == 148) data = 45; // тире вместо длинного тире - _lastChar = thisData; - } - if (data == 0) return 1; - // если тут не вылетели - печатаем символ - - if (_TYPE < 2 || 1) { // для SSD1306 - int newX = _x + _scaleX * 6; - if (newX < 0 || _x > _maxX) _x = newX; // пропускаем вывод "за экраном" - else { - if (!_BUFF) beginData(); - for (uint8_t col = 0; col < 6; col++) { // 6 стобиков буквы - uint8_t bits = getFont(data, col); // получаем байт - if (_invState) bits = ~bits; // инверсия - if (_scaleX == 1) { // если масштаб 1 - if (_x >= 0 && _x <= _maxX) { // внутри дисплея - if (_shift == 0) { // если вывод без сдвига на строку - writeData(bits, 0, 0, _mode); // выводим - } else { // со сдвигом - writeData(bits << _shift, 0, 0, _mode); // верхняя часть - writeData(bits >> (8 - _shift), 1, 0, _mode); // нижняя часть - } - } - } else { // масштаб 2, 3 или 4 - растягиваем шрифт - uint32_t newData = 0; // буфер - for (uint8_t i = 0, count = 0; i < 8; i++) - for (uint8_t j = 0; j < _scaleX; j++, count++) - bitWrite(newData, count, bitRead(bits, i)); // пакуем растянутый шрифт - - for (uint8_t i = 0; i < _scaleX; i++) { // выводим. По Х - byte prevData = 0; - if (_x + i >= 0 && _x + i <= _maxX) // внутри дисплея - for (uint8_t j = 0; j < _scaleX; j++) { // выводим. По Y - byte data = newData >> (j * 8); // получаем кусок буфера - if (_shift == 0) { // если вывод без сдвига на строку - writeData(data, j, i, _mode); // выводим - } else { // со сдвигом - writeData((prevData >> (8 - _shift)) | (data << _shift), j, i, _mode); // склеиваем и выводим - prevData = data; // запоминаем предыдущий - } - } - if (_shift != 0) writeData(prevData >> (8 - _shift), _scaleX, i, _mode); // выводим нижний кусочек, если со сдвигом - } - } - _x += _scaleX; // двигаемся на ширину пикселя (1-4) - } - if (!_BUFF) endTransm(); - } - } else { - // для SSH1106 - } -#endif - return 1; - } - - // автоматически переносить текст - void autoPrintln(bool mode) { - _println = mode; - } - - // отправить курсор в 0,0 - void home() { - setCursorXY(0, 0); - } - - // поставить курсор для символа 0-127, 0-8(4) - void setCursor(int x, int y) { - setCursorXY(x, y << 3); - } - - // поставить курсор для символа 0-127, 0-63(31) - void setCursorXY(int x, int y) { - _x = x; - _y = y; - setWindowShift(x, y, _maxX, _scaleY); - } - - // масштаб шрифта (1-4) - void setScale(uint8_t scale) { - scale = constrain(scale, 1, 4); // защита от нечитающих доку - _scaleX = scale; - _scaleY = scale * 8; - setCursorXY(_x, _y); - } - - // инвертировать текст (0-1) - void invertText(bool inv) { - _invState = inv; - } - - void textMode(byte mode) { - _mode = mode; - } - - // возвращает true, если дисплей "кончился" - при побуквенном выводе - bool isEnd() { - return (_y > _maxRow); - } - - // ================================== ГРАФИКА ================================== - // точка (заливка 1/0) - void dot(int x, int y, byte fill = 1) { - if (x < 0 || x > _maxX || y < 0 || y > _maxY) return; - _x = 0; - _y = 0; - if (_BUFF) { - bitWrite(_oled_buffer[_bufIndex(x, y)], y & 0b111, fill); - } else { - if (!_buf_flag) { - setWindow(x, y >> 3, _maxX, _maxRow); - beginData(); - sendByte(1 << (y & 0b111)); // задвигаем 1 на высоту y - endTransm(); - } else { - x -= _bufX; - y -= _bufY; - if (x < 0 || x > _bufsizeX || y < 0 || y > (_bufsizeY << 3)) return; - bitWrite(_buf_ptr[(y >> 3) + x * _bufsizeY], y & 0b111, fill); - } - } - } - - // линия - void line(int x0, int y0, int x1, int y1, byte fill = 1) { - _x = 0; - _y = 0; - if (x0 == x1) fastLineV(x0, y0, y1, fill); - else if (y0 == y1) fastLineH(y0, x0, x1, fill); - else { - int sx, sy, e2, err; - int dx = abs(x1 - x0); - int dy = abs(y1 - y0); - sx = (x0 < x1) ? 1 : -1; - sy = (y0 < y1) ? 1 : -1; - err = dx - dy; - for (;;) { - dot(x0, y0, fill); - if (x0 == x1 && y0 == y1) return; - e2 = err << 1; - if (e2 > -dy) { - err -= dy; - x0 += sx; - } - if (e2 < dx) { - err += dx; - y0 += sy; - } - } - } - } - - // горизонтальная линия - void fastLineH(int y, int x0, int x1, byte fill = 1) { - _x = 0; - _y = 0; - if (x0 > x1) _swap(x0, x1); - if (y < 0 || y > _maxY) return; - if (x0 == x1) { - dot(x0, y, fill); - return; - } - x1++; - x0 = constrain(x0, 0, _maxX); - x1 = constrain(x1, 0, _maxX); - if (_BUFF) { - for (int x = x0; x < x1; x++) dot(x, y, fill); - } else { - if (_buf_flag) { - for (int x = x0; x < x1; x++) dot(x, y, fill); - return; - } - byte data = 0b1 << (y & 0b111); - y >>= 3; - setWindow(x0, y, x1, y); - beginData(); - for (int x = x0; x < x1; x++) writeData(data, y, x); - endTransm(); - } - } - - // вертикальная линия - void fastLineV(int x, int y0, int y1, byte fill = 1) { - _x = 0; - _y = 0; - if (y0 > y1) _swap(y0, y1); - if (x < 0 || x > _maxX) return; - if (y0 == y1) { - dot(x, y0, fill); - return; - } - y1++; - if (_BUFF) { - for (int y = y0; y < y1; y++) dot(x, y, fill); - } else { - if (_buf_flag) { - for (int y = y0; y < y1; y++) dot(x, y, fill); - return; - } - if (fill) fill = 255; - byte shift = y0 & 0b111; - byte shift2 = 8 - (y1 & 0b111); - if (shift2 == 8) shift2 = 0; - int height = y1 - y0; - y0 >>= 3; - y1 = (y1 - 1) >> 3; - byte numBytes = y1 - y0; - setWindow(x, y0, x, y1); - - beginData(); - if (numBytes == 0) { - if (_inRange(y0, 0, _maxRow)) writeData((fill >> (8 - height)) << shift, y0, x); - } else { - if (_inRange(y0, 0, _maxRow)) writeData(fill << shift, y0, x); // начальный кусок - y0++; - for (byte i = 0; i < numBytes - 1; i++, y0++) - if (_inRange(y0, 0, _maxRow)) writeData(fill, y0, x); // столбик - if (_inRange(y0, 0, _maxRow)) writeData(fill >> shift2, y0, x); // нижний кусок - } - endTransm(); - } - } - - // прямоугольник (лев. верхн, прав. нижн) - void rect(int x0, int y0, int x1, int y1, byte fill = 1) { - _x = 0; - _y = 0; - if (x0 > x1) _swap(x0, x1); - if (y0 > y1) _swap(y0, y1); - if (fill == OLED_STROKE) { - fastLineH(y0, x0 + 1, x1 - 1); - fastLineH(y1, x0 + 1, x1 - 1); - fastLineV(x0, y0, y1); - fastLineV(x1, y0, y1); - } else { - if (x0 == x1 && y0 == y1) { - dot(x0, y0, fill); - return; - } - if (x0 == x1) { - fastLineV(x0, y0, y1); - return; - } - if (y0 == y1) { - fastLineH(y0, x0, x1); - return; - } - if (!_BUFF && fill == OLED_CLEAR) { - clear(x0, y0, x1, y1); - return; - } - - // если рисуем в мини-буфер - if (_buf_flag) { - x0 = constrain(x0, 0, _maxX); - x1 = constrain(x1, 0, _maxX); - for (byte x = x0; x <= x1; x++) fastLineV(x, y0, y1, fill == OLED_FILL ? 1 : 0); - return; - } - byte thisFill = (fill == OLED_FILL ? 0 : 1); - // рисуем в олед и в большой буфер - x1++; - y1++; - byte shift = y0 & 0b111; - byte shift2 = 8 - (y1 & 0b111); - if (shift2 == 8) shift2 = 0; - int height = y1 - y0; - y0 >>= 3; - y1 = (y1 - 1) >> 3; - byte numBytes = y1 - y0; - x0 = constrain(x0, 0, _maxX); - x1 = constrain(x1, 0, _maxX); - - if (!_BUFF) setWindow(x0, y0, x1, y1); - if (!_BUFF) beginData(); - for (byte x = x0; x < x1; x++) { - int y = y0; - if (numBytes == 0) { - if (_inRange(y, 0, _maxRow)) writeData((255 >> (8 - height)) << shift, y, x, thisFill); - } else { - if (_inRange(y, 0, _maxRow)) writeData(255 << shift, y, x, thisFill); // начальный кусок - y++; - for (byte i = 0; i < numBytes - 1; i++, y++) - if (_inRange(y, 0, _maxRow)) writeData(255, y, x, thisFill); // столбик - if (_inRange(y, 0, _maxRow)) writeData(255 >> shift2, y, x, thisFill); // нижний кусок - } - } - if (!_BUFF) endTransm(); - } - } - - // прямоугольник скруглённый (лев. верхн, прав. нижн) - void roundRect(int x0, int y0, int x1, int y1, byte fill = OLED_FILL) { - if (fill == OLED_STROKE) { - fastLineV(x0, y0 + 2, y1 - 2); - fastLineV(x1, y0 + 2, y1 - 2); - fastLineH(y0, x0 + 2, x1 - 2); - fastLineH(y1, x0 + 2, x1 - 2); - dot(x0 + 1, y0 + 1); - dot(x1 - 1, y0 + 1); - dot(x1 - 1, y1 - 1); - dot(x0 + 1, y1 - 1); - } else { - fastLineV(x0, y0 + 2, y1 - 2, fill); - fastLineV(x0 + 1, y0 + 1, y1 - 1, fill); - fastLineV(x1 - 1, y0 + 1, y1 - 1, fill); - fastLineV(x1, y0 + 2, y1 - 2, fill); - rect(x0 + 2, y0, x1 - 2, y1, fill); - } - } - - // окружность (центр х, центр у, радиус, заливка) - void circle(int x, int y, int radius, byte fill = OLED_FILL) { - //if (!_BUFF) createBuffer(x - radius, y - radius, x + radius + 1, y + radius); - int f = 1 - radius; - int ddF_x = 1; - int ddF_y = -2 * radius; - int x1 = 0; - int y1 = radius; - - byte fillLine = (fill == OLED_CLEAR) ? 0 : 1; - dot(x, y + radius, fillLine); - dot(x, y - radius, fillLine); - dot(x + radius, y, fillLine); - dot(x - radius, y, fillLine); - //if (fill != OLED_STROKE) fastLineH(y, x - radius, x + radius-1, fillLine); - if (fill != OLED_STROKE) fastLineV(x, y - radius, y + radius - 1, fillLine); - while (x1 < y1) { - if (f >= 0) { - y1--; - ddF_y += 2; - f += ddF_y; - } - x1++; - ddF_x += 2; - f += ddF_x; - if (fill == OLED_STROKE) { - dot(x + x1, y + y1); - dot(x - x1, y + y1); - dot(x + x1, y - y1); - dot(x - x1, y - y1); - dot(x + y1, y + x1); - dot(x - y1, y + x1); - dot(x + y1, y - x1); - dot(x - y1, y - x1); - } else { // FILL / CLEAR - - fastLineV(x + x1, y - y1, y + y1, fillLine); - fastLineV(x - x1, y - y1, y + y1, fillLine); - fastLineV(x + y1, y - x1, y + x1, fillLine); - fastLineV(x - y1, y - x1, y + x1, fillLine); - /* - fastLineH(y + y1, x - x1, x + x1-1, fillLine); - fastLineH(y - y1, x - x1, x + x1-1, fillLine); - fastLineH(y + x1, x - y1, x + y1-1, fillLine); - fastLineH(y - x1, x - y1, x + y1-1, fillLine); - */ - } - } - //if (!_BUFF) sendBuffer(); - } - void bezier(int* arr, uint8_t size, uint8_t dense, uint8_t fill = 1) { - int a[size * 2]; - for (int i = 0; i < (1 << dense); i++) { - for (int j = 0; j < size * 2; j++) a[j] = arr[j]; - for (int j = (size - 1) * 2 - 1; j > 0; j -= 2) - for (int k = 0; k <= j; k++) - a[k] = a[k] + (((a[k + 2] - a[k]) * i) >> dense); - dot(a[0], a[1], fill); - } - } - - // вывести битмап - void drawBitmap(int x, int y, const uint8_t* frame, int width, int height, uint8_t invert = 0, byte mode = 0) { - _x = 0; - _y = 0; - if (invert) invert = 255; - byte left = height & 0b111; - if (left != 0) height += (8 - left); // округляем до ближайшего кратного степени 2 - int shiftY = (y >> 3) + (height >> 3); // строка (row) крайнего байта битмапа - setWindowShift(x, y, width, height); // выделяем окно - bool bottom = (_shift != 0 && shiftY >= 0 && shiftY <= _maxRow); // рисовать ли нижний сдвинутый байт - - if (!_BUFF) beginData(); - for (int X = x, countX = 0; X < x + width; X++, countX++) { // в пикселях - byte prevData = 0; - if (_inRange(X, 0, _maxX)) { // мы внутри дисплея по X - for (int Y = y >> 3, countY = 0; Y < shiftY; Y++, countY++) { // в строках (пикс/8) - byte data = pgm_read_word(&(frame[countY * width + countX])) ^ invert; // достаём байт - if (_shift == 0) { // без сдвига по Y - if (_inRange(Y, 0, _maxRow)) writeData(data, Y, X, mode); // мы внутри дисплея по Y - } else { // со сдвигом по Y - if (_inRange(Y, 0, _maxRow)) writeData((prevData >> (8 - _shift)) | (data << _shift), Y, X, mode); // задвигаем - prevData = data; - } - } - if (bottom) writeData(prevData >> (8 - _shift), shiftY, X, mode); // нижний байт - } - } - if (!_BUFF) endTransm(); - } - - // залить весь дисплей указанным байтом - void fill(uint8_t data) { - if (_BUFF) memset(_oled_buffer, data, _bufSize); - else { - if (_TYPE < 2 || 1) { // для SSD1306 - setWindow(0, 0, _maxX, _maxRow); - beginData(); - for (int i = 0; i < (_TYPE ? 1024 : 512); i++) sendByte(data); - endTransm(); - } else { // для SSH1108 - } - } - setCursorXY(_x, _y); - } - - // шлёт байт в "столбик" setCursor() и setCursorXY() - void drawByte(uint8_t data) { - if (++_x > _maxX) return; - if (_TYPE < 2 || 1) { // для SSD1306 - if (!_BUFF) beginData(); - if (_shift == 0) { // если вывод без сдвига на строку - writeData(data); // выводим - } else { // со сдвигом - writeData(data << _shift); // верхняя часть - writeData(data >> (8 - _shift), 1); // нижняя часть со сдвигом на 1 - } - if (!_BUFF) endTransm(); - } else { - // для SSH1106 - /* - int h = y & 0x07; - if (_BUFF) { - for (int p = 0; p < 2; p++) { - Wire.beginTransmission(_address); - continueCmd(0xB0 + (y >> 3) + p); // Page - continueCmd(0x00 + ((x + 2) & 0x0F)); // Column low nibble - continueCmd(0x10 + ((x + 2) >> 4)); // Column high nibble - continueCmd(0xE0); // Read modify write - Wire.write(OLED_ONE_DATA_MODE); - Wire.endTransmission(); - Wire.requestFrom((int)_address, 2); - Wire.read(); // Dummy read - int j = Wire.read(); - Wire.beginTransmission(_address); - Wire.write(OLED_ONE_DATA_MODE); - Wire.write((data << h) >> (p << 3) | j); - continueCmd(0xEE); // Cancel read modify write - Wire.endTransmission(); - } - } else { - for (int p = 0; p < 2; p++) { - Wire.beginTransmission(_address); - continueCmd(0xB0 + (y >> 3) + p); // Page - continueCmd(0x00 + ((x + 2) & 0x0F)); // Column low nibble - continueCmd(0x10 + ((x + 2) >> 4)); // Column high nibble - Wire.write(OLED_ONE_DATA_MODE); - Wire.write((data << h) >> (p << 3)); - Wire.endTransmission(); - } - }*/ - } - } - - // вывести одномерный байтовый массив (линейный битмап высотой 8) - void drawBytes(uint8_t* data, byte size) { - if (!_BUFF) beginData(); - for (byte i = 0; i < size; i++) { - if (++_x > _maxX) return; - if (_shift == 0) { // если вывод без сдвига на строку - writeData(data[i]); // выводим - } else { // со сдвигом - writeData(data[i] << _shift); // верхняя часть - writeData(data[i] >> (8 - _shift), 1); // нижняя часть со сдвигом на 1 - } - } - if (!_BUFF) endTransm(); - } - - // ================================== СИСТЕМНОЕ =================================== - // полностью обновить дисплей из буфера - void update() { - if (_BUFF) { - if (_TYPE < 2) { // для 1306 - setWindow(0, 0, _maxX, _maxRow); - beginData(); - for (int i = 0; i < (_TYPE ? 1024 : 512); i++) sendByte(_oled_buffer[i]); - endTransm(); - } else { // для 1106 - sendCommand(0x00); - sendCommand(0x10); - sendCommand(0x40); - uint16_t ptr = 0; - for (uint8_t i = 0; i < (64 >> 3); i++) { - sendCommand(0xB0 + i + 0); //set page address - sendCommand(2 & 0xf); //set lower column address - sendCommand(0x10); //set higher column address - for (uint8_t a = 0; a < 8; a++) { - beginData(); - for (uint8_t b = 0; b < (OLED_WIDTH >> 3); b++) { - sendByteRaw(_oled_buffer[((ptr & 0x7F) << 3) + (ptr >> 7)]); - ptr++; - } - endTransm(); - } - } - } - } - } - - // выборочно обновить дисплей из буфера (x0, y0, x1, y1) - void update(int x0, int y0, int x1, int y1) { - if (_BUFF) { - y0 >>= 3; - y1 >>= 3; - setWindow(x0, y0, x1, y1); - beginData(); - for (int x = x0; x < x1; x++) - for (int y = y0; y < y1 + 1; y++) - if (x >= 0 && x <= _maxX && y >= 0 && y <= _maxRow) - sendByte(_oled_buffer[y + x * (_TYPE ? 8 : 4)]); - endTransm(); - } - } - - // отправить байт по i2с или в буфер - void writeData(byte data, byte offsetY = 0, byte offsetX = 0, int mode = 0) { - if (_BUFF) { - switch (mode) { - case 0: - _oled_buffer[_bufIndex(_x + offsetX, _y) + offsetY] |= data; // добавить - break; - case 1: - _oled_buffer[_bufIndex(_x + offsetX, _y) + offsetY] &= ~data; // вычесть - break; - case 2: - _oled_buffer[_bufIndex(_x + offsetX, _y) + offsetY] = data; // заменить - break; - } - } else { - if (_buf_flag) { - int x = _x - _bufX; - int y = _y - _bufY; - if (x < 0 || x > _bufsizeX || y < 0 || y > (_bufsizeY << 3)) return; - switch (mode) { - case 0: - _buf_ptr[(y >> 3) + x * _bufsizeY] |= data; // добавить - break; - case 1: - _buf_ptr[(y >> 3) + x * _bufsizeY] &= ~data; // вычесть - break; - case 2: - _buf_ptr[(y >> 3) + x * _bufsizeY] = data; // заменить - break; - } - } else { - sendByte(data); - } - } - } - - // окно со сдвигом. x 0-127, y 0-63 (31), ширина в пикселях, высота в пикселях - void setWindowShift(int x0, int y0, int sizeX, int sizeY) { - _shift = y0 & 0b111; - if (!_BUFF) setWindow(x0, (y0 >> 3), x0 + sizeX, (y0 + sizeY - 1) >> 3); - } - - // ================== ДИНАМИЧЕСКИЙ БУФЕР ================ - // создать - bool createBuffer(int x0, int y0, int x1, int y1, byte fill = 0) { - if (!_BUFF) { - _bufX = x0; - _bufY = y0; - _bufsizeX = x1 - x0 + 1; - _bufsizeY = ((y1 - y0) >> 3) + 1; - - int bufSize = _bufsizeX * _bufsizeY; - _buf_ptr = (byte*)malloc(bufSize); - if (_buf_ptr != NULL) { - _buf_flag = true; - memset(_buf_ptr, fill, bufSize); - return true; - } else { - _buf_flag = false; - return false; - } - } - } - - // отправить - void sendBuffer() { - if (!_BUFF) { - if (_buf_flag) { - setWindow(_bufX, _bufY >> 3, _bufX + _bufsizeX, (_bufY >> 3) + _bufsizeY - 1); - beginData(); - for (int i = 0; i < _bufsizeX * _bufsizeY; i++) { - sendByte(_buf_ptr[i]); - } - endTransm(); - _buf_flag = false; - free(_buf_ptr); - } - } - } - - // ========= ЛОУ-ЛЕВЕЛ ОТПРАВКА ========= - - // супер-костыль для либы Wire. Привет индусам! - void sendByte(uint8_t data) { - sendByteRaw(data); -#if !defined(microWire_h) - if (!_CONN) { - _writes++; - if (_writes >= 16) { - endTransm(); - beginData(); - } - } -#endif - } - void sendByteRaw(uint8_t data) { - Wire.write(data); - } - - - // отправить команду - void sendCommand(uint8_t cmd1) { - beginOneCommand(); - sendByteRaw(cmd1); - endTransm(); - } - - // отправить код команды и команду - void sendCommand(uint8_t cmd1, uint8_t cmd2) { - beginCommand(); - sendByteRaw(cmd1); - sendByteRaw(cmd2); - endTransm(); - } - - // выбрать "окно" дисплея - void setWindow(int x0, int y0, int x1, int y1) { - beginCommand(); - sendByteRaw(OLED_COLUMNADDR); - sendByteRaw(constrain(x0, 0, _maxX)); - sendByteRaw(constrain(x1, 0, _maxX)); - sendByteRaw(OLED_PAGEADDR); - sendByteRaw(constrain(y0, 0, _maxRow)); - sendByteRaw(constrain(y1, 0, _maxRow)); - endTransm(); - } - - void beginData() { - startTransm(); - if (_CONN) fastWrite(_DC, 1); - else sendByteRaw(OLED_DATA_MODE); - } - - void beginCommand() { - startTransm(); - if (_CONN) fastWrite(_DC, 0); - else sendByteRaw(OLED_COMMAND_MODE); - } - - void beginOneCommand() { - startTransm(); - if (_CONN) fastWrite(_DC, 0); - else sendByteRaw(OLED_ONE_COMMAND_MODE); - } - - void endTransm() { - Wire.endTransmission(); - _writes = 0; - } - - void startTransm() { - Wire.beginTransmission(_address); - } - - - // получить "столбик-байт" буквы - uint8_t getFont(uint8_t font, uint8_t row) { -#ifndef OLED_NO_PRINT - if (row > 4) return 0; - font = font - '0' + 16; // перевод код символа из таблицы ASCII - if (font <= 95) { - return pgm_read_byte(&(_charMap[font][row])); // для английских букв и символов - } else if (font >= 96 && font <= 111) { // и пизд*ц для русских - return pgm_read_byte(&(_charMap[font + 47][row])); - } else if (font <= 159) { - return pgm_read_byte(&(_charMap[font - 17][row])); - } else { - return pgm_read_byte(&(_charMap[font - 1][row])); // для кастомных (ё) - } -#endif - } - - // ==================== ПЕРЕМЕННЫЕ И КОНСТАНТЫ ==================== - const uint8_t _address = 0x3C; - const uint8_t _maxRow = (_TYPE ? 8 : 4) - 1; - const uint8_t _maxY = (_TYPE ? 64 : 32) - 1; - const uint8_t _maxX = OLED_WIDTH - 1; // на случай добавления мелких дисплеев - - // софт. буфер - const int _bufSize = ((_BUFF == 1) ? (_TYPE ? BUFSIZE_128x64 : BUFSIZE_128x32) : 0); - uint8_t _oled_buffer[((_BUFF == 1) ? (_TYPE ? BUFSIZE_128x64 : BUFSIZE_128x32) : 0)]; -private: - // всякое - void fastWrite(const uint8_t pin, bool val) { -#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) - if (pin < 8) bitWrite(PORTD, pin, val); - else if (pin < 14) bitWrite(PORTB, (pin - 8), val); - else if (pin < 20) bitWrite(PORTC, (pin - 14), val); -#elif defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny13__) - bitWrite(PORTB, pin, val); -#else - digitalWrite(pin, val); -#endif - } - // индекс в буфере - int _bufIndex(int x, int y) { - return ((y) >> 3) + ((x) << (_TYPE ? 3 : 2)); // _y / 8 + _x * (4 или 8) - } - void _swap(int& x, int& y) { - int z = x; - x = y; - y = z; - } - bool _inRange(int x, int mi, int ma) { - return x >= mi && x <= ma; - } - - bool _invState = 0; - bool _println = false; - bool _getn = false; - uint8_t _scaleX = 1, _scaleY = 8; - int _x = 0, _y = 0; - uint8_t _shift = 0; - uint8_t _lastChar; - uint8_t _writes = 0; - uint8_t _mode = 2; - - // дин. буфер - int _bufsizeX, _bufsizeY; - int _bufX, _bufY; - uint8_t* _buf_ptr; - bool _buf_flag = false; -}; -#endif \ No newline at end of file