Почему эскизы занимают столько места и памяти?

Когда я скомпилирую этот эскиз для Yún:

int led = 7;

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

void loop() {
  digitalWrite(led, HIGH);
}

Я получаю:

  

В Sketch используется 5 098 байт (17%) пространства для хранения программ.

     

Максимум   28 672 байта. Глобальные переменные используют 153 байта (5%) динамической памяти,   оставив 2 407 байтов для локальных переменных. Максимум составляет 2,560 байт.

Даже когда я компилирую эскиз BareMinimum:

void setup() {                
  // setup    
}

void loop() {
  // loop
}

Я получаю:

  

В Sketch используется 4,548 байт (15%) пространства для хранения программ.

     

Максимум   28 672 байта. Глобальные переменные используют 151 байт (5%) динамической памяти,   оставив 2 409 байтов для локальных переменных. Максимум составляет 2,560 байт.

Почему минимальный минимальный эскиз занимает 15% выделенного пространства для программ? И почему очень простой эскиз занимает 17% пространства для хранения программ? Согласно веб-сайту Arduino :

  

Легко использовать все это, имея много строк в вашей программе.   Например, объявление типа: char message[] = "I support the Cape Wind project."; помещает 33 байта в SRAM (каждый символ принимает байт,   плюс терминатор '\ 0').

Однако в любом из этих эскизов нет ни одной строки.

Кажется, что они могут импортировать или использовать другие библиотеки /классы, которые я не укажу. Может быть, он импортирует библиотеку по умолчанию системы? Или это что-то еще?

11 голосов | спросил hichris123 22 FebruaryEurope/MoscowbSat, 22 Feb 2014 01:29:25 +0400000000amSat, 22 Feb 2014 01:29:25 +040014 2014, 01:29:25

4 ответа


6

YUN - это комбо. Part Arduino и Part OpenWRT (Linux). Ваш вопрос касается Ардуино. Где это на самом деле ATmega32u4, подобный Леонардо, а не UNO (ATmega328p). 32u4 (Leo) обменивается данными через виртуальные последовательные порты через USB (короткий ответ: это нужно поддерживать) , где UNO имеет настоящий последовательный порт (он же UART). Ниже приведена статистика построения различных типов плат для процессоров AVR.

Примечание. В UNO есть внешний чип, который преобразует USB в контакт DTR последовательного порта, который переключает контакт сброса ATmega328 при подключении, что вызывает перезагрузку загрузчика. В отличие от USB-устройства Leo /Yun от Serial, реализовано в прошивке 32u4. Следовательно, чтобы удаленно перезагружать чип Leo или YUU 32u4, загружаемая прошивка всегда должна поддерживать драйвер клиентской стороны USB. Которая потребляет приблизительно 4K.

Если USB не нужен, и других ресурсов библиотеки не было вызвано, как в случае BareMinimum.ino в UNO, для основной библиотеки Arduino требуется только приблизительно 466 байт.

компилировать статистику BareMinimum.ino на UNO (ATmega328p)

Sketch uses 466 bytes (1%) of program storage space. Maximum is 32,256 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2,039 bytes for local variables. Maximum is 2,048 bytes.

скомпилировать статистику BareMinimum.ino на Leonardo (ATmega32u4)

Sketch uses 4,554 bytes (15%) of program storage space. Maximum is 28,672 bytes.
Global variables use 151 bytes (5%) of dynamic memory, leaving 2,409 bytes for local variables. Maximum is 2,560 bytes.

скомпилировать статистику BareMinimum.ino на Yun (ATmega32u4)

Sketch uses 4,548 bytes (15%) of program storage space. Maximum is 28,672 bytes.
Global variables use 151 bytes (5%) of dynamic memory, leaving 2,409 bytes for local variables. Maximum is 2,560 bytes.
ответил mpflaga 22 FebruaryEurope/MoscowbSat, 22 Feb 2014 09:58:42 +0400000000amSat, 22 Feb 2014 09:58:42 +040014 2014, 09:58:42
7

Arduino компилируется во множество стандартных библиотек, прерываний и т. д. Например, функции pinMode и digitalWrite используют таблицу поиска для определения во время выполнения, которое GPIO регистрирует для записи данных. Другим примером является то, что Arduino отслеживает время, он определяет некоторые прерывания по умолчанию, и для всех этих функций требуется некоторое пространство. Вы заметите, что если вы продлеваете программу, нога будет немного изменяться.

Мне лично нравится программировать контроллеры с минимальным минимумом, без «раздувания», но вы быстро войдете в мир EE.SE и SO, потому что несколько простых в использовании функций больше не будут работать из коробки. Есть несколько альтернативных библиотек для pinMode и digitalWrite, которые скомпилируются в меньшую площадь, но имеют другие недостатки, такие как, например, статические скомпилированные контакты (где led не может быть переменной, но является константой).

ответил jippie 22 FebruaryEurope/MoscowbSat, 22 Feb 2014 01:36:27 +0400000000amSat, 22 Feb 2014 01:36:27 +040014 2014, 01:36:27
3

Я написал сообщение о Почему требуется 1000 байт, чтобы мигать одним светодиодом? .

Краткий ответ: «Не требуется 2000 байт, чтобы мигать два светодиода!»

Более длинный ответ заключается в том, что стандартные библиотеки Arduino (которые вам не нужно использовать, если вы не хотите), имеют приятную функциональность, чтобы упростить вашу жизнь. Например, вы можете адресовать контакты по номеру во время выполнения, где библиотека преобразует (скажем) вывод 8 в правильный порт и исправляет число бит. Если вы имеете доступ к жесткому коду, вы можете сохранить эти накладные расходы.

Даже если вы их не используете, стандартные библиотеки включают в себя код для подсчета «тиков», чтобы вы могли узнать текущее «время» (вызывая millis()). Для этого необходимо добавить накладные расходы некоторых процедур обслуживания прерываний.

Если вы упростите (на Arduino Uno) на этот эскиз, вы получите использование памяти программы до 178 байт (в IDE 1.0.6):

int main ()
  {
  DDRB = bit (5);
  while (true)
    PINB = bit (5);
  }

ОК, 178 байтов не так много, и первые 104 байта представляют собой аппаратные прерывания векторов (по 4 байта для 26 векторов).

Таким образом, для мигания светодиода требуется всего 74 байта. И из этих 74 байтов большинство на самом деле является кодом, сгенерированным компилятором для инициализации глобальной памяти. Если вы добавите достаточно кода для мигания двух светодиодов:

int main ()
  {
  DDRB = bit (5);  // pin 13
  DDRB |= bit (4);  // pin 12

  while (true)
    {
    PINB = bit (5); // pin 13
    PINB = bit (4); // pin 12
    }
  }

Затем размер кода увеличивается до 186 байтов. Поэтому вы можете утверждать, что для мигания светодиода требуется только 186 - 178 = 8.

Итак, 8 байт для мигания светодиода. Звучит довольно эффективно для меня.


В случае, если у вас возникает соблазн попробовать это дома, я должен указать, что, хотя выложенный код выше мигает двумя светодиодами, он делает это очень быстро. Фактически, они мигают на частоте 2 МГц - см. Снимок экрана. Канал 1 (желтый) - это контакт 12, канал 2 (голубой) - это контакт 13.

Быстрое мигание контактов 12 и 13

Как вы можете видеть, выходные выводы имеют прямоугольную волну с частотой 2 МГц. Контакт 13 изменяет состояние 62,5 нс (один такт) перед выводом 12 из-за порядка переключения контактов в коде.

Итак, если у вас не будет гораздо лучших глаз, чем у меня, вы не увидите никакого мигающего эффекта.


Как забавное дополнение, вы можете переключать два пика в тот же объем программного пространства, как на один вывод.

int main ()
  {
  DDRB = bit (4) | bit (5);  // set pins 12 and 13 to output

  while (true)
    PINB =  bit (4) | bit (5); // toggle pins 12 and 13
  } // end of main

Это компилируется в 178 байт.

Это дает вам более высокую частоту:

Очень быстрое мигание контактов 12 и 13

Теперь мы до 2,66 МГц.

ответил Nick Gammon 7 J000000Tuesday15 2015, 05:17:10
3

У вас уже есть отличные ответы. Я публикую это только для поделиться некоторыми статистическими данными, которые я сделал однажды, я спросил себя вопросы: что занимает столько места на минимальном эскизе? Что это минимум для достижения той же функциональности?

Ниже приведены три версии минимальной мигающей программы, которая переключает Светодиод на контакте 13 каждую секунду. Все три версии были скомпилированы для Uno (без участия USB) с использованием avr-gcc 4.8.2, avr-libc 1.8.0 и arduino-core 1.0.5 (я не использую IDE Arduino).

Во-первых, стандартный способ Arduino:

 const uint8_t ledPin = 13;

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

void loop() {
    digitalWrite(ledPin, HIGH);
    delay(1000);
    digitalWrite(ledPin, LOW);
    delay(1000);
}

Скомпилируется до 1018 байт. Использование avr-nm и разборка , Я разбил этот размер на отдельные функции. Из наименьшее:

 148 A ISR(TIMER0_OVF_vect)
 118 A init
 114 A pinMode
 108 A digitalWrite
 104 C vector table
  82 A turnOffPWM
  76 A delay
  70 A micros
  40 U loop
  26 A main
  20 A digital_pin_to_timer_PGM
  20 A digital_pin_to_port_PGM
  20 A digital_pin_to_bit_mask_PGM
  16 C __do_clear_bss
  12 C __init
  10 A port_to_output_PGM
  10 A port_to_mode_PGM
   8 U setup
   8 C .init9 (call main, jmp exit)
   4 C __bad_interrupt
   4 C _exit
-----------------------------------
1018   TOTAL

В приведенном выше списке первый столбец имеет размер в байтах, а второй в колонке указано, поступает ли код из основной библиотеки Arduino (A, 822 байта), время выполнения C (C, 148 байт) или пользователь (U, 48 байт).

Как видно из этого списка, наибольшей функцией является подпрограмма обслуживание прерывания переполнения таймера 0. Эта процедура несет ответственность за время отслеживания и требуется millis(), micros() и delay(). Второй по величине функцией является init(), который устанавливает аппаратные таймеры для PWM, позволяет TIMER0_OVF прерывать и отключать USART (что был использован загрузчиком). И эта, и предыдущая функция определенных в <Arduino directory>/hardware/arduino/cores/arduino/wiring.c.

Следующая версия C + avr-libc:

 #include <avr/io.h>
#include <util/delay.h>

int main(void)
{
    DDRB |= _BV(PB5);     /* set pin PB5 as output */
    for (;;) {
        PINB = _BV(PB5);  /* toggle PB5 */
        _delay_ms(1000);
    }
}

Разрушение отдельных размеров:

104 C vector table
 26 U main
 12 C __init
  8 C .init9 (call main, jmp exit)
  4 C __bad_interrupt
  4 C _exit
----------------------------------
158   TOTAL

Это 132 байта для среды выполнения C и 26 байтов кода пользователя, включая встроенная функция _delay_ms().

Можно отметить, что поскольку эта программа не использует прерывания, таблица векторов прерываний не требуется, а обычный код пользователя может быть поставлена ​​на его место. Следующая версия сборки делает точно что:

#include <avr/io.h>
#define io(reg) _SFR_IO_ADDR(reg)

    sbi io(DDRB), 5  ; set PB5 as output
loop:
    sbi io(PINB), 5  ; toggle PB5
    ldi r26, 49      ; delay for 49 * 2^16 * 5 cycles
delay:
    sbiw r24, 1
    sbci r26, 0
    brne delay
    rjmp loop

Он собран (с avr-gcc -nostdlib) только в 14 байтах, большинство из которых используются для задержки переключателей, так что мигает видимый. Если вы удалите этот цикл задержки, вы получите 6-байтовый программа, которая слишком быстро мигает, чтобы ее можно было увидеть (на частоте 2 МГц):

    sbi io(DDRB), 5  ; set PB5 as output
loop:
    sbi io(PINB), 5  ; toggle PB5
    rjmp loop
ответил Edgar Bonet 7 J000000Tuesday15 2015, 11:12:16

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132