Как работает функция delayMicroseconds (). Из того, что я понял, prescaler таймера 0 установлен на 64. Для 16 МГц тактовая частота дает 4.0uS за счет. Я немного запутался в математике, чтобы добраться до интервала 1 мкс?
В документации сказано: «Эта функция работает очень точно в диапазоне от 3 микросекунд и выше. Мы не можем гарантировать, что delayMicroseconds будет работать точно при меньших временах задержки». В документе micros()сказано: «На платах Arduino 16 МГц (например, Duemilanove и Nano) эта функция имеет разрешение в четыре микросекунды (т. Е. Возвращаемое значение всегда кратно четырем)».
Исходный код этой функции довольно хорошо задокументирован и может быть найден в /usr/share/arduino/hardware/arduino/cores/arduino/wiring.c в системах Linux. Системы Windows будут иметь аналогичный путь к файлу wiring.c. Приложите усилия, чтобы найти файл и просмотреть его. А пока просто сосредоточьтесь на этой единственной функции, она не зависит от других функций.
Изучив код, вы заметите, что речь идет не о таймерах, а о циклах инструкций. Код в значительной степени опирается на оптимизацию компилятора, которая для вас точно такая же, как и для разработчика библиотеки. Это предположение автора! Количество циклов ЦП, «записанных» каждой инструкцией, хорошо задокументировано в документе набора команд Atmel AVR .
Сначала проверяется, что значение задержки равно 1, в этом случае просто возвращается из процедуры, уже потраченной за микросекунду времени ЦП.
Затем значение задержки умножается на четыре ( <<=2). В __asm__-loop компилируется в петле цикла 4 процессора. 4 цикла × 4 = 16 циклов. 16 МГц / (4 × 4) = 1 МГц, что занимает 1 цикл цикла, разрешение, которое мы получаем.
Последние -2 микросекунды (перед тем как цикл будет запущен) снова являются поправкой на вводимые компилятором служебные данные. Для вызова __asm__-code из C требуются дополнительные инструкции для сохранения регистров процессора.
Для обычного Arduino @ 16MHz будет скомпилирован только следующий код:
/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */void delayMicroseconds(unsignedint us){// calling avrlib's delay_us() function with low values (e.g. 1 or// 2 microseconds) gives delays longer than desired.//delay_us(us);// for the 16 MHz clock on most Arduino boards// for a one-microsecond delay, simply return. the overhead// of the function call yields a delay of approximately 1 1/8 us.if(--us ==0)return;// the following loop takes a quarter of a microsecond (4 cycles)// per iteration, so execute it four times for each microsecond of// delay requested.
us <<=2;// account for the time taken in the preceeding commands.
us -=2;// busy wait
__asm__ __volatile__ ("1: sbiw %0,1""\n\t"// 2 cycles"brne 1b":"=w"(us):"0"(us)// 2 cycles);}
Кстати: скомпилированный код довольно точен, но имейте в виду следующее: на Arduino настроены прерывания по времени, о которых большинство не знают. Когда прерывание получено во время выполнения delayMicroseconds(), время delayMicroseconds()будет неправильным. Конечно, вы можете остановить прерывания перед вызовом delayMicroseconds()и включить их впоследствии, но это опять-таки влияет на точность синхронизации на продолжительность скомпилированного кода для включения / выключения.
micros()
сказано: «На платах Arduino 16 МГц (например, Duemilanove и Nano) эта функция имеет разрешение в четыре микросекунды (т. Е. Возвращаемое значение всегда кратно четырем)».Ответы:
Исходный код этой функции довольно хорошо задокументирован и может быть найден в /usr/share/arduino/hardware/arduino/cores/arduino/wiring.c в системах Linux. Системы Windows будут иметь аналогичный путь к файлу wiring.c. Приложите усилия, чтобы найти файл и просмотреть его. А пока просто сосредоточьтесь на этой единственной функции, она не зависит от других функций.
Изучив код, вы заметите, что речь идет не о таймерах, а о циклах инструкций. Код в значительной степени опирается на оптимизацию компилятора, которая для вас точно такая же, как и для разработчика библиотеки. Это предположение автора! Количество циклов ЦП, «записанных» каждой инструкцией, хорошо задокументировано в документе набора команд Atmel AVR .
Сначала проверяется, что значение задержки равно 1, в этом случае просто возвращается из процедуры, уже потраченной за микросекунду времени ЦП.
Затем значение задержки умножается на четыре (
<<=2
). В__asm__
-loop компилируется в петле цикла 4 процессора. 4 цикла × 4 = 16 циклов. 16 МГц / (4 × 4) = 1 МГц, что занимает 1 цикл цикла, разрешение, которое мы получаем.Последние -2 микросекунды (перед тем как цикл будет запущен) снова являются поправкой на вводимые компилятором служебные данные. Для вызова
__asm__
-code из C требуются дополнительные инструкции для сохранения регистров процессора.Для обычного Arduino @ 16MHz будет скомпилирован только следующий код:
Кстати: скомпилированный код довольно точен, но имейте в виду следующее: на Arduino настроены прерывания по времени, о которых большинство не знают. Когда прерывание получено во время выполнения
delayMicroseconds()
, времяdelayMicroseconds()
будет неправильным. Конечно, вы можете остановить прерывания перед вызовомdelayMicroseconds()
и включить их впоследствии, но это опять-таки влияет на точность синхронизации на продолжительность скомпилированного кода для включения / выключения.источник