#1 2025-05-23 22:26:59

chipaka
Учасник
Зареєстрований: 2024-04-27
Повідомлень: 11

Переробляю скетч i2c на дисплей SPI OLED

Допоможіть!
Переробляю скетч i2c на дисплей SPI OLED. Була бібліотека GyverOLED. Переробляю під Adafruit SSD1306. Виникла така проблема: є курсор такого типу ">", який переміщається по меню з 8 рядків при натисканні на кнопку. У старому коді з Гувер бібліотекою можна встановлювати курсор рядками:
void printPointer(uint8_t pointer) { // Навігація по меню
if (flag) {                                     // Якщо прапор встановлено
oled.setCursor(0, pointer);            // Вказуємо на параметр
oled.print(">");
} else {                                       // Інакше
oled.setCursor(124, pointer);        // Вказуємо значення параметра
oled.print("<");
}
}
В Adafruit SSD1306 курсор можна встановлювати тільки за координатами х і у. Як зробити переміщення курсору рядками

Неактивний

#2 2025-05-23 23:05:22

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 428

Re: Переробляю скетч i2c на дисплей SPI OLED

chipaka пише:

Як зробити переміщення курсору рядками

Помножити номер рядка на висоту рядка в пікселях:

oled.setCursor(0, pointer * 8);

Активний

#3 2025-05-24 09:06:22

chipaka
Учасник
Зареєстрований: 2024-04-27
Повідомлень: 11

Re: Переробляю скетч i2c на дисплей SPI OLED

В Adafruit SSD1306 у мене так виходить:
void printPointer(uint8_t pointer) {          // Навигация по меню
  if (flag) {                                             // Если флаг установлен
    display.setCursor(0, pointer);               // Указываем на параметр
    display.print(">");
  } else {                                                 // Иначе
    display.setCursor(116, pointer);            // Указываем на значение параметра
    display.print("<");
  }
}
Але тут курсор встановлюється на піксель. У гувері є дві можливості встановлення на піксель та на рядок: oled.setCursorXY и
oled.setCursor

Неактивний

#4 2025-05-24 09:16:33

jokeer
Гість

Re: Переробляю скетч i2c на дисплей SPI OLED

Намалюйте пару рядків на листочку а клітинку. Порахуйте клітинки.
Якщо потрібна функція як у Гувера - ну, напишіть wink Можна навіть успадкувати свій клас від тої ліби і зробити як у Гувера.

#5 2025-05-24 09:25:35

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 428

Re: Переробляю скетч i2c на дисплей SPI OLED

chipaka пише:

Але тут курсор встановлюється на піксель.

Що у вас є `pointer` в `void printPointer(uint8_t pointer)`? Номер рядка? Так помножте номер рядка на висоту рядка в пікселях, отримаєте координату в пікселях:

void printPointer(uint8_t pointer) {
  if (flag) {
    display.setCursor(0, pointer * 8);
    display.print(">");
  } else {
    display.setCursor(116, pointer * 8);
    display.print("<");
  }
}

А краще спочатку обчисліть координату в пікселях, потім передавайте її в setCursor():

void printPointer(uint8_t pointer) {
  int y = pointer * 8;
  if (flag) {
    display.setCursor(0, y);
    display.print(">");
  } else {
    display.setCursor(116, y);
    display.print("<");
  }
}
chipaka пише:

У гувері є дві можливості встановлення на піксель та на рядок: oled.setCursorXY и oled.setCursor

У гувері робиться те ж саме: GyverOLED.h:361:

void setCursor(int x, int y) { setCursorXY(x, y << 3); }

`<< 3` - це те ж саме множення на 8.

Активний

#6 2025-05-24 16:40:38

jokeR
Учасник
Зареєстрований: 2024-12-12
Повідомлень: 89

Re: Переробляю скетч i2c на дисплей SPI OLED

ІЧСХ, такий запис множення тільки збиває з пантелику, смислу в ньому немає. Спеціально перевірив, в які команди проца компілюється ця конструкція.

    int y = 7;
    return y * 8

       

        ldi r24,lo8(7)
        ldi r25,hi8(7)
        std Y+2,r25
        std Y+1,r24
        ldd r24,Y+1
        ldd r25,Y+2
        lsl r24
        rol r25
        lsl r24
        rol r25
        lsl r24
        rol r25

       
       

     int y = 5;
    return y << 3;

   

        ldi r24,lo8(5)
        ldi r25,hi8(5)
        std Y+2,r25
        std Y+1,r24
        ldd r24,Y+1
        ldd r25,Y+2
        lsl r24
        rol r25
        lsl r24
        rol r25
        lsl r24
        rol r25 

Для проца різниці ніякої. А для людини є

    return y << 3 /* це множення чи зсув? треба врюхувати що курив автор */
    return y * 8 /* 8 - що за магічна константа? 
   особливо збс коли десь в іншому місці з"являється магічна константа 7, 
   і треба врюхувати, це 8-1 чи 0b0111 ци ще щось */
    return y * ROW_HEIGTH /* очевидно, це пов"язане з висотою рядка */

Короче, не треба писати незрозуміло.

Неактивний

#7 2025-05-24 17:13:31

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 428

Re: Переробляю скетч i2c на дисплей SPI OLED

jokeR пише:

Спеціально перевірив, в які команди проца компілюється ця конструкція.

Така перевірка не має сенсу, бо по-перше, ви множите константу на константу, по-друге, компілювали, мабуть, без оптимізації. З увімкненою оптимізацією константи помножаться під час компіляції, і буде повертатись просто константа.

Ардуіно фреймворк компілює з -Os. Обидва варіанти:

int mul8(uint8_t n)
{
    return n * 8;
}

int shl3(uint8_t n)
{
    return n << 3;
}

з оптимізацією по розміру (-Os) компілюються в однаковий код, який використовує інструкцію mul:

00000000 <_Z4mul8h>:
   0:   28 e0           ldi     r18, 0x08       ; 8
   2:   82 9f           mul     r24, r18
   4:   c0 01           movw    r24, r0
   6:   11 24           eor     r1, r1
   8:   08 95           ret

0000000a <_Z4shl3h>:
   a:   28 e0           ldi     r18, 0x08       ; 8
   c:   82 9f           mul     r24, r18
   e:   c0 01           movw    r24, r0
  10:   11 24           eor     r1, r1
  12:   08 95           ret

З оптимізацюєю по швидкодії (-O2) компілюються теж в однаковий код:

00000000 <_Z4mul8h>:
   0:   90 e0           ldi     r25, 0x00       ; 0
   2:   88 0f           add     r24, r24
   4:   99 1f           adc     r25, r25
   6:   88 0f           add     r24, r24
   8:   99 1f           adc     r25, r25
   a:   88 0f           add     r24, r24
   c:   99 1f           adc     r25, r25
   e:   08 95           ret

00000010 <_Z4shl3h>:
  10:   90 e0           ldi     r25, 0x00       ; 0
  12:   88 0f           add     r24, r24
  14:   99 1f           adc     r25, r25
  16:   88 0f           add     r24, r24
  18:   99 1f           adc     r25, r25
  1a:   88 0f           add     r24, r24
  1c:   99 1f           adc     r25, r25
  1e:   08 95           ret

Але вважаючи, що фреймворк також використовує оптимізацію на етапі лінковки (-flto), кінцевий код може бути зовсім іншим.

jokeR пише:

ІЧСХ, такий запис множення тільки збиває з пантелику, смислу в ньому немає.

Саме так. Гувер думав, що він розумніший за компілятор, але компілятор виявився розумніший. Компілятор знає, що у AVR нема інструкцій зсуву окрім як на один біт, зате є апаратний мультиплікатор.
Хоча загалом у gcc теж достатньо проблем з генерацією оптимального коду для AVR. 

Така "оптимізація" мала би сенс років 30 тому, і то тільки для процесорів, у яких або взагалі нема інструкцій множення, або якщо вони виконуються набагато довше ніж зсуви (як у 8086, наприклад).

Активний

#8 2025-05-24 17:44:48

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 428

Re: Переробляю скетч i2c на дисплей SPI OLED

dimich пише:

З оптимізацюєю по швидкодії (-O2) компілюються теж в однаковий код:

00000000 <_Z4mul8h>:
   0:   90 e0           ldi     r25, 0x00       ; 0
   2:   88 0f           add     r24, r24
   4:   99 1f           adc     r25, r25
   6:   88 0f           add     r24, r24
   8:   99 1f           adc     r25, r25
   a:   88 0f           add     r24, r24
   c:   99 1f           adc     r25, r25
   e:   08 95           ret

Цікаво, що цей код виконується навіть довше ніж той, що з -Os smile Схоже, розробники gcc зовсім забили на -O2/O3 для AVR. Все одно всі компілять з -Os.

Активний

#9 2025-05-24 20:39:27

chipaka
Учасник
Зареєстрований: 2024-04-27
Повідомлень: 11

Re: Переробляю скетч i2c на дисплей SPI OLED

Запрацювало. Дякую

Неактивний

Швидке повідомлення

Введіть повідомлення і натисніть Надіслати

Підвал форуму