Оптимизируем и уменьшаем размер программ Ардуино 9

В предыдущих статьях мы рассмотрели примеры прошивки контроллеров Ttiny13 Attiny2313
При программировании контроллеров, рано или поздно, мы сталкиваемся с проблемой нехватки памяти контроллера для загружаемой программы.
Для избежания этой проблемы необходимо соблюдать несколько правил при написания скетча:

Код программы, который нужно выполнить всего один раз за все время работы контроллера , нужно писать в

1
void setup(){}
void setup(){}

  • Такой код выполняется каждый раз при включении контроллера

Хороший пример:

1
2
3
4
5
6
7
8
9
10
int led = 13;
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
}
int led = 13;
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
}

Плохой пример:

1
2
3
4
5
6
7
8
9
10
void setup() {
}
void loop() {
    int led = 13;
    pinMode(led, OUTPUT);
    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
}
void setup() {
}
void loop() {
	int led = 13;
	pinMode(led, OUTPUT);
	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
}

Повторяющийся код следует выносить в отдельные процедуры, и в тех местах, где он использовался, вызывать эти процедуру.

  • Позволит сократить размер программы, количество кода и с легкостью вносить изменения в него.

Хороший пример(размер 694 байт):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int led = 13;
void setup() {
    pinMode(led, OUTPUT);
}
 
void loop() {
    led_switch();
}
void led_switch(){
    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(10000);
}
int led = 13;
void setup() {
	pinMode(led, OUTPUT);
}

void loop() {
	led_switch();
}
void led_switch(){
	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(10000);
}

Плохой пример(размер 1 128 байт):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int led = 13;
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(10000);
    
    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(10000);
}
int led = 13;
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(10000);
	
	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(10000);
}

Использовать только те типы переменных, которые действительно подходят под ваши задачи. Например, если переменная может принимать только два возможных значения, то ни в коем случае не нужно использовать текстовый или числовой тип. Достаточно будет воспользоваться логическим типом BOOLEAN.

  • Позволит сократить размер программы

Хороший пример(размер 1 340 байт):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int led = 13;
int pin1 = 12;
boolean a=false;
void setup() {
    pinMode(led, OUTPUT);
    pinMode(pin1, INPUT);
    if (digitalRead(pin1)==HIGH)
    {
        a=true;
    }
 
}
void loop() {
    if (!a){
        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(10000);
    }
    if (a){
        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(10000);
    }
}
int led = 13;
int pin1 = 12;
boolean a=false;
void setup() {
	pinMode(led, OUTPUT);
	pinMode(pin1, INPUT);
	if (digitalRead(pin1)==HIGH)
	{
		a=true;
	}

}
void loop() {
	if (!a){
		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(10000);
	}
	if (a){
		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(10000);
	}
}

Плохой пример(размер 1 352 байт):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int led = 13;
int pin1 = 12;
int a=0;
void setup() {
    pinMode(led, OUTPUT);
    pinMode(pin1, INPUT);
    if (digitalRead(pin1)==HIGH)
    {
        a=1;
    }
    
    }
void loop() {
    if (a==0){
        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(10000);
    }
    if (a==1){
        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(10000);
    }
}
int led = 13;
int pin1 = 12;
int a=0;
void setup() {
	pinMode(led, OUTPUT);
	pinMode(pin1, INPUT);
	if (digitalRead(pin1)==HIGH)
	{
		a=1;
	}
	
	}
void loop() {
	if (a==0){
		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(10000);
	}
	if (a==1){
		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(10000);
	}
}

В конце каждой строки старайтесь писать комментарий, что код данной строки выполняет.

  • Сделает ваш код понятным, даже спустя длительное время.

Не используйте переменные без необходимости.

  • Каждая объявленная переменная добавляет вес программе.

Хороший пример(размер 1 076 байт):

1
2
3
4
5
6
7
8
9
10
void setup() {
    pinMode(13, OUTPUT);
}
 
void loop() {
    digitalWrite(13, HIGH);
    delay(1000);
    digitalWrite(13, LOW);
    delay(1000);
}
void setup() {
	pinMode(13, OUTPUT);
}

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

Плохой пример(размер  1 084 байт):

1
2
3
4
5
6
7
8
9
10
11
int led = 13;
void setup() {
    pinMode(led, OUTPUT);
}
 
void loop() {
    digitalWrite(led, HIGH);
    delay(1000);
    digitalWrite(led, LOW);
    delay(1000);
}
int led = 13;
void setup() {
	pinMode(led, OUTPUT);
}

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

Не пишите все проверяемые аргументы в одном операторе условия (IF)

  • Позволит сократить время выполнения программы

Хороший пример(размер 466 байт):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int ex = 1;
int ex2 = 0;
int ex3 = 1;
 
void setup() {
 
}
 
void loop() {
    if (ex==1){
        if (ex2==1){
            if (ex3==1){
            
            }
        }
    }
}
int ex = 1;
int ex2 = 0;
int ex3 = 1;

void setup() {

}

void loop() {
	if (ex==1){
		if (ex2==1){
			if (ex3==1){
			
			}
		}
	}
}

Плохой пример(размер 466 байт):

1
2
3
4
5
6
7
8
9
10
11
12
13
int ex = 1;
int ex2 = 0;
int ex3 = 1;
 
void setup() {
 
}
 
void loop() {
    if (ex==1 and ex2==1 and ex3==1){
    
    }
}
int ex = 1;
int ex2 = 0;
int ex3 = 1;

void setup() {

}

void loop() {
	if (ex==1 and ex2==1 and ex3==1){
	
	}
}

Управляйте портами через регистры

  • Позволит сократить не только размер программы но и ее время выполнения

Хороший пример(размер 478 байт):

1
2
3
4
5
DDRD = DDRD | B11110000;
}
void loop() {
    PORTD |= B11110000;
}
DDRD = DDRD | B11110000;
}
void loop() {
	PORTD |= B11110000;
}

Плохой пример(размер 914 байт):

1
2
3
4
5
6
7
8
9
10
11
12
13
void setup() {
    pinMode(7, OUTPUT);
    pinMode(6, OUTPUT);
    pinMode(5, OUTPUT);
    pinMode(4, OUTPUT);
}
 
void loop() {
    digitalWrite(7, HIGH);
    digitalWrite(6, HIGH);
    digitalWrite(5, HIGH);
    digitalWrite(4, HIGH);
}
void setup() {
	pinMode(7, OUTPUT);
	pinMode(6, OUTPUT);
	pinMode(5, OUTPUT);
	pinMode(4, OUTPUT);
}

void loop() {
	digitalWrite(7, HIGH);
	digitalWrite(6, HIGH);
	digitalWrite(5, HIGH);
	digitalWrite(4, HIGH);
}

При анализе одной переменной используйте IF ELSE IF вместо IF IF

  • Позволит сократить количество тактов на выполнение программы

Плохой пример:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int led = 13;
int pin1 = 12;
boolean a=false;
void setup() {
    pinMode(led, OUTPUT);
    pinMode(pin1, INPUT);
    if (digitalRead(pin1)==HIGH)
    {
        a=true;
    }
 
}
void loop() {
    if (!a){
        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(10000);
    }
    if (a){
        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(10000);
    }
}
int led = 13;
int pin1 = 12;
boolean a=false;
void setup() {
	pinMode(led, OUTPUT);
	pinMode(pin1, INPUT);
	if (digitalRead(pin1)==HIGH)
	{
		a=true;
	}

}
void loop() {
	if (!a){
		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(10000);
	}
	if (a){
		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(10000);
	}
}

Хороший пример:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int led = 13;
int pin1 = 12;
boolean a=false;
void setup() {
    pinMode(led, OUTPUT);
    pinMode(pin1, INPUT);
    if (digitalRead(pin1)==HIGH)
    {
        a=true;
    }
    
}
void loop() {
    if (!a){
        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(10000);
    } else if (a){
        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(10000);
    }
}
int led = 13;
int pin1 = 12;
boolean a=false;
void setup() {
	pinMode(led, OUTPUT);
	pinMode(pin1, INPUT);
	if (digitalRead(pin1)==HIGH)
	{
		a=true;
	}
	
}
void loop() {
	if (!a){
		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(10000);
	} else if (a){
		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(10000);
	}
}

И самое главное правило — Читайте мануалы, ридми и описания всех библиотек с которыми работаете.

Итак, какие-же плюсы мы получим при соблюдении всех этих правил:

  • Меньше размер программ
  • Понятнее и читабельнее код программы
  • Вспомнить программу спустя длительное время будет проще

Минусы оптимизации программ:

  • Время, затраченное на оптимизацию

Вывод делайте сами.

9 комментс для “Оптимизируем и уменьшаем размер программ Ардуино

  1. Ответить Tomasina Мар 31, 2014 17:27

    Код отформатировать правильно бы, с отступами, люди же повторять за вами станут 🙂

    В конце каждой строки старайтесь писать комментарий, что код данной строки выполняет.

    Если переменные названы логично, то в большинстве мест необходимость в комментарии отпадает — читая код, все очевидно. А комментарии использовать там, где нужны пояснения, почему сделано именно так. Согласны?

    Использовать только те типы переменных, которые действительно подходят под ваши задачи.
    Хороший пример(размер 1 340 байт):
    int led = 13;
    int pin1 = 13;
    boolean a=false;
    void setup() {
    pinMode(led, OUTPUT);
    pinMode(pin1, INPUT);
    if (digitalRead(pin1)==HIGH)
    {
    a=true;
    }

    }
    void loop() {
    if (!a){
    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(10000);
    }
    if (a){
    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(10000);
    }
    }

    Это ОЧЕНЬ плохой пример.
    1. Зачем для пинов резервировать область размером 2 байта (65535)?
    2. В строке 5 мы назначаем пин 13 как выход, затем в строке 6 мы ЭТОТ ЖЕ пин определяем как выход 🙂
    3. Блоки if выполняют одно и то же, т.е. системе пофиг какое сейчас состояние, действия те же самые. Зачем тогда выполнять проверку? Ладно, отнесем это на недоработки при спешке %)
    4. Если мы в блоке if проверяем логическую переменную, т.е. имеющую всего 2 состояния то выгоднее сравнивать как if-else, а не if-if, тем самым экономим 4-16 тактов процессорного времени, т.е. чуть увеличиваем быстродействие.

    Я бы еще добавил правило: Использовать для глобальных переменных внятные названия. Если код большой, то через полгода хрен разберешь, за что отвечает переменная a, но ежели ее обозвать stateButtonA, то весь блок if читается без остановки и размышлений.

    Тогда полуправильный пример будет выглядеть так (1322 байта против ваших 1340):
    [code]
    const byte ledSectorA = 13;
    const byte pinSectorA = 13;
    boolean stateSectorA = false;

    void setup()
    {
    pinMode(ledSectorA, OUTPUT);
    pinMode(pinSectorA, INPUT);
    if (digitalRead(pinSectorA) == HIGH)
    {
    stateSectorA = true;
    }

    }
    void loop()
    {
    if (!stateSectorA)
    {
    digitalWrite(ledSectorA, HIGH); // turn the LED on (HIGH is the voltage level)
    delay(1000); // wait for a second
    digitalWrite(ledSectorA, LOW); // turn the LED off by making the voltage LOW
    delay(10000);
    }
    if (stateSectorA)
    {
    digitalWrite(ledSectorA, HIGH); // turn the LED on (HIGH is the voltage level)
    delay(1000); // wait for a second
    digitalWrite(ledSectorA, LOW); // turn the LED off by making the voltage LOW
    delay(10000);
    }
    }
    [/code]
    А совсем правильный так (1266 байт против ваших 1340):

    #define ledSectorA 13
    #define pinSectorA 7
    boolean stateSectorA = false;

    void setup()
    {
    pinMode(ledSectorA, OUTPUT);
    pinMode(pinSectorA, INPUT);
    if (digitalRead(pinSectorA) == HIGH)
    {
    stateSectorA = true;
    }

    }

    void loop()
    {
    if (stateSectorA)
    {
    digitalWrite(ledSectorA, HIGH); // turn the LED on (HIGH is the voltage level)
    delay(1000); // wait for a second
    digitalWrite(ledSectorA, LOW); // turn the LED off by making the voltage LOW
    delay(10000);
    }
    else
    {
    digitalWrite(ledSectorA, HIGH); // turn the LED on (HIGH is the voltage level)
    delay(5000); // wait for a second
    digitalWrite(ledSectorA, LOW); // turn the LED off by making the voltage LOW
    delay(10000);
    }
    }

    • Ответить Slava Мар 31, 2014 19:35

      Код отформатировать правильно бы, с отступами, люди же повторять за вами станут 🙂

      К сожалению парсер кода, удаляет отступы (((
      Но, удалось исправить

      1. Зачем для пинов резервировать область размером 2 байта (65535)?

      Согласен, не акцентировал на это внимание

      2. В строке 5 мы назначаем пин 13 как выход, затем в строке 6 мы ЭТОТ ЖЕ пин определяем как выход 🙂

      Спасибо за указание опечатки, исправил

      3. Блоки if выполняют одно и то же, т.е. системе пофиг какое сейчас состояние, действия те же самые. Зачем тогда выполнять проверку? Ладно, отнесем это на недоработки при спешке %)

      Суть не в начинке, а в оболочке )))

      4. Если мы в блоке if проверяем логическую переменную, т.е. имеющую всего 2 состояния то выгоднее сравнивать как if-else, а не if-if, тем самым экономим 4-16 тактов процессорного времени, т.е. чуть увеличиваем быстродействие.

      Я бы еще добавил правило: Использовать для глобальных переменных внятные названия. Если код большой, то через полгода хрен разберешь, за что отвечает переменная a, но ежели ее обозвать stateButtonA, то весь блок if читается без остановки и размышлений.

      Думаю это стоит вынести в отдельное правило.

  2. Ответить Артём Июн 8, 2014 19:00

    При попытке записать «DDRD = DDRD | B11110000;», программа пишет «sketch_jun08a.ino: In function ‘void setup()’:
    sketch_jun08a:4: error: ‘DDRD’ was not declared in this scope»?

  3. Ответить Артём Июн 9, 2014 18:36

    Да точно(тини13), спасибо! А где можно подробней почитать про эти «короткие» команды, а то порт я определил, но светодиод не заморгал (PORTB |= B00001000;)?

  4. Ответить Константин Ноя 22, 2014 11:05

    int led = 13;
    void setup() {
    pinMode(led, OUTPUT);
    }

    void loop() {
    led_switch;
    }
    void led_switch(){
    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(10000);
    }

    этот скетч не работает. Почему? Если вытащить всё из функции led_switch и просто вставить в loop, то всё ок

  5. Ответить Сергей Янв 28, 2016 11:54

    Везде где используются строки для вывода использовать функцию F() флеш памяти много больше, например Serial.println( F(«My big string») ); в Ардуино удобно просто многие строки обернуть в F() что существенно сократит использование динамической памяти, каждый символ ест память, по сравнению с этим многие способы оптимизации вносят не существенный вклад, хотя все конечно зависит от проекта, очень сильно выручило в свое время, можно много больше вещей делать на том же железе. Успехов.

  6. Ответить Олег Дек 7, 2016 19:33

    Сергей, а где можно почитать про эту обертку F()?
    С применением проблем нет, а вот теорию узнать хотелось бы.

Добавить комментарий