Режимы установки и сброса CTC таймера — как отменить сброс и сброс?

Шпаргалка Ника Гэммона для ATmega328P Ardunino UNO (ниже) дает некоторые подсказки по режимам очистки таймера при сравнении (CTC) чипов AVR. Большинство примеров для режима CTC, которые я нашел, используют регистры COMxxx 01 = переключение для управления выводом OCxx, что даст 50% рабочий цикл на 1/2 частоты очистки таймера.

Мой вопрос касается использования непереключаемых режимов COMxxx Clear и Set, которые, похоже, не обеспечивают автоматического способа сброса в противоположное состояние, как в режимах PWM.

Например:

void setup() {
  // поместите сюда ваш код настройки для однократного запуска:

   // Режим CTC таймера 1 Очистка OC1B на частоте 0,25 Гц с использованием OCR1A для установки частоты
   // Вывод на OC1B
   // Очистить в OCR1B
   // WGM =15 0b0100

   DDRB |= bit(DDB5)| bit(DDB6);  // Выходы Teensy2.0 atmega32u OC1A и OC1B
  // DDRB |= bit(DDB1)| bit(DDB2); // atmega168/UNO OC1A и OC1B (проверено OP/Luis)
   TCCR1A =  bit(COM1A0) | bit(COM1B1)  ; // Переключить OC1A, очистить OC1B
   TCCR1B =  bit(WGM12)  | bit(CS12);  // Установка прескалера /1
   TCCR1C = 0;  // Обратите внимание, что лучше инициализировать таймер
                // в известный режим, прежде чем пытаться установить интересные ТОПы
   OCR1A  = 62500U ;    // Установить TOP-счетчик на 16000000/(PreScaler *Ftimer)
   OCR1B  = OCR1A/2;    // ~50% рабочий цикл
   TCCR1A =  bit(COM1A0) | bit(COM1B1)  ; // Переключить OC1A, очистить OC1B
   TCCR1B =  bit(WGM12)  | bit(CS12) | bit(CS10);  // Установка прескалера /1024
   TCNT1 = 0 ;
}

void loop() {
  // поместите сюда свой основной код для многократного выполнения:
  //OCR1B = 62500U/4-1; // Рабочий цикл 25%.
}

Если я попробую приведенный выше код, я получу сигнал частотой 0,125 Гц (период 8 с) на PB5 и постоянный низкий уровень на PB6.

Каким образом установить высокий уровень OC1B для очистки по совпадению таймера? И аналогично, наоборот: очистка OC1B для установки по совпадению таймера?

Есть ли прямой способ или нужно возиться с COM1Bx, запускать FOC1B, а затем снова возиться с COM1B?

Этот код использует регистр TCCR1C:FOC1B для установки бита путем манипуляций с битами TCCR1A:COM1Bx, но это выглядит неуклюже:

void setup() {
   // Режим CTC таймера 1 Очистка OC1B на частоте 0,25 Гц с использованием OCR1A для установки частоты
   // Вывод на OC1B
   // Очистить в OCR1B
   // WGM =15 0b0100

   DDRB |= bit(DDB5)| bit(DDB6);  // Выходы Teensy2.0 atmega32u OC1A и OC1B
  // DDRB |= bit(DDB1)| bit(DDB2); // atmega168/UNO OC1A и OC1B (проверено OP/Luis)
   TCCR1A =  bit(COM1A0) | bit(COM1B1)  ; // Переключить OC1A, очистить OC1B
   TCCR1B =  bit(WGM12)  | bit(CS12);  // Установка прескалера /1
   TCCR1C = 0;  // Обратите внимание, что лучше инициализировать таймер
                // в известный режим, прежде чем пытаться установить интересные ТОПы
   OCR1A  = 62500U ;    // Установить TOP-счетчик на 16000000/(PreScaler *Ftimer)
   OCR1B  = OCR1A/2;    // ~50% рабочий цикл
   TCCR1A =  bit(COM1A0) | bit(COM1B1)  ; // Переключить OC1A, очистить OC1B
   TCCR1B =  bit(WGM12)  | bit(CS12) | bit(CS10);  // Установка прескалера /1024
   TCNT1 = 0 ;
}

void loop() {
  int saveCOM;
  Serial.println(TCCR1A,BIN);
  delay(7000); // 7 секунд
  saveCOM = TCCR1A; 
  TCCR1A |= bit(COM1B1) | bit(COM1B0) ; // конфигурация для набора OC1B
  TCCR1C = bit(FOC1B); // принудительное сравнение для установки бита
  TCCR1A = saveCOM ; // режим восстановления
}

Этот код имеет частоту 0,125 Гц на OC1A и полуслучайную серию импульсов длительностью 1–4 секунды на OC1B.

Мне было интересно поиграть с режимами CTC для создания длинного цикла/низкочастотной ШИМ. С обычными ШИМ вы могли бы варьироваться от 1-битного 50% ШИМ на 8 МГц до 16-битного ШИМ на частоте 0,119 Гц (8,388 с). С режимами CTC, если бы вы могли управлять установками и сбросами в TIMERx_OVF_vect с парой 16-битных регистров, вы могли бы расширить его до 32 бит разрешения ШИМ с периодом до 152 часов.

, 👍1


1 ответ


1

Комментарий OP под вопросом:

Я имел в виду, как мне установить вывод OC1A, когда я использую режим очистки при совпадении CTC (и наоборот). Я знаю, что переключение меняет его при каждом совпадении, но я не понимаю, как использовать режимы без переключения.

Этот код переключает OC1A (D9 на Uno) на частоте 19 кГц, давая общую частоту 38 кГц:

void setup() 
 {
  pinMode (9, OUTPUT);
  TCCR1A = bit (COM1A0);  // переключить OC1A при совпадении
  TCCR1B = bit (WGM12) | bit (CS10);   // CTC, без прескалера
  OCR1A =  (F_CPU / 38000L) - 1;       // ноль относительно
  }  // конец настройки

void loop()
  {
  }

Режимы без переключения не особенно полезны. Когда он совпадает, он устанавливает выход высоким или низким, что в данном случае не дает особого результата.

Я полагаю, если бы у вас было большое время CTC (большой предварительный делитель и большой объем для подсчета), то вы могли бы использовать его для установки этого вывода в высокое или низкое состояние по истечении времени.


Есть ли на Atmega328P удобный способ сброса или сброса imer в режиме сброса при совпадении или установки при совпадении CTC?

Вы имеете в виду выход таймера? Не совсем, потому что установка этих битов означает, что таймер управляет выходным пином. Что вы могли бы сделать, так это отключить управление выходом (бит (COM1A0)), самостоятельно изменить пин и вернуть его на место, но я не уверен, переключит ли это его обратно на выход таймера.

,