arduino: задержка микросекунды ()

8

Как работает функция delayMicroseconds (). Из того, что я понял, prescaler таймера 0 установлен на 64. Для 16 МГц тактовая частота дает 4.0uS за счет. Я немного запутался в математике, чтобы добраться до интервала 1 мкс?

Hawk_08
источник
4
В документации сказано: «Эта функция работает очень точно в диапазоне от 3 микросекунд и выше. Мы не можем гарантировать, что delayMicroseconds будет работать точно при меньших временах задержки». В документе micros()сказано: «На платах Arduino 16 МГц (например, Duemilanove и Nano) эта функция имеет разрешение в четыре микросекунды (т. Е. Возвращаемое значение всегда кратно четырем)».
RedGrittyBrick
См. Также electronics.stackexchange.com/q/22584/2191
RedGrittyBrick

Ответы:

9

Исходный код этой функции довольно хорошо задокументирован и может быть найден в /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(unsigned int 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()и включить их впоследствии, но это опять-таки влияет на точность синхронизации на продолжительность скомпилированного кода для включения / выключения.

jippie
источник
Или, если у вас не установлена ​​Arduino IDE, этот файл доступен по адресу github.com/arduino/Arduino/blob/master/hardware/arduino/cores/…
microtherion
Это перемещено здесь: github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/…
Frepa