Друзья, помогите пожалуйста убить проблему. Несколько вечеров возюкаюсь безрезультатно. То ли уже не вижу ничего, то ли она в принципе не решаема?
На фото, слева - у-координаты символов кратны 8 и здесь все в порядке и с картинкой (вверху) и со строкой ("768"). А вот справа, у-координаты картинки = 4, текста = 35 и снизу вылезла непонятная "грязь".
Вывод посимвольный, буфер(512 байт), всякий раз чистится и заполняется побитово. Здесь псевдокод ответственный за проблему.
Спойлер
Код: Выделить всё
/*
* temp_ssd1306.c
*
* Created: 18.02.2020 22:36:34
* Author: МОНСТЕР
*/
#define BUFFER_LENGTH SSD1306_WIDTH * SSD1306_HEIGHT >>4
#define BUFFER_ROWS BUFFER_LENGTH / SSD1306_WIDTH * 8
uint8_t dev_address;
uint8_t _oled_buffer[BUFFER_LENGTH]; /*512 bytes*/
/*
эта функция меняет состояние соответствующего бита
в распределенных элементах буфера, определяемого координатами х/у.
По идее, биты полученные от единого байта из 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);
}

