Я пытаюсь использовать Timer1 микроконтроллера Atmel AVR, либо AtMega328, который используется в Arduino, либо ATTiny85, для вывода двух тактовых сигналов, которые являются зеркальными отображениями друг друга. Частота, которую я пытаюсь сгенерировать, представляет собой переменную от 1 МГц до 2 МГц или более, что слишком высоко, чтобы сделать это с помощью кода для переключения выходных контактов, если я не хочу делать почти ничего другого в контроллере. Поэтому я хочу использовать выход таймера непосредственно на связанных выводах. Я использую набор инструментов GCC, поэтому не ограничен библиотеками или языком arduino.
Timer1 в Atmega328 имеет два контакта, связанных с ним, и я могу получить от них два идентичных сигнала от 1 МГц до 2 МГц. Хотя в техническом описании, кажется, говорится, что я могу получить инвертированную форму волны, это сбивает меня с толку. Я также могу получить два сигнала с разными рабочими циклами на частоте 1 МГц, используя настройки ШИМ с Timer1, но оба сигнала становятся высокими одновременно, более короткий сигнал становится низким раньше. Это не служит моему проекту. Мне даже не нужно изменение ширины импульса ШИМ, мне просто нужны два одинаковых сигнала типа «часы» с противоположной фазой, вот и все.
Я не прошу никого писать для меня код, чтобы сделать это, мне просто нужно, чтобы кто-то сказал мне, какой режим/флаги таймера должны дать мне простой инвертированный сигнал на одном из двух контактов, связанных с таймером. Если возможно, я хочу избежать использования внешней инвертирующей схемы для одного из выходов, если только это не единственный вариант.
Если это вообще возможно в ATTiny, это будет еще лучше. ATTiny также имеет 2 контакта, связанных с одним таймером, но я не уверен, что у него есть те же параметры, что и у ATMega.
У меня уже есть кристалл на 20 МГц и конденсаторы, подключенные к плате, и часы на 20 МГц надежно работают на ATMega328. На плате ATTiny85 у меня стоит кварц 8МГц и он тоже работает надежно.
Пожалуйста помоги. Спасибо.
ОБНОВЛЕНИЕ . Пока что в ответах и комментариях есть несколько неверных предположений, поэтому, возможно, мне следует уточнить: обратите внимание, что в моем исходном сообщении я заявил, что использую тактовую частоту 20 МГц, а не 8 МГц , а также что мне не нужен ШИМ .
Единственным режимом, дающим достаточно высокую выходную частоту, является режим CTC, потому что режимы PWM не работают для выходной частоты 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, чтобы моя самодельная плата не вводила режим ошибки, и чтобы любой, у кого есть Arduino, мог попробовать мой код выше и убедиться, что он работает так, как я упомянул, а не как я. необходимость!
Из таблицы данных 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 показано, как установить режим сравнения вывода для режима Fast PWM.
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) для режима Fast PWM.
Таким образом, вы можете использовать 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 МГц
Так что я все еще думаю, что вам нужен режим Fast PWM. В частности, режим 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(){
}
Семейство ATtinyX5 имеет PLL внутри, используйте его, большой мальчик.
Я также использую внутреннюю PLL для питания тактовой частоты процессора и имею 16 МГц без XTAL. Это ценно, так как у вас всего 5 булавок. (я не считаю пин-код сброса). Также один ШИМ с ФАПЧ (OCR1B) работает на контактах XTAL с дополнительным дополнительным выходом. Вам просто нужно отрегулировать предохранители для 16Mhz Xtalless ATtiny... Или просто позволить процессору работать на частоте 8Mhz, но запустить PWM с тактовой частотой 64Mhz без замены предохранителей..
Вы можете иметь ШИМ с тактовой частотой до 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
Вы должны знать, что генератор мертвого времени будет потреблять выход PWM, если вы установите OCR1A = 1. Вам нужны более высокие значения, чем мертвое время.
С уважением,
Эрдем
Ворак
Кристоф Б.