Нужен сигнал ШИМ частотой 10 кГц от контактов 3 и 11 с использованием таймера 2.
Работа контакта 11 должна быть инверсной по отношению к контакту 3. Я использовал цифровое чтение и цифровую запись, а также простой, если еще. Но задержка составляет 10 мкс. Что мне делать?
Я нашел этот код на форуме, но он имеет форму таймера 1. Он мне нужен для таймера 2.
void setup()
{
// Определение PB1 и PB2 как выходов путем установки PORTB1 и PORTB2
// Установка DDB1 и DDB2
DDRB |= bit (DDB1) | bit (DDB2);
// остановка таймера 1
TCCR1A = 0;
TCCR1B = 0;
TCCR1A = bit (COM1B0) | bit (COM1B1) // Устанавливаем OC1B при сравнении, очищаем
// OC1B внизу (режим инвертирования)
| bit (COM1A1) // Очистить OC1A при сравнении, установить
// OC1A внизу (неинвертирующий режим)
| bit (WGM11); // Быстрый ШИМ, максимум на ICR1
TCCR1B = bit (WGM12) | bit (WGM13) // то же самое
| bit (CS11); // Запускаем таймер, прескалер 8
// Инициализируем OCR1A = 300 (pulse_width = 150 мкс), OCR1B и ICR1
ICR1 = 0xFFFF;
OCR1B = 299;
OCR1A = ICR1 - OCR1B;
} // конец настройки
void loop()
{
}
@Pranav Pillai, 👍-1
Обсуждение2 ответа
Вы не сможете сделать это с Таймером 2 без внешнего оборудования. Этот код будет генерировать сигнал частотой 10 кГц на выводе 3, однако для этого он использует оба регистра таймера:
- OCR2A используется для установки периода (т. е. частоты)
- OCR2B используется для установки рабочего цикла.
const byte OUTPUT_PIN = 3; // Таймер 2 "B" выход: OC2B
const byte n = 199; // 10 кГц
void setup()
{
pinMode (OUTPUT_PIN, OUTPUT);
TCCR2A = bit (WGM20) | bit (WGM21) | bit (COM2B1); // быстрый ШИМ, очистка OC2A при сравнении
TCCR2B = bit (WGM22) | bit (CS21); // быстрый ШИМ, прескалер 8
OCR2A = n; // период
OCR2B = ((n + 1) / 2) - 1; // рабочий цикл 50%
} // конец настройки
void loop() { }
Обратите внимание, что сигнал с коэффициентом заполнения 50% может генерироваться в режиме CTC, при этом выходы настроены на «переключение на совпадение сравнения»., @Edgar Bonet
и вот, для полноты картины, NPN-транзистор, настроенный как инвертор (НЕ затвор) https://www.tutorialspoint.com/build-an-inverter-with-a-transistor, @6v6gt
@EdgarBonet Я некоторое время пытался получить инвертированный сигнал в различных режимах, но безуспешно., @Nick Gammon
Вы пытались написать бит «Принудительное сравнение вывода»?, @Edgar Bonet
@EdgarBonet Это, похоже, ни на что не влияет. Согласно техническому описанию, эффект возникает только при записи в этот бит, а не на постоянной основе. В моем тестировании в режиме CTC to OCR2A (010) два выхода не совпадают по фазе, но не инверсны друг другу. Фактически, они, похоже, на 50% не совпадают по фазе друг с другом (по какой-то причине). В режиме 101 (PWM to OCR2A) я не получаю выходного сигнала (т. е. 0 В) на выходе B (D3)., @Nick Gammon
А при этом: TCCR2A = бит (WGM20) | бит (WGM21) | бит (COM2A0) | бит (COM2B0) | бит (COM2B1);
и TCCR2B = бит (CS21) | бит (WGM22);
выход B совпадает по фазе с выходом A, но имеет удвоенную частоту., @Nick Gammon
Как пояснил в ответе Ник Гэммон, на самом деле невозможно сгенерировать два ШИМ сигналы с частотой 10 кГц от Таймера 2: регистр OCR2A будет используется для установки частоты, и у вас не будет независимого управления рабочий цикл выхода OC2A.
Однако вы можете создать два дополнительных сигнала по 10 кГц с коэффициентом заполнения 50%. цикл. Это не совсем ШИМ (широтно-импульсная модуляция), так как вы не можете на самом деле модулировать ширину импульса. Если это соответствует вашим потребностям, Решение — настроить выходы в режиме переключения. Написание Бит «принудительное сравнение выходных данных B» создает дополнительный переключатель OC2B, который гарантирует, что выходы будут иметь противоположные фазы. Вот код для сделайте это:
void setup() {
TCCR2B = 0; // остановить Таймер 2
TCNT2 = 0; // сбросить таймер
TCCR2A = _BV(COM2A0) // переключить OC2A при сравнении совпадений
| _BV(COM2B0) // переключить OC2B при сравнении совпадений
| _BV(WGM21); // режим 2 = CTC, TOP = OCRA
OCR2A = 99; // период таймера = 100 * 2 * 8 / C_CPU
OCR2B = 99; // одновременное переключение OC2A и OC2B
TCCR2B = _BV(CS21) // тактовая частота @ F_CPU/8
| _BV(FOC2B); // принудительное сравнение выходного сигнала B: инвертирование сигнала OC2B
DDRB |= _BV(PB3); // OC2A = PB3 = цифровой 11 как выход
DDRD |= _BV(PD3); // OC2B = PD3 = цифровой 3 как выход
}
void loop(){}
Поздравляю! У вас получилось! Как вы сказали, рабочий цикл ограничен 50%, но, как мне кажется, автор этого и хотел., @Nick Gammon
Если кому-то интересно, _BV
и bit
практически идентичны. В hardware/arduino/avr/cores/arduino/Arduino.h
bit
определяется следующим образом: #define bit(b) (1UL << (b))
, а в hardware/tools/avr/avr/include/avr/sfr_defs.h
_BV
определяется следующим образом: #define _BV(bit) (1 << (bit))
., @Nick Gammon
- Использовать timer0, не влияя на millis() и micros().
- Можно ли сгенерировать точный тактовый импульс 15 кГц с помощью ардуино?
- Светодиод Arduino PWM с замиранием в сборке
- генерировать два сдвинутых по фазе ШИМ-импульса, запускаемых внешним сигналом с частотным разделением, с помощью Arduino uno?
- ATmega328P - проблема с использованием таймера 2 для генерации тона
- максимальная частота ШИМ на основе прерываний при 500 Гц
- Как прочитать направление таймера в фазе правильного ШИМ?
- Может ли Arduino uno регулировать входную квадратную волну, фазу и частоту только с помощью таймера-счетчика?
Что мне делать?
... использовать инвертор, @jsotolaВ режиме быстрого ШИМ на таймере 2 контакт 11 использовать нельзя. Только контакт 3. См.: https://forum.arduino.cc/t/atmega328p-timer2-fastpwm-mode/499500. Если вам нужен инверсный контакт 3, то можно использовать простой инвертор (скажем, транзистор), как предложил @jsotola., @6v6gt
а какая у тебя ардуино?, @Juraj
Я использую ардуино ООН, @Pranav Pillai