В предыдущем расследовании стало ясно как работает функция millis(). Есть у Arduino более мелкая функция micros(). Посмотрим, что у нее внутри…
micros()
Возвращает количество микросекунд с момента начала выполнения текущей программы на плате Arduino. Значение переполняется и сбрасывается на ноль, приблизительно через 70 минут.
Долго в «дебрях» подкаталогов каталога установки Arduino IDE блуждать не приходится в том же файле: ..\Arduino\hardware\arduino\cores\arduino\wiring.c находим код, описывающий эту функцию:
unsigned long micros() { unsigned long m; uint8_t oldSREG = SREG, t; cli(); m = timer0_overflow_count; t = TCNT0; if ((TIFR0 & _BV(TOV0)) && (t < 255)) m++; SREG = oldSREG; return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond()); }
Здесь я немного повыкидывал строчки кода — условия проверки кристалла — оставлено то, что актуально для младших ардуин: UNO, mini и прочих.
В результате видно, что используется тот же Таймер 0, что и в функции millis(). Но возвращаемое значение микросекунд берется уже с учетом состояния счетчика таймера, а не только счетчика числа его переполнений (см считывание TCNT0 и timer0_overflow_count). Результат упаковывается в четыре байта без знака. (Число переполнений таймера в переменной timer0_overflow_count считается в обработке прерывания от Таймера 0 — см предыдущую статью). Ранее было отмечено, что Таймер 0 в Arduino UNO тактируется с частотой 16МГц/64 — такой уж разработчиками выбран предделитель, чтоб получить период переполнений таймера близкий к 1 мс.
В итоге имеем на выходе число микросекунд, прошедших с момента запуска контроллера. Переполнение такого четырехбайтного счетчика при микросекундных тактах происходит раз в 2 в 32 степени мкс, т.е. примерно раз в 71,5 минуту.
В нижней части программы видно с каким дискретом выдается информация. Функцию clockCyclesPerMicrosecond() из любопытства можно запустить в каком-нибудь скетче и посмотреть возвращаемое значение на экране с помощью:
Serial.println(clockCyclesPerMicrosecond());
для 16МГц, естественно, получим 16 (можно перевод названия посмотреть: «число циклов в микросекунде»). Т.е. дискрет результата выполнения micros() для UNO 16МГц будет 4мкс!
Отметим интересный факт: даже при запрещенных прерываниях, в отличие от millis(), функция micros() вернет вполне адекватное значение, правда только в младшем байте. Период его переполнений — 256мкс!