Переключение OC1A, OC1B и OC1C с помощью таймера в режиме CTC

Большинство микроконтроллеров AVR имеют три выделенных вывода для каждого таймера (например, OC1A, OC1B и OC1C), которые могут переключаться автоматически, когда счетчик достигает так называемого верхнего значения в соответствующих трех регистрах (OCR1A, OCR1B и OCR1C).

Я не уверен, как эти три выделенных вывода/регистра могут работать в режиме CTC для разных независимых верхних значений, и это то, чего я хочу добиться. Я хочу переключать OC1A, OC1B и OC1C (хотя и «сравнение вывода», а не через прерывание или что-то в этом роде) с разными интервалами (чтобы увидеть наличие трех выделенных регистров и контактов).

Допустим, я хочу запрограммировать таймер AVR для переключения контактов OC1A, OC1B и OC1C с разными интервалами (например, 1 секунда, полсекунды, четверть секунды), но это не работает, как я ожидаю. Я установил сравнение регистров соответствия A, B и C с тремя разными значениями, имеющими наибольшее значение для A (я также пробовал использовать его для C).

Только OC1A переключается на нужной частоте.

Мне кажется, что если бы только OC1A очищал счетчик сверху, тогда можно было бы заставить три вывода работать с тремя разными независимыми значениями. Это правильно?

Вот сегмент, который я поместил в свою установку Arduino Lenoardo (на основе ATmega32U4 ). Я оставил loop()пустым.

  // Initialize timer1
  noInterrupts();           // Disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1C = 0;
  TCNT1  = 0;

  OCR1A = 62500;            // Compare match register 16 MHz/256/1 Hz
  OCR1B = 31250;            // Compare match register 16 MHz/256/2 Hz
  OCR1C = 15625;            // compare match register 16 MHz/256/4 Hz

  // Toggle OC1A, OC1B and OC1C => (on Lenoardo) PB5, PB6 and PB7 => digital 9, 10, 11
  // TCCR1A = 0b01010100;
  TCCR1A |= (1 << COM1C0) | (1 << COM1B0) | (1 << COM1A0);
  // TCCR1B = 0b1100
  TCCR1B |= (1 << WGM12);   // CTC mode
  TCCR1B |= (1 << CS12);    // 256 prescaler

  interrupts();             // Enable all interrupts
С каким АВР вы имеете дело?
Какова необходимая частота и какова фактическая частота?
@jippie речь идет не о конкретной частоте или чипе, а о том, как использовать любой AVR, чтобы контакты OC1A и OC1B автоматически периодически переключались на разные значения для OCR1A / OCR1B.
Они по-прежнему привязаны к одному и тому же таймеру. Я не уверен, почему вы думаете, что у них могут быть разные периоды.
@ignacio-vazquez-abrams 3 разных регистра и 3 разных контакта, какая трата, если у них может быть что-то другое. могут ли они иметь разную фазу? что-либо?
Конечно, они могут иметь разную фазу. Используйте PWM или CTC с ICR1 в качестве TOP, а затем установите для них разные значения. Или они могут быть дифференциальными. Установите один на неинвертирующий, а другой на инвертирующий и присвойте им одинаковое значение.
@ IgnacioVazquez-Abrams, вопрос о CTC. так что OCR1A и OCR1B.. предназначены для формирования разного фазового сдвига, а не частоты. Пожалуйста, сформируйте это как ответ, и я выберу его. пожалуйста, включите пример кода.

Ответы (2)

Таймер в нормальном, быстром ШИМ или режиме CTC считает напрямую от НИЗА к ВЕРХУ, если не применяется внешнее воздействие. Когда он передает каждое значение OC, он выдает прерывание и/или прерывает вывод, как он настроен. Каждое значение OC пересекается только один раз , что означает, что все OC для одного и того же таймера работают с одной и той же частотой .

Они могут быть сконфигурированы так, чтобы иметь разные фазы или работать в дифференциальных парах на основе значений битов OCRnr и COMnrb, но единственный способ напрямую заставить их использовать разные частоты — это манипулировать их значениями OCR каждый раз, когда вызывается их ISR.

Самый простой способ изменить контакты с разной частотой — установить таймер на GCF/LCM различных желаемых периодов/частот, вести подсчет прошедших циклов, а затем удалять выводы, когда прошло соответствующее количество циклов. .

Чтобы было ясно, утверждение «три выделенных контакта для каждого таймера (например, OC1A, OC1B и OC1C)» в вопросе неверно. OC1A, OC1B и OC1C связаны с одним и только одним таймером, timer1 (16-битный таймер).

Модуль таймера позволяет генерировать несколько выходов с разными рабочими циклами, но все они будут иметь одинаковую основную частоту. Если вы хотите генерировать разные частоты, вам нужно будет использовать другой метод. Есть два основных способа сделать это. Первый метод заключается в использовании трех таймеров, каждый из которых работает на разной частоте. Если вы пытаетесь генерировать относительно низкочастотные выходы (1 кГц или меньше), вы можете использовать разумный такт таймера и процедуру прерывания. Если вы хотите генерировать 1 Гц, 2 Гц и 4 Гц, вы можете установить такт таймера не менее 8 Гц, а затем подсчитывать тики и включать и выключать контакты в нужное время. С тактом таймера 8 Гц для генерации выходного сигнала с частотой 4 Гц потребуется переключать контакт в каждом цикле, 2 Гц — каждый второй цикл, а 1 Гц — каждые 4 цикла.

Я пытаюсь понять использование 3 регистров TCCR1A, TCCR1B и TCCR1C и наличие 3 соответствующих контактов (OC1A, OC1B и OC1C) для переключения. зачем 3 выделенных вывода, регистра и значения, если практически можно использовать только один.