Нужна помощь в понимании AVR ATMEGA / ATTINY таймер зеркальный вывод

10

Я пытаюсь использовать Timer1 микроконтроллера Atmel AVR, либо AtMega328, который используется в Arduino, либо ATTiny85, для вывода двух тактовых сигналов, которые являются зеркальным отображением друг друга. Частота, которую я пытаюсь сгенерировать, - это переменная от 1 МГц до 2 МГц или более, которые слишком высоки, чтобы делать это с помощью кода для переключения выходных контактов, если я не хочу почти ничего делать в контроллере. Поэтому я хочу использовать выход таймера непосредственно на соответствующих выводах. Я использую GCC toolchain, поэтому он не ограничен библиотеками Arduino или языком.

Timer1 в Atmega328 имеет два контакта, связанных с ним, и я могу получить два идентичных сигнала от 1 МГц до 2 МГц из них. Несмотря на то, что таблица данных говорит, что я могу получить инвертированную форму волны, это сбивает меня с толку. Я также могу получить два сигнала с разными рабочими циклами на частоте 1 МГц, используя настройки ШИМ с таймером 1, но оба сигнала одновременно повышаются, а более низкий - раньше. Это не служит моему проекту. Мне даже не нужно изменение ширины импульса ШИМ, мне просто нужны два идентичных сигнала «тактового» типа противоположной фазы, вот и все.

Я не прошу, чтобы кто-нибудь написал код, чтобы я сделал это, мне просто нужно, чтобы кто-то сказал мне, какой режим / флаги таймера должен дать мне простой инвертированный сигнал на одном из двух контактов, связанных с таймером. Если возможно, я хочу избегать использования внешней инвертирующей цепи для одного из выходов, если только это не вариант.

Если это вообще возможно в ATTiny, это будет еще лучше. ATTiny также имеет 2 контакта, связанных с одним таймером, но я не уверен, что он имеет те же опции, что и ATMega.

У меня уже есть 20 МГц кристалл и конденсаторы, подключенные к печатной плате, а 20 МГц часы надежно работают на ATMega328. На плате ATTiny85 у меня кристалл 8 МГц, и он тоже работает надежно.

Пожалуйста помоги. Спасибо.


ОБНОВЛЕНИЕ : В ответах и ​​комментариях есть некоторые неверные предположения, поэтому, возможно, я должен уточнить: Обратите внимание, что в своем первоначальном посте я заявил, что я использую тактовую частоту 20 МГц, а не 8 МГц , а также что мне не нужен ШИМ ,

Единственный режим, который дает достаточно высокую выходную частоту, кажется, режим CTC, потому что режимы ШИМ не работают для выхода 2 МГц. Есть ли способ инвертировать либо выход A таймера 1, либо выход B в режиме CTC?

Теперь я переключился на стандартную Arduino Uno (ATMega328, 16 МГц) вместо моей собственной платы на 20 МГц, чтобы проверить мой код, и это мой код для хороших устойчивых часов 2 МГц в режиме CTC с выводов 9 и 10, таймер 1 вывод выводов:

#define tick 9
#define tock 10

void setup() {
  pinMode(tick, OUTPUT);  
  pinMode(tock, OUTPUT); 

  TCCR1A = _BV(COM1A0) | _BV(COM1B0) ;   // activate both output pins 
  TCCR1B = _BV(WGM12)| 1;                // set CTC mode, prescaler mode 1

  // various frustrating attempts to invert OC1B failed. What do I put here?

  OCR1A = 3;                             // set the counter max for 2 MHz

}

void loop() {
}

Следы осциллографа для обоих выводов идентичны и синхронно, как я могу получить один из двух инвертированных сигналов? Режим инвертирования в техническом описании ничего не делает в режиме CTC. Я неправильно читаю таблицу данных или мне все равно придется использовать более низкую частоту и режим ШИМ?

Чтобы добавить конкретный вопрос о «вознаграждении» в мой исходный запрос:
какие изменения мне нужно внести в мой код выше, чтобы он давал идеально инвертированные сигналы на контактах 9 и 11 на максимально возможной частоте для тактовой частоты 16 МГц , будь то это 2 МГц или нет?

Сейчас я буду придерживаться стандартного Arduino Uno, чтобы на моей панели homespun не было режима ошибок и чтобы любой, у кого есть arduino, мог попробовать мой код выше и подтвердить, что он работает так, как я упоминал, а не так, как я. необходимость!

ExcitingProjects
источник
1
Глядя на странице 97-98 из atmega8L таблицы , есть таблица режимов работы. Страница 108 гласит: «Биты COM21: 0 определяют, должен ли генерируемый выход ШИМ быть инвертированным или нет (инвертированный или не инвертированный ШИМ)». Держите нас в курсе о вашем успехе!
Vorac
Почему бы не использовать простой транзисторный инвертор для зеркальных выходов?
Джонни Б. Хорошо

Ответы:

10

Из таблицы ATtiny85:

Режим работы, т. Е. Поведение выводов таймера / счетчика и выводов сравнения, определяется комбинацией режима генерации формы волны (WGM0 [2: 0]) и режима сравнения выхода (COM0x [1: 0]) биты. Биты режима сравнения выходных данных не влияют на последовательность подсчета, в то время как биты режима генерации формы сигнала влияют. Биты COM0x [1: 0] управляют тем, следует ли инвертировать генерируемый выход ШИМ (инвертированный или неинвертированный ШИМ ).

Таблица 11-5 показывает, как установить режим.

Mode   WGM  WGM  WGM  Timer/Counter Mode    TOP      Update of    TOV Flag
c0     02   01   00   of Operation                   OCRx at      Set on
==========================================================================
0      0    0    0    Normal                0xFF     Immediate    MAX(1)
1      0    0    1    PWM, Phase Correct    0xFF     TOP          BOTTOM
2      0    1    0    CTC                   OCRA     Immediate    MAX
3      0    1    1    Fast PWM              0xFF     BOTTOM       MAX
4      1    0    0    Reserved                                  
5      1    0    1    PWM, Phase Correct    OCRA     TOP          BOTTOM
6      1    1    0    Reserved                                  
7      1    1    1    Fast PWM              OCRA     BOTTOM       TOP

Вам нужен режим Fast PWM (режим 3 или 7). Если вы хотите изменить рабочий цикл, и он звучит так, как вы, вам нужен режим 7 и изменить рабочий цикл, установив OCRA.

В таблице 11-3 показано, как установить выходной режим сравнения для режима быстрой ШИМ.

COM0A1/   COM0A0/
COM0B1    COM0B0     Description
===============================================================================
0         0          Normal port operation, OC0A/OC0B disconnected.
0         1          Reserved
1         0          Clear OC0A/OC0B on Compare Match, set OC0A/OC0B at BOTTOM
                     (non-inverting mode)
1         1          Set OC0A/OC0B on Compare Match, clear OC0A/OC0B at BOTTOM
                     (inverting mode)

То есть вы можете установить выход OC0A на низкий уровень, когда значение таймера == OCR0A, и высокий уровень, когда значение таймера == 0x00, установив COM0A1: COM0A0 = 0b10. Или наоборот, установив COM0A1: COM0A0 = 0b11. И аналогично для OC0B, OCR0B, COM0B0, COM0B1.

Частота ШИМ определяется тактовой частотой входов / выходов (8 МГц, как вам кажется) и настройкой прескалера таймера. И уравнение задается как f_clk_IO / (N * 256) для режима быстрой ШИМ.

Таким образом, вы можете использовать OC0A для «нормальной» полярности и OC0B для «инвертированной» полярности, установив OCR0A и OCR0B на одно и то же значение и установив COM0A1: COM0A0 = 0b10 и COM0B1: COM0B0 на 0b11.

ОБНОВИТЬ

Если вы хотите максимально быстро переключить выход и используете Mega328, работающий с частотой 16 МГц, режим работы CTC позволит вам получить частоту переключения:

f_OCnA = f_clk_IO / (2 * N * [1 + OCRnA) = 16e6 / (2 * 1 * [1 + 1]) = 4 МГц

Режим Fast PWM позволит вам переключать контакт в:

f_OCnxPWM = f_clk_IO / (N * [1 + TOP]) = 16e6 / (1 * [1 + 1]) = 8 МГц

Поэтому я все еще думаю, что вы хотите быстрый режим ШИМ. В частности, режим 3 с OCR0A = OCR0B = 0x80 для рабочего цикла 50%. И установите биты COM0A на 0x3 и биты COM0B на 0x2, чтобы сделать две формы сигнала на инверсиях OC0A и OC0B друг друга.

Обновление # 2 Больше Mega328 Попробуйте этот код Arduino:

#define tick 9
#define tock 10

void setup(){

  pinMode(tick, OUTPUT);  
  pinMode(tock, OUTPUT); 

  // Setup Waveform Generation Mode 15
  // OC1A Compare Output Mode = inverting mode
  // OC1B Compare Output Mode = non-inverting mode
  // Timer Prescaler = 1
  // TOP = OCR1A = 1

  //COM1A[1:0] = 0b11, COM1B[1:0] = 0b10, WGM1[1:0] = 0b11
  TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(COM1B1) | _BV(WGM11) | _BV(WGM10);

  //WGM1[3:2] = 0b11, CS1[2:0] = 0b001
  TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);

  OCR1A = 0x0001;
  OCR1B = 0x0001;
}

void loop(){

}
vicatcu
источник
Позвольте мне немного обдумать это и посмотреть, сработает ли это. Спасибо.
Захватывающие
Перечитав ваш ответ, чтобы опробовать его сегодня, я вижу пару неверных предположений: я указал тактовую частоту 20 МГц (и теперь я переключился на 16 МГц), а не «(8 МГц это звучит как для вас)» . Также я указал, что мне не нужно изменение ширины импульса ШИМ, поэтому не уверен, где вы предполагали: «Если вы хотите изменить рабочий цикл, и это звучит так, как вы» .
Захватывающие
@ExcitingProjects Я отключил ваше заявление: «На плате ATTiny85 у меня кристалл 8 МГц, и он также работает надежно». и мой ответ относится к ATtiny85. Я постараюсь обновить свой ответ, в ответ сделаю ваш обновленный вопрос.
Викацу
@vicateu Спасибо. Я обновил вопрос, так как режим инвертирования, похоже, не действует в режиме CTC, если я не пропустил какой-то шаг.
Захватывающие
@ExcitingProjects из таблицы ATmega328: «Для не-ШИМ-режимов биты COM0x1: 0 определяют, должен ли выход быть установлен, очищен или переключен при сопоставлении»
викацю
1

Семейство ATtinyX5 имеет PLL внутри, используйте его большой мальчик.

Я использую внутренний PLL для питания тактовой частоты процессора тоже и 16 МГц без XTAL. Это очень ценно, так как у вас всего 5 пинов. (Я не считаю пин-код сброса). Также один PLL'-PWM (OCR1B) работает на выводах XTAL с дополнительным дополнительным выходом. Вам просто нужно настроить предохранители для 16 МГц Xtalless ATtiny ... Или просто позволить процессору работать на 8 МГц, но запустить ШИМ с тактовой частотой 64 МГц без замены предохранителей ..

Вы можете иметь тактовую частоту до 64 МГц (но с разрешением 1 бит). Или 125 кГц при разрешении 8 бит. Вы можете уменьшить разрешение ШИМ и увеличить скорость с помощью уменьшения регистра OCR1C.

Для 1 МГц вам нужно установить OCR1C на 63. Для 2 МГц вам нужно установить OCR1C на 31. Для 4 МГц вам нужно установить OCR1C на 15. ...

Просто включите PLL с этим кодом:

PLLCSR |= (1 << PLLE);           //Start PLL
while( !(PLLCSR & (1<<PLOCK)) ); //Wait for PLL lock
//PLLCSR |= (1<<LSM );           //Low Speed PLL that clocks 32Mhz, not 64Mhz
PLLCSR |= (1 << PCKE);           //Enable PLL

Теперь у вас есть тактовые частоты 64 МГц на ШИМ "OCR1B0 / OCR1A0".

Кроме того, вы можете настроить OCR1 [A / B] 0 и XOCR1 [A / B] 0 для зеркального вывода.

if(0){ //Synch mode
     //OCR1A & XOCR1A enable for Synch operation but not allow odd PWM values!
     TCCR1 |= (1 << PWM1A) | (0 << COM1A1) | (1 << COM1A0); 
     //Also ATtinyX5 has "Dead Time Generator", use it ;)
     DTPS1 = 3;   //8x Prescaler for dead time generator (maximum)
     DT1A = 0xff; //Clk dead on both channels (maximum)
     }
   else
     TCCR1 |= (1 << PWM1A) | (1 << COM1A1) | (0 << COM1A0);  //ONLY OCR1A enabled

Вы должны знать, что Dead Time Generator съест PWM вне, если вы установите OCR1A = 1. Вам нужны более высокие значения, чем мертвое время.

С Уважением,

Erdem

EUA
источник