Измерение времени выполнения команды (в цикле)

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

for (int i = 1; i <= 5000; i++) {
          meas = analogRead(PIN_A0);
          sum = sum + meas*meas;
          }

Хочу сделать вольтметр для ЛБП, но он ещё должен показывать среднеквадратичное значение шумов и пики на выходе ЛБП. Для реализации нужно понять как быстро я смогу обрабатывать массив измерений.

Измерения показывают 1676 мкс, но это не реально, видно что программа зависает секунды на 2 для расчета. Что происходи не понятно, как будто код выполняется не лтнейно, в serial monitor появляются первые две буквы от “START” потом зависание и потом мгновенно выдается результат 1676 мкс.

Если что вот весь код проекта.

Спойлер
#include <GyverLBUF.h>
#include <TimerMs.h>
#include <GyverOLED.h>

TimerMs tmr_v_now(2, 1, 0);
TimerMs tmr_heartbeat_13(1000, 1, 0);
//TimerMs tmr_v_rms(100000, 1, 0);
TimerMs tmr_display_v_now(100, 1, 0);
TimerMs tmr_display_v_rms(1000, 1, 0);

GyverLBUF<uint16_t, 64> V_buf;
GyverOLED<SSD1306_128x32> oled(0x3C);

float analogReference_k = 4.096;
uint16_t analogReadResolution_k = 4095;
float v_divider_k = 7.657;                  // R1=1811 R2=12170  k = R1+R2/R1 = 7.720  (эксперементально = 7.652)
float v_divider_Vpkpk_k = v_divider_k;      // Vpk-pk correction
float v_divider_Vrms_k= 6.56;

const uint8_t bitmap_32x32[] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0xE0, 0xF0, 0x70, 0x70, 0x30, 0x30, 0x30, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF0, 0x70, 0x30, 0x30, 0x20, 0x00, 0x00,
  0x00, 0x30, 0x78, 0xFC, 0x7F, 0x3F, 0x0F, 0x0F, 0x1F, 0x3C, 0x78, 0xF0, 0xE0, 0xC0, 0x80, 0x80, 0x80, 0x40, 0xE0, 0xF0, 0xF8, 0xFC, 0xFF, 0x7F, 0x33, 0x13, 0x1E, 0x1C, 0x1C, 0x0E, 0x07, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF9, 0xF7, 0xEF, 0x5F, 0x3F, 0x7F, 0xFE, 0xFD, 0xFB, 0xF1, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x1E, 0x33, 0x33, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x1F, 0x0E, 0x04, 0x00, 0x00, 0x00, 0x00,
};

uint16_t V_buf_medium = 0;
uint32_t V_buf_summ = 0;
uint32_t V_buf_rms = 0;
int16_t V_buf_element_deviation = 0;
uint32_t V_buf_element_deviation_sqr = 0;
uint16_t V_buf_element_deviation_max = 0;
uint32_t V_buf_element_deviation_max_sqr = 0;
uint32_t V_buf_elements_deviation_sqr_sum = 0;
/*
  //  TYPE - указанный при инициализации тип данных
      void write(TYPE newVal);        // добавить в буфер
      void write(int num, TYPE val);  // запись в буфер по номеру num
      TYPE read(int num);             // чтение из буфера
      int size();                     // размер буфера
  */

void setup() {
  analogReference(INTERNAL4V096);     // внктренне опорное АЦП
  analogReadResolution(12);           // DAC resolution
  DDRB = 0b00100000;                  // pinMode(PIN_A13, OUTPUT);
  PORTB ^= (1<<PORTB5);               // led bit inverter
  pinMode(PIN_A0, INPUT);
  tmr_v_now.setPeriodMode();
  //tmr_v_rms.setPeriodMode();
  Serial.begin(9600);
  oled.init();
  oled.setContrast(180);
  oled.setScale(3);
  oled.clear();
  oled.update();

  Serial.println();
  Serial.println("Starting...");
}

void loop() {

  if (tmr_heartbeat_13.tick()) {
    PORTB ^= (1<<PORTB5);
  }

  if (tmr_v_now.tick()) {
    V_buf.write(analogRead(A0));
  }

  if (tmr_display_v_now.tick()) {
    V_buf_summ = 0;
    for (int i = 0; i < V_buf.size(); i++) {
      V_buf_summ = V_buf_summ + V_buf.read(i);
    }
    V_buf_medium = V_buf_summ / V_buf.size();
    float V_buf_medium_volt = (V_buf_medium * analogReference_k) / analogReadResolution_k * v_divider_k;
    oled.setScale(1);
    oled.home();
    oled.print("V=");
    oled.print(V_buf_medium_volt, 3);
    oled.update();
    //Serial.print(V_buf_medium_volt, 3);
    //Serial.print(" === ");
    //Serial.println(V_buf_medium);
  }

  if (tmr_display_v_rms.tick()) {

    V_buf_summ = 0;
    V_buf_rms = 0;
    V_buf_element_deviation = 0;
    V_buf_element_deviation_sqr = 0;
    V_buf_element_deviation_max = 0;
    V_buf_element_deviation_max_sqr = 0;
    V_buf_elements_deviation_sqr_sum = 0;

    for (int i = 0; i < V_buf.size(); i++) {
      V_buf_element_deviation = V_buf_medium - V_buf.read(i);
      V_buf_element_deviation_sqr = V_buf_element_deviation * V_buf_element_deviation;      // квадрат отклонения элемента
      V_buf_elements_deviation_sqr_sum = V_buf_elements_deviation_sqr_sum + V_buf_element_deviation_sqr;  // сумма квадратов отклонения элементов
      
      if (V_buf_element_deviation_sqr > V_buf_element_deviation_max_sqr){
          V_buf_element_deviation_max_sqr = V_buf_element_deviation_sqr;    //максимум
        }        
    }

    V_buf_element_deviation_max = sqrt(V_buf_element_deviation_max_sqr);
    V_buf_rms = sqrt(V_buf_elements_deviation_sqr_sum / V_buf.size());
    float V_buf_rms_volt = (V_buf_rms * analogReference_k) / analogReadResolution_k * v_divider_Vrms_k;
    float V_buf_element_deviation_max_volt = (V_buf_element_deviation_max * analogReference_k) * 2 / analogReadResolution_k * v_divider_Vpkpk_k;
    //oled.clear();
    oled.setScale(1);
    oled.setCursor(0, 1);
    oled.print("Vrms=");
    oled.print(V_buf_rms_volt, 3);
    oled.setCursor(0, 2);
    oled.print("Vpkpk=");
    oled.print(V_buf_element_deviation_max_volt, 3);
    oled.update();
  }
}

Где код, который делает это “измерение”. Давайте только не портянку на сотню строк, а короткий код, которым Вы измеряли время.

Не могу найти как редактировать пост… Плата LGT8F328 32 miniEVB.

Измеряю так

// определение времени выполнения программного блока Ардуино

void test() {

//float array[1000];
unsigned long t1;
unsigned long t2;
unsigned long t3;
unsigned long sum = 0;
unsigned long meas = 0;

  noInterrupts(); // запрет прерываний
  t1 = micros();

  // ---------- исследуемый программный блок ---------

          for (int i = 1; i <= 5000; i++) {
          meas = analogRead(PIN_A0);
          sum = sum + meas*meas;
          }
          
  // -------------------------------------------------

  t2 = micros();
  t3 = t2-t1;
  interrupts(); // разрешение прерываний

  Serial.print(t1);
  Serial.print(" - ");
  Serial.print(t2);
  Serial.print(" = ");
  Serial.println(t3); 
  Serial.print("SUM = ");
  Serial.println(sum);

}

void setup() {
  pinMode(PIN_A0, INPUT);
  pinMode(13, OUTPUT);
  Serial.begin(9600);  // инициализируем последовательный порт, скорость 9600
  Serial.println("START...");
  test();
}

void loop() {
}

Соотв. ядро установили?

Микрос Миллис работают с использованием прерываний !!! Отключив прерывания вы получаете ПОПУГАЕВ !

2 лайка

Между noInterrupts и interrupts не считается micros. Отсюда и цена на овёс в Ваших измерениях. Откуда берётся хоть что-то - не знаю, надо смотреть что там у Вас ещё.

Строка №39 не нужна от слова совсем.

Строка №42 создаст погрешность в измерениях. Или убрать или поставить после неё flush.

2 лайка

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

1 лайк

На заборе и не такое напишут …

1 лайк

Очень странно что

for (int i = 0; i < 1000; i++) {
          meas = analogRead(PIN_A0);
          }

Выполняется 336000 мкс, а

for (int i = 0; i < 1000; i++) {
          meas = analogRead(PIN_A0);
          sum = sum + meas*meas;
          }

336012 мкс.

Реально что вычисление суммы квадратов значений массива из 1000 unsigned long занимает 12 мкс? это при частоте 32Мгц всего 40 тактов чтоли?

Это на каком же камне аналоговые чтение занимает 336 мкс?

LGT8F328. 336 это много?

Я никогда не щупал этот камень.
Мне кажется, что много, т.к. у Атмеги328 это занимае6т 112 мкс.

Скорее 400 (а если точнее, то 384)

Вас уже спросили, что у Вас за контроллер и какова его частота.

104 при “ардуиновской” частоте 16МГц

LGT8F328 частота 32Мгц

Так кто ж Вам мешает даташит посмотреть?

При умолчательной настройке (делитель 32) преобразование занимает 15 микросекунд, можно настроить (без потери точности), на делитель 16, тогда 7,5 микросекунд.

Но это само преобразование. А что там наворочено в функции analogRead в Вашем аддоне, это Вы сами смотрите.

Спасибо буду смотреть. Я просто микроконтьроллер неделю назад в руки взял, до этого вообще не сталкивался с этим.

Умолчательная настройки делителя 32 это вы про CLKPR - регистр предделителя тактов? Пойду разбираться что там на что делится т.к. я пока не понимаю о чем речь.

При чём тут CLKPR? Вы даташит-то читайте! Делитель частоты АЦП задается битами ADPS[2:0] регистра ADCSRA (стр. 254 в самом низу)

Само измерение, может, и 104, а вызов AnalogRead - 112.