Программируем Arduino. Профессиональная работа со скетчами. - страница 25

стр.

Попробуем выполнить следующую тестовую программу на Arduino и немного измененную ее версию — на моем Mac:

// sketch 04_01_benchmark

void setup()

{

  Serial.begin(9600);

  Serial.println("Starting Test");

  long startTime = millis();

  // Далее следует код тестирования

  long  i = 0;

  long j = 0;

  for (i = 0; i < 20000000; i ++)

  {

    j = i + i * 10;

    if (j > 10) j = 0;

  }

  // конец кода, выполняющего тестирование

  long endTime = millis();

  Serial.println(j); // чтобы предотвратить оптимизацию цикла компилятором

  Serial.println("Finished Test");

  Serial.print("Seconds taken: ");

  Serial.println((endTime — startTime) / 1000l);

}

void loop()

{

}


ПРИМЕЧАНИЕ

Версию программы на C для компьютера можно найти в разделе загрузки примеров на веб-сайте книги.

Вот какие результаты получились: на MacBook Pro с процессором 2,5 ГГц тестовая программа выполнялась 0,068 с, тогда как на Arduino Uno ей понадобилось 28 с. Плата Arduino оказалась примерно в 400 раз медленнее при решении данной задачи.


Сравнение плат Arduino

В табл. 4.1 показаны результаты выполнения этого теста в нескольких разных моделях платы Arduino.


Таблица 4.1. Результаты тестирования быстродействия Arduino

МодельВремя выполнения теста, с
Uno28
Leonardo29
Arduino Mini Pro28
Mega256028
Due2

Как видите, большинство моделей имеют схожую производительность, и только Due показала внушительный результат — она оказалась более чем в 10 раз быстрее остальных моделей.


Скорость арифметических операций

Для дальнейших исследований изменим только что использованный тест и вместо арифметики с длинными целыми протестируем быстродействие арифметики с вещественными числами. И те и другие занимают в памяти 32 бита, поэтому можно было бы ожидать, что время работы примера останется сопоставимым. В следующем тесте используем Arduino Uno.

// sketch 04_02_benchmark_float

void setup()

{

  Serial.begin(9600);

  while (! Serial) {};

  Serial.println("Starting Test");

  long startTime = millis();

  // Далее следует код тестирования

  long  i = 0;

  float j = 0.0;

  for (i = 0; i < 20000000; i ++)

  {

    j = i + i * 10.0;

    if (j > 10) j = 0.0;

  }

  // конец кода, выполняющего тестирование

  long endTime = millis();

  Serial.println(j); // чтобы предотвратить оптимизацию цикла компилятором

  Serial.println("Finished Test");

  Serial.print("Seconds taken: ");

  Serial.println((endTime — startTime) / 1000l);

}

void loop()

{

}

К сожалению, с использованием вещественных чисел этот скетч выполняется намного дольше. Этот пример выполнялся в Arduino около 467 с вместо 28 с. То есть простая замена длинных целых чисел вещественными уменьшила скорость выполнения более чем в 16 раз. Справедливости ради следует заметить, что отчасти ухудшение обусловлено дополнительными операциями преобразования между значениями вещественных и целочисленных типов, которые также обходятся недешево в смысле времени выполнения.


Нужны ли вещественные числа в действительности?

Многие ошибочно полагают, что если измеряется такая характеристика, как температура, ее значение обязательно следует хранить в виде вещественного числа, потому что оно часто будет выражаться дробным числом, таким как 23,5. Вещественное число действительно может понадобиться, чтобы отобразить температуру, но ее необязательно хранить именно в таком виде.

Значения, прочитанные с аналоговых входов, имеют тип int, и на самом деле значимыми являются только 12 бит, что соответствует целым числам в диапазоне между 0 и 1023. При желании можно, конечно, сохранить эти 12 бит в 32-битном вещественном числе, но это никак не отразится на точности данных.

Значение, читаемое с датчика, может соответствовать, например, температуре в градусах Цельсия. Широко известный температурный датчик (TMP36) выводит напряжение, пропорциональное температуре. В скетчах, как показано далее, часто можно увидеть вычисления, преобразующие значение в диапазоне 0…1023, прочитанное с аналогового входа, в температуру в градусах Цельсия:

int raw = analogRead(sensePin);

float volts = raw / 205.0;

float tempC = 100.0 * volts — 50;

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