Як справді скоротити ескіз


9

Я хочу зробити ескіз, якомога менший, для тестових цілей. Проблема полягає в тому, що коли я складаю ескіз BareMinimum (з порожнім налаштуванням і циклом), я отримую 466 байт для Uno і колосальних 4 422 для Леонардо. Чи є спосіб написати власний код, який не має додаткових функцій (а саме Timer0 для millis()і delay()). Я також хотів би мати можливість відключити функції клавіатури / миші для Леонардо.


4
Чи не слід цього позначати леонардо, а не uno (і зосередити увагу на одній дошці)? Це окремі запитання.
asheeshr

Я просто вказую, що пустий скомпільований ескіз великий для багатьох плат, особливо рідних на базі USB
TheDoctor

Я також хотів би мати можливість відключити функції клавіатури / миші для Леонардо. є другим питанням.
asheeshr

Відповіді:


3

Ви повинні мати можливість створити власне визначення дошки за допомогою спеціального файлу Board.txt відповідно до https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification . Як я бачу, у визначенні леонардо є кілька функцій usb. Я би сподівався, що компіляція включення 4K базується на цих прапорах, а не на процесорі.

Там, де Board.txt буде використовувати завантаження, розділи завантажувача з Леонардо та збірку з uno.

Це все припускаючи, що в складі основної бібліотеки не використовуються специфічні для процесора прапори для включення функцій USB.

Якщо ви працюєте таким. Повідомлення назад, я впевнений, що інші будуть зацікавлені в такому.


Нещодавно я наткнувся на це використання 4K обмеження на демонстрацію бібліотеки, яка фактично склала UNO і довелося ввести

#if !defined(__AVR_ATmega32U4__)
...

навколо великого шматка додаткових функцій у ескізі, що підходить до Леонардо.

Я припускав (неправильно), що це 4K, тому що я все ще включав Serial.print, який передавав CDC USB на Leo. Але я бачу після скидання пам’яті порожній ескіз, вони все ще є.

C:\Users\mflaga\AppData\Local\Temp\build8958339595868119500.tmp>avr-objdump -d sketch_feb13a.cpp.elf > sketch_feb13a.cpp.elf.lst

Що має сенс. Оскільки Леонардо все ще вимагає клієнта USB-CDC (4K) для виявлення з'єднання 1200 Baud від AVR-DUDE, щоб погладити віддалену перезавантаження.


Отже, виготовлення користувальницьких плат.txt без USB у збірці також має бути

leonardo.upload.use_1200bps_touch=true

вилучено.

Після завантаження в ціль, це вимагатиме синхронізації завантаження з ручним скиданням цілі. Як втрачається здатність до віддаленої перезавантаження.


оновлено, чому 4K все ще збирається, навіть якщо Serial.print опущений.
mpflaga

3

Нещодавно я хотів зробити саме це. Оскільки не існує хороший спосіб зробити це, я завівся писати патч для Stino піднесеного-тексту Arduino плагіна , щоб зробити саме це. Згодом це було прийнято, тому воно повинно бути в будь-яких сучасних установках Stino.

Це додає нового варіанту для Stino:

введіть тут опис зображення

Використання цього режиму дає результати компіляції, такі:

Для Uno:

Розмір двійкового ескізу: 172 байти (максимум 32256 байт, 0,53 відсотка).
Орієнтовне використання пам'яті: 0 байт (з 1024 байт максимум, 0,00 відсотків).

Для леонардо

Розмір двійкового ескізу: 240 байт (максимум 28672 байт, 0,84 відсотка).
Орієнтовне використання пам'яті: 0 байт (максимум 2560 байт, 0,00 відсотків).

Насправді програмування леонардо на вищезгаданому складеному виході - це, мабуть, погана ідея, оскільки це може порушити функцію автоматичного скидання, але ви могли , якщо хочете. Hat-tip mpflaga за те, що зазначив це у своїй відповіді.

Зауважте, що звіти про пам’ять насправді є невірними, але це окрема проблема .

Код, використаний для вищезазначеного:

int main()
{
    while (1)
    {

    }
}

Деякі примітки:

  • Ви не пишете «ескіз» більше, що не то, що ви коли - небудь на самому ділі зробити написати ескіз. Ви пишете програми . Період. Мені байдуже, що хочуть сказати вакуйоми Arduino, вони не можуть переробити терміни.
  • Весь керування перервами є ручним. Це означає, що немає milis()або подібне.
  • Ви все ще можете використовувати послідовну бібліотеку arduino тощо, якщо хочете. Ви повинні #include <Arduino.h>.
  • Ви визначаєте main. Ви ніколи не повертаєтесь звідти main. Якщо ви хочете налаштувати речі, це буде раніше while (1).

@jfpoilpret Ви називаєте це IDE? Більше нагадує блокнот з макросами ...
Рон

@ Ron-E Я не називаю це IDE, Arduino IDE - це його ім'я, тому я просто використав його ім'я, хоча це ім'я не варто.
jfpoilpret

2
@FakeName На веб-сайтах Stack Exchange заборонена мова (див .: stackoverflow.com/help/behavior ). Я відредагував це в цьому випадку, але будь-ласка, намагайтеся утриматися від використання експлікатів на цьому веб-сайті в майбутньому. Дякую.
Пітер Блумфілд

2

Хоча це залежить від вашого ескізу, ви можете дещо зменшити розмір, повторно використовуючи код методами.

Візьміть цей код:

int led = 13;
int val;

void setup() {                
  pinMode(led, OUTPUT);     
}

void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  val = digitalRead(10);
}

1322 байти на Arduino Uno. Тепер трохи зменшимо:

int led = 13;
int val;

void setup() {                
  pinMode(led, OUTPUT);     
}

void loop() {
  for(uint8_t i = 0; i < 8; i++) {
    blink(HIGH);
    blink(LOW);
  }    
  val = digitalRead(10);
}

void blink(uint8_t state) {
  digitalWrite(led, state);   // turn the LED to the right state
  delay(1000);                // wait for a second
}

1194 байт. Це приблизно на 10% зменшення!

У будь-якому випадку, хоча це не сильно зменшує ескіз, іноді це може бути найпростіший маршрут, коли ви перебуваєте на два байти за межею, або просто хочете зробити більш компактний ескіз для початку, не втрачаючи жодної функціональності. Це не для кожної ситуації, але я вважаю це корисним часом.


Як правило, якщо ви витягнете код з функцій, компілятор зробить важку роботу і все інше підійде саме вам.
Кібергібони

@Cybergibbons Чи можете ви визначити це [для користувачів, які не знайомі з цим]?
Анонімний пінгвін

3
Якщо ви виділите код у функцію, і він не є ефективним, компілятор, як правило, буде вбудований у нього. Однак компілятор ніколи не розбиває код на функції. Тому майже завжди краще написати більше функцій.
Кібергібони

1
Плюс введення коду у функції набагато простіше читати та розуміти

Використовуючи прямий доступ до порту, розмір зменшується до 646 байт. Використовуючи лише avr-libc (без ядра Arduino), він зменшується до 220 байт.
Едгар Бонет

0

@annonomus пінгвін, впевнений, що ми можемо. Хоча код збирається в 1180 байт флеш + 13 байт оперативної пам’яті для уно на моєму комп’ютері, ми можемо вдосконалити його :), тому виклик для гольфу прийнятий, а також кілька корисних порад, оскільки ми працюємо в навчання.

Крок 1: зменшення вимог до змінних. Використання int для led порту здається трохи надмірним, ми, звичайно, не маємо 65535 адресних портів IO на arduino :) Отже, ми змінюємо його на байт тільки для задоволення. Пізніше ми змінимо його на #define, але щоб показати вплив використання занадто великих типів змінних.

byte led = 13;
int val;

void setup() {                
  pinMode(led, OUTPUT);     
}

void loop() {
  blink();
  val = digitalRead(10);
}

void blink() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

Компілюється в 1172 байти + 13 байт оперативної пам’яті. Це економить 8 байт спалаху за рахунок меншої кількості необхідних операцій для байта замість цілого числа. Я б очікував 12 байт оперативної пам'яті, але добре. Не так багато, але кожен збережений байт - це добре.

Крок 2: змінити змінну на визначає, коли це має сенс. Наприклад, приведений байт не потрібен, штифт не розпаяється сам.

#define LED 13
int val;

void setup() {                
  pinMode(LED, OUTPUT);     
}

void loop() {
  blink();
  val = digitalRead(10);
}

void blink() {
  digitalWrite(LED, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(LED, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

Компілюється в 1142 байт-флаш + 11 байт таран. Вже збережено 38 байт. Це пов’язано з меншою кількістю операцій реєстрації, необхідних для отримання значення int. Також ми зберегли 2 байти від оперативної пам'яті. (все ще цікаво, чому байт не компілюється в 1 менший байт оперативної пам'яті .....)

Крок 3: оптимізуйте код. Я бачу 2 затримки. Цікаво, якщо я зміню його на 1 затримку, це заощадить простір, але я повинен з'ясувати значення світлодіодного штифта і перемкнути (інвертувати) його. Ми можемо це зробити з digitalRead (), але чи економить це місце?

#define LED 13
int val;
void setup() {                
  pinMode(LED, OUTPUT);     
}
void loop() {
  blink();
  val = digitalRead(10);
}
void blink() {
  digitalWrite(LED, !digitalRead(LED));   // toggle the led based on read value
  delay(1000);               // wait for a second and spare yourself the other delay
}

Компілюється в 1134 байт + 11 байт таран. Так! ще 8 байт. Це загалом складає 46 байт та 2 менших рядки коду.

Також ще одна загальна порада щодо зменшення кодового розміру. Не використовуйте клас String. ВЕЛИЧЕЗНО, дізнайтеся, як боротися з масивами char, strcpy (), strcmp (). Якщо у вас є кілька основних рядкових операцій, використання класу String - це здебільшого просто витрачання місця як на флеш, так і на оперативну пам'ять.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.