Режимы установки и сброса 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

Обсуждение

Если вы не установите режим WGM до установки TOP/OCR1A/ICR1, он может быть усечен до 8 (, 9 или 10?) бит по сравнению с режимами Arduino по умолчанию WGM=5=0b0101., @Dave X

Вы можете установить выход с помощью digitalWrite(10, HIGH). При сравнении он очищается. Если он уже был очищен, ничего не происходит. Это было бы полезно для создания **одиночного** импульса точной длины., @Gerben

@Gerben Возможно, это мой Teensy 2.0, но установка digitalWrite(PIN_B6,HIGH) или digitalWrite(15, HIGH) кажется, остается высоким навсегда после конфигурации CTC или немедленно очищается, если до настройки CTC. Проверяя TCCRA1, кажется, что digitalWrite(PIN_B6,HIGH) отключает COM1B1 и COM1B0., @Dave X

Извините, я глупый. Реализация digitalWrite отключит ШИМ. Вместо этого сделайте что-то вроде PORTB |= _BV(PB2)., @Gerben

@Gerben. Пока нет. похоже, что значение бита PORTB подавляется/переопределяется состоянием OC1B. "Если один или оба бита COMnB1:0 записаны в единицу, выход OCnB переопределяет нормальную функциональность порта контакта ввода-вывода, к которому он подключен. Если один или оба бита COMnC1:0 записаны в единицу, выход OCnC переопределяет нормальную функциональность порта контакта ввода-вывода, к которому он подключен." в разделе TCCR1A моего технического описания. Если я включаю и выключаю COM1Bxx с базовым высоким уровнем PORTB, он переключает напряжение на выводе и выключает его., @Dave X

Teensy2.0 atmega32u - моя шпаргалка была для Atmega328P. Вероятно, все будет немного по-другому., @Nick Gammon

Это немного отличается, например, у atmega32u есть OC1C, и они находятся на разных битах, но базовая функциональность, по-видимому, во многом одинакова., @Dave X

http://arduinoprosto.ru/q/30507/timer2-clear-oc2b-on-compare-match-not-working-as-expected-in-ctc-mode/30529#30529 связано, @Dave X

@NickGammon: На Atmega328P есть ли удобный способ сбросить или снять очистку таймера в режиме CTC clear-on-match или set-on-match? Я попробовал трехэтапный процесс инвертирования режима COM, принудительного совпадения и сброса режима COM, но это кажется неудобным., @Dave X

@DaveX Я думаю (не проверяя), что вы бы записали 0 в TCNT1, возможно, сначала остановив таймер., @Nick Gammon

@NickGammon -- Извините, я задал неправильный вопрос. Я имел в виду, как мне установить пин OC1A, когда я использую режим CTC clear-on-match (и наоборот). Я знаю, что переключение меняет его каждый матч, но я не понимаю, как использовать непереключаемые режимы., @Dave X

@DaveX Если у вас есть еще вопросы, пожалуйста, задайте их. Этот сайт не является форумом., @the busybee


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

,

Да, я имею в виду выход таймера. Кажется, что режимы CTC+set или CTC+clear могли бы быть разумным выбором для использования таймера для выполнения одноразового действия, но сброс кажется неопределенным. В режимах переключения с более высокой частотой часто можно игнорировать начальное состояние, но для поведения одноразового действия вам нужно знать/контролировать начальное состояние. // Поэтому нельзя сбросить выход таймера в режиме CTC set-on-match, и для этого вам нужно выйти из режима. И этот OC1A может быть инициализирован с помощью бита PORTB:1, когда вы включаете управление выходом (бит COM1A0). Я поэкспериментирую с этим., @Dave X

@DaveX Для длительных периодов, которые вы описываете, вероятно, проще просто вызвать прерывание и установить контакт в обработчике прерываний., @Nick Gammon