Как сделать микросекундную задержку в AVR (ATmega8) с таймером?

Хочу сделать переменную задержку в ATmega8. Но в функции delay_us() я могу просто указать постоянное значение. Я думаю, что могу сделать микросекунду с переменной задержкой с помощью таймера, но я не знаю, как с этим работать.

Помогите пожалуйста мне.


person Mahdi    schedule 11.02.2020    source источник
comment
Не могли бы вы поделиться тем, что вы уже сделали?   -  person dunajski    schedule 12.02.2020
comment
когда я пишу delay_us(i) и я являюсь переменной, кодовое видение ошибочно.   -  person Mahdi    schedule 13.02.2020
comment
Пожалуйста, предоставьте код. Вы не можете установить переменную в delay_us, потому что delay_us(x) — это макрос, который вставляет некоторый дополнительный код, создающий задержку в x мкс. Когда вам нужна переменная задержка, вы должны использовать таймер.   -  person Kampi    schedule 14.02.2020


Ответы (1)


Вы можете использовать цикл задержки: вы делаете задержку на одну микросекунду в каждой итерации и выполняете столько итераций, сколько микросекунд вам нужно сжечь:

void delay_us(unsigned long us)
{
    while (us--) _delay_us(1);
}

Однако есть несколько проблем с этим подходом:

  • требуется время для управления итерациями (уменьшение счетчика, сравнение с нулем, условный переход...), поэтому задержка в цикле должна быть значительно короче 1 мкс
  • требуется время на вызов функции и возврат из нее, и это следует вычесть из подсчета итераций, но поскольку это время может быть не полным числом микросекунд, вам придется добавить небольшую задержку, чтобы перейти к следующему полная микросекунда
  • если компилятор встраивает функцию, все будет выключено.

Попытка исправить эти проблемы дает что-то вроде этого:

// Only valid with a 16 MHz clock.
void __attribute__((noinline)) delay_us(unsigned long us)
{
    if (us < 2) return;
    us -= 2;
    _delay_us(0.4375);
    while (us--) _delay_us(0.3125);
}

Более полную версию, которая может работать с различными тактовыми частотами, см. функция delayMicroseconds() из ядра Arduino AVR. Обратите внимание, что функция точна только для нескольких дискретных частот. Обратите также внимание на то, что цикл задержки выполняется на встроенном ассемблере, чтобы не зависеть от оптимизации компилятора.

person Edgar Bonet    schedule 28.02.2020