Ви не увійшли.
...
Дякую за розгорнуту відповідь. Даташит я читав (в моєму про це написано в розділі 14).
Мій працюючий варіант:
SMCR=1; // in setup()
__asm__("sleep/n/t") ; // in loop()
І ніяких бібліотек. Цікаво, що ще пару днів тому я так вже робив. Не запрацювало з-за того, що забув /n/t. Переглянувши бібліотеку зрозумів, у чому був косяк.
Остання редакція MikeM (2025-08-28 11:32:04)
Неактивний
Не запрацювало з-за того, що забув /n/t.
Не зрозумів роль /n/t
І ніяких бібліотек.
А SMCR, по-вашому, де визначено? На avr-libc і весь ардуіно фреймворк побудований, так що це як раз із бібліотекою. Тільки замість бібліотечної функції чи макроса прямий доступ до регістра. Цілком можна і так, якщо не планується компілювати для контролерів, у яких sleep modes визначаються не через SMCR.
Цікаво, що ще пару днів тому я так вже робив. Не запрацювало з-за того, що забув /n/t. Переглянувши бібліотеку зрозумів, у чому був косяк.
Дивно, бо для єдиної інструкції у виразі в asm це не має значення. А для кількох інструкцій без \n була б синтаксична помилка.
Не зрозумів роль /n/t
\n для асемблера, бо компілятор спочатку зклеює сусідні строкові літерали, потім передає асемблеру. А асемблеру потрібно розрізняти рядки з мнемоніками. Але для єдиної інструкції це не обовʼязково.
\t для краси, щоби при виводі асемблерного лістингу наступний рядок був з відступом.
Неактивний
Більше тижня нічого не писав, бо дуже ретельно працював над проектом. Схоже, те, що було потрібно, отримав. Вийшло виводити на екран 24 текстових рядків по 16 символів плюс 6 інтервалів. Є ідея, як подвоїти кількість символів в рядку за допомогою зовнішньої мікросхеми. Але реалізацію відклав з огляду на поточну неактуальність.
А от ще одну ідею реалізував і екран у мене тепер кольоровий. Що цікаво, навантаження на процессор практично не зросло.
Дякую усім, хто допомагав.
Найскладнішим виявився такий фрагмент:
У 32-розрядному слові в бітах з 12 по 27 міститься двійковий код 16-розрядного числа з фіксованою крапкою. Старші 9 бітів містять цілу частину, молодші 7 бітів - дробову. Потрібно перетворити його в 6-байтовий код для відображення на екран (по одній двійково-десятковій цифрі в байті).
Задача здається нескладною, але це все треба зробити швидше, ніж за 25 мікросекунд (на 16 МГц 8-бітному Arduino).
Це не прохання про допомогу (у мене вже все працює). Це ідея "задачі вихідного дня" для реально творчіх особистостей. Якщо хтось зацікавиться, спробуйте.
Цікаво, яким буде найменший час.
Остання редакція MikeM (2025-09-05 22:06:41)
Неактивний
У 32-розрядному слові в бітах з 12 по 27 міститься двійковий код 16-розрядного числа з фіксованою крапкою. Старші 9 бітів містять цілу частину, молодші 7 бітів - дробову. Потрібно перетворити його в 6-байтовий код для відображення на екран (по одній двійково-десятковій цифрі в байті).
Задача здається нескладною, але це все треба зробити швидше, ніж за 25 мікросекунд (на 16 МГц 8-бітному Arduino).
Якщо правильно зрозумів вхідний та вихідний формати, то дві таблиці з десятковими цифрами, 3 * (512 + 128) = 1920 байт флеша. Навіть "в лоб", без низькорівневої оптимізації:
const char PROGMEM intr[512 * 3] = {
0, 0, 0,
0, 0, 1,
...
5, 1, 0,
5, 1, 1
};
const char PROGMEM frac[128 * 3] = {
0, 0, 0,
0, 0, 8,
...
9, 8, 4,
9, 9, 2
};
char out[6];
void convert(uint32_t n)
{
char *dst = out;
const char *src = intr + 3*((n >> 19) & 511);
*dst++ = pgm_read_byte(src++);
*dst++ = pgm_read_byte(src++);
*dst++ = pgm_read_byte(src++);
src = frac + 3*((n >> 12) & 127);
*dst++ = pgm_read_byte(src++);
*dst++ = pgm_read_byte(src++);
*dst++ = pgm_read_byte(src++);
}
виходить щось біля сотні тактів, десь 7 мкс.
Звісно, BCD можна упакувати. Тоді таблиці будуть менші, але виконання трохи довшим.
Остання редакція dimich (2025-09-06 10:19:40)
Неактивний
Прикольно я заходився гуглити швидкий алгоритм ділення на 5
але там дофіга асемблера, і враховувати такти не дуже й хотілось
Звісно, BCD можна упакувати. Тоді таблиці будуть менші, але виконання трохи довшим.
А якщо правильно упакувати, то і таблиці в півтора раза менші, і виконання навіть швидше. Має вийти десь 5.5 мкс.
const uint16_t PROGMEM intr[512] = { 0x000, 0x001, ... 0x510, 0x511 };
const uint16_t PROGMEM frac[128] = { 0x000, 0x008, ... 0x984, 0x992 };
char out[6];
void convert(uint32_t n)
{
char *dst = out;
uint16_t d;
d = pgm_read_word(intr + ((n >> 19) & 511));
*dst++ = d >> 8;
*dst++ = (d >> 4) & 0xf;
*dst++ = d & 0xf;
d = pgm_read_word(frac + ((n >> 12) & 127));
*dst++ = d >> 8;
*dst++ = (d >> 4) & 0xf;
*dst = d & 0xf;
}
Неактивний
Звичайно, обробки, швидше ніж таблична, не існує.
Та не завжди. Залежить від алгоритму та особливостей архітектури. Хоча, спеціалізовані інструкції, по суті, на таких же "таблицях" реалізовані, тільки вони містяться на самому кристалі.
Звісно, в загальному випадку нічого швидше за O(1) не існує, але в конкретних випадках бувають нюанси. В мультизадачному середовищі взагалі, ще питання, що краще: виконати кілька додаткових інструкцій, чи лазити в таблицю через спільний кеш.
Однак, не варто було одразу викладати код. JOKEERу весь кайф обламали.
Вибачте, не хотів. Здавалось очевидним. Але там є ще простір для подальшої оптимізації
Неактивний