Невозможно получить последовательность импульсов на частоте 32 Гц с шириной импульса 20 мкс с помощью Uno

Я пытался получить последовательность импульсов 32 Гц (между 30 Гц и 35 Гц тоже подойдет) с шириной импульса около 20 мкс с помощью Arduino Uno, но не смог. Проблема в следующем:

Если я сделаю следующее:

void setup() {

    TCCR1B = TCCR1B & B11111000 | B00000101;  

    pinMode(pwmPin9, OUTPUT); // устанавливает вывод как выход

}


void loop() {

analogWrite(pwmPin9, 1)


}

Я могу установить частоту примерно на 30 Гц, но analogWrite(pwmPin9, 1) даст минимум 100 мкс и не сможет снизиться до 20 мкс.

С другой стороны, метод digitalWrite с задержкой не позволяет получить частоты ниже 60 Гц.

Как получить выходной сигнал последовательности импульсов с частотой от 30 Гц до 35 Гц и шириной импульса около 20 мкс?

, 👍0


2 ответа


Лучший ответ:

1

Для решения такого рода задач первое, что нужно сделать, это преобразовать два соответствующие моменты времени (период сигнала и длительность состояния HIGH) в несколько циклов ЦП. С тактовой частотой 16 МГц, что дает:

  • Время HIGH: 20 мкс = 320 циклов ЦП
  • период: 31,25 мс = 500000 циклов (±7%)

Затем разделите эти числа на доступные значения предварительного делителя, чтобы получить соответствующее количество предварительно масштабированных тактовых циклов:

prescaler       1      8    64     256      ...
HIGH time     320     40     5       1.25   ...
period     500000  62500  7812.5  1953.125  ...

В идеале вам нужен предделитель, который выдает целые числа в порядке чтобы избежать ошибок округления. И поскольку вы используете 16-битный таймер, вы хотите, чтобы эти числа были не больше 216. Или вдвое больше, если вы используете режим фазовой коррекции ШИМ, но я предпочитаю этого избегать усложнение, если возможно.

Из таблицы выше следует, что идеальным является предделитель 8. 64 будет практически таким же хорошим, с погрешностью частоты всего лишь 64 ppm, что меньше допуска частоты керамики резонатор тактирует ваш Uno.

Затем вы используете либо OCR1A, либо OCR1B для установки высокого времени, в зависимости от от того, выводите ли вы сигнал на вывод OC1A (цифровой 9) или OC1B (цифровой 10). Вы используете либо OCR1A, либо ICR1 для установки периода. Поскольку вы выводятся на вывод 9, регистр OCR1A будет использоваться для установки время, поэтому вам нужно использовать ICR1 для установки периода. Затем вы найдите в таблице режимов в техническом описании тот, который соответствует этот режим работы - режим 14: быстрая ШИМ с ВЕРХНИМ значением определяется ICR1. Это дает следующую конфигурацию:

void configure_timer_1()
{
    DDRB  |= _BV(PB1);    // установить вывод 9 = PB1 = OC1A как выход
    TCCR1A = 0;           // сброс таймера
    TCCR1B = 0;           // то же самое
    OCR1A  = 40 - 1;      // HIGH для 40 * 8 циклов ЦП
    ICR1   = 62500 - 1;   // период = 62500 * 8 циклов ЦП
    TCCR1A = _BV(COM1A1)  // неинвертирующий ШИМ на выводе OC1A
           | _BV(WGM11);  // режим 14: быстрый ШИМ, TOP = ICR1
    TCCR1B = _BV(WGM12)   // то же самое
           | _BV(WGM13)   // то же самое
           | _BV(CS11);   // тактовая частота F_CPU/8
}

Обратите внимание, что OCR1A и OCR1B должны быть установлены на желаемое количество циклов. минус один.

,

0

analogWrite — 8-битный.

Обратная величина 30 Гц (время за полный период) составляет 0,0313.

0,0313 деленное на 256 (28) равно 0,000122 или 122uS.

8 бит — это наименьшее время, на которое можно разрезать сигнал частотой 30 Гц.

Чтобы получить меньшие срезы, вам нужен ШИМ-сигнал с более высоким разрешением. Этот вопрос и ответ показывают, как это можно сделать, но он ограничен тем, какие выводы можно использовать, поскольку вам нужны каналы ШИМ, подключенные к 16-битному таймеру.

,