Здоровья котам! Друзья, помогите пожалуйста убить проблему. Несколько вечеров возюкаюсь безрезультатно. То ли уже не вижу ничего, то ли она в принципе не решаема? На фото, слева - у-координаты символов кратны 8 и здесь все в порядке и с картинкой (вверху) и со строкой ("768"). А вот справа, у-координаты картинки = 4, текста = 35 и снизу вылезла непонятная "грязь". Вывод посимвольный, буфер(512 байт), всякий раз чистится и заполняется побитово. Здесь псевдокод ответственный за проблему. Спойлер
/* эта функция меняет состояние соответствующего бита в распределенных элементах буфера, определяемого координатами х/у. По идее, биты полученные от единого байта из draw_byte(), здесь могут распределиться по разным байтам буфера. */ void draw_pixel(int16_t x, int16_t y, uint16_t color, uint8_t width){ //y %= BUFFER_ROWS; uint16_t bi = width * (y / 8) + x; color?(_oled_buffer[bi] |= (1 << (y & 0x07))):(_oled_buffer[bi] &= ~(1 << (y & 0x07))); }
/* Состояние каждого бита аргумента byte поочередно отправляется для модификации буфера. Остальные аргументы - сквозняком. */ void draw_byte(uint8_t byte, int16_t x, int16_t y, uint8_t width){ uint8_t bit = 8; while(bit--){ draw_pixel(x, y, byte & 0x80, width); byte <<= 1; y++; } }
/* В памяти дисплея задаем прямоугольную область для дальнейшей отрисовки. Возвращается байтовый размер этой области. */ uint16_t set_area(int x, int y, uint8_t width, uint8_t height){ uint8_t page_0 = y >> 3; //стартовая страница области uint8_t pages = height >> 3; //общее количество while((height + (y & 0x07)) > (pages << 3)) pages++;//страниц области i2c_cmd(0x21); //установка столбца i2c_cmd(x); //Начальный столбец. i2c_cmd(x + width - 1); //Конечный столбец. i2c_cmd(0x22); //установка страницы i2c_cmd(page_0); //Начальная страница. i2c_cmd(page_0 + pages - 1); //Конечная страница. return (pages * width); //Байтовый размер области }
/* Вывод символа в заданные координаты экрана. \ char c - код символа \ int x, int y - пиксельные координаты лево-верхнего пиксела символа. cfont - структура моноширинного шрифта. Здесь: \ cfont.data - массив шрифта + служебные байты. Сам шрифт смещен на величину FONT_DATA_SHIFT от начала массива. \ cfont.x_size, cfont.y_size - пиксельные размеры символа шрифта. \ cfont.bytes - количество байт на символ в массиве шрифта. \ cfont.interspace - межсимвольный промежуток в слове.
*/ void _print_char(char c, int x, int y){ uint16_t size, sym_id; //байт-размер области, смещение и счетчик байт символа в массиве шрифта. uint8_t pages, current_y; //вертикальный размер символа в страницах дисплея, смещение по "у" для обрабатываемой страницы. size = set_area(x, y, cfont.x_size + cfont.interspace, cfont.y_size); memset(_oled_buffer, 0, size); current_y = y & 7; pages = 1; while((current_y + cfont.y_size) > (pages << 3)) pages++; //декодирование символа c switch (c){ case 0x2a: sym_id = FONT_DATA_SHIFT; break; // "*" default: sym_id = (c - 0x2c) * cfont.bytes + FONT_DATA_SHIFT; // "-./0123456789:" } //****************** for (uint8_t dy = 0; dy < pages; dy++){ for (uint8_t dx = 0; dx < cfont.x_size; dx++){ draw_byte(pgm_read_byte(&cfont.data[sym_id++]), dx, current_y, cfont.x_size + cfont.interspace); } current_y += 8; } i2c_data_array(_oled_buffer, size); }
/* Вывод строки */ void oled_print(char *st, int x, int y){ while(*st != '\0'){ _print_char(*st++, x, y); x += (cfont.x_size + cfont.interspace); } }
/* Вывод картинки. Алгоритм во многом повторяет процедуру _print_char. */ void oled_drawImage(const uint8_t* image, int x, int y){ cimage.data = image; cimage.width = pgm_read_byte(&cimage.data[OLED_IMG_WIDTH]); cimage.height = pgm_read_byte(&cimage.data[OLED_IMG_HEIGHT]); cimage.bytes = pgm_read_byte(&cimage.data[OLED_IMG_BYTES]); uint16_t size = set_area(x, y, cimage.width, cimage.height); uint16_t shift = OLED_IMG_SHIFT; uint8_t sy = y & 7, pages = 1; memset(_oled_buffer, 0, size); //memset(_oled_buffer, 0, BUFFER_LENGTH); while((sy + cimage.height) > (pages << 3)) pages++; for (uint8_t dy = 0; dy < pages; dy++){ for (uint8_t dx = 0; dx < cimage.width; dx++){ draw_byte(pgm_read_byte(&cimage.data[shift++]), dx, sy, cimage.width); } sy += 8; } i2c_data_array(_oled_buffer, size); }
Может у вас SH1106? Присылают под видом SSD1306/ Вот пишут
Цитата:
Контроллер оказался проще, чем ssd1306. В частности, он не поддерживает режимы горизонтальной и вертикальной адресации, а умеет только страничную адресацию. Возможности по ремапу строк столбцов тоже ограничены. Поэтому попытка запуска экранчика с кодом от 1306 привела к закономерной неудаче.
pcb432, Здесь горизонтальная адресация и она работает вроде... Картинка 16х16, а шрифт 10х14 бит. Т.е. занимают 2, а когда и 3 страницы (это если координата у не кратна . Так вот 2 страницы рисуются идеально, при любых координатах, а на 3 почему-то мусор.
Решил задачу. Видимо передоз программирования был. В процедурах _print_char(...) и oled_drawImage(...) битовое смещение, в циклах подсчета страниц, было лишним. Правильно работающие строчки таковы:
Код:
void _print_char(char c, int x, int y){ ... while(cfont.y_size > (pages << 3)) pages++; ... }
void oled_drawImage(const uint8_t* image, int x, int y){ ... while(cimage.height > (pages << 3)) pages++; ... }
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 19
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения