Ви не увійшли.
Допоможіть!
Переробляю скетч 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 курсор можна встановлювати тільки за координатами х і у. Як зробити переміщення курсору рядками
Неактивний
В 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
Неактивний
Намалюйте пару рядків на листочку а клітинку. Порахуйте клітинки.
Якщо потрібна функція як у Гувера - ну, напишіть Можна навіть успадкувати свій клас від тої ліби і зробити як у Гувера.
Але тут курсор встановлюється на піксель.
Що у вас є `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("<");
}
}
У гувері є дві можливості встановлення на піксель та на рядок: oled.setCursorXY и oled.setCursor
У гувері робиться те ж саме: GyverOLED.h:361:
void setCursor(int x, int y) { setCursorXY(x, y << 3); }
`<< 3` - це те ж саме множення на 8.
Неактивний
ІЧСХ, такий запис множення тільки збиває з пантелику, смислу в ньому немає. Спеціально перевірив, в які команди проца компілюється ця конструкція.
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 /* очевидно, це пов"язане з висотою рядка */
Короче, не треба писати незрозуміло.
Неактивний
Спеціально перевірив, в які команди проца компілюється ця конструкція.
Така перевірка не має сенсу, бо по-перше, ви множите константу на константу, по-друге, компілювали, мабуть, без оптимізації. З увімкненою оптимізацією константи помножаться під час компіляції, і буде повертатись просто константа.
Ардуіно фреймворк компілює з -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), кінцевий код може бути зовсім іншим.
ІЧСХ, такий запис множення тільки збиває з пантелику, смислу в ньому немає.
Саме так. Гувер думав, що він розумніший за компілятор, але компілятор виявився розумніший. Компілятор знає, що у AVR нема інструкцій зсуву окрім як на один біт, зате є апаратний мультиплікатор.
Хоча загалом у gcc теж достатньо проблем з генерацією оптимального коду для AVR.
Така "оптимізація" мала би сенс років 30 тому, і то тільки для процесорів, у яких або взагалі нема інструкцій множення, або якщо вони виконуються набагато довше ніж зсуви (як у 8086, наприклад).
Неактивний
З оптимізацюєю по швидкодії (-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 Схоже, розробники gcc зовсім забили на -O2/O3 для AVR. Все одно всі компілять з -Os.
Неактивний