Квадратная волна 100 Гц с рабочим циклом 50% в цифровом выводе 3 и проверка с помощью вывода 4

Я застрял на этом на некоторое время, я пытаюсь генерировать прямоугольную волну 100 Гц с рабочим циклом 50% на выводе 3 и пытаюсь проверить ее с помощью провода на выводе 4; Я получаю 64000, но не 100 в последовательном мониторе.


#define LEDPIN 3

uint16_t val2= pulseIn(4, HIGH);

ISR(TIMER1_COMPA_vect) { digitalWrite(LEDPIN, !digitalRead(LEDPIN)); }
void setup() {
Serial.begin(9600);
pinMode(LEDPIN, OUTPUT);
// initialize Timer1 (the 16-bit timer) using channel A output compare
noInterrupts(); // disable global interrupts
// TIMER 1 for interrupt frequency 100 Hz:
cli(); // stop interrupts
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
// set compare match register for 100 Hz increments
OCR1A = 19999; // = 16000000 / (8 * 100) - 1 (must be <65536)
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS12, CS11 and CS10 bits for 8 prescaler
TCCR1B |= (0 << CS12) | (1 << CS11) | (0 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei(); // allow interrupts
//TCCR1A = 0; // Timer/Counter Control Register 1A
//TCCR1B = 0; // (both control registers need to be configured)
//// set compare match register to desired timer count:
//OCR1A = 15624; // Output Compare Register 1A (i.e., for channel A)
//TCCR1B |= (1 << WGM12); // CTC (Clear Timer on Compare Match) mode
//TCCR1B |= (1 << CS10); // for 1,024 prescaler; UNO has a 16 MHz clock
//TCCR1B |= (1 << CS12);
//TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
interrupts(); // enable global interrupts:
}
void loop() {
uint16_t val = OCR1A/8;

ICR1 = val -1;
OCR1A = val/2 - 1 ; // 50% duty cycle for pin 3
//OCR1B = val/2 - 1 ; // 50% duty cycle for pin 4
//uint16_t val2= pulseIn(4, HIGH);
Serial.print(val2);
delay(1000);
Serial.print("\n");

}

, 👍1


1 ответ


2

Вы написали:

uint16_t val2 = pulseIn(4, HIGH);

Нет смысла вызывать это здесь, так как таймер не был инициализирован. В этом контексте вы, вероятно, не можете ожидать ничего, кроме тайм-аута .

noInterrupts();
cli();

Эти два понятия являются синонимами. Не нужно повторяться. На самом деле, вообще не нужно блокировать прерывания.

sei();
interrupts();

То же.

OCR1A = 19999; // = 16000000 / (8 * 100) - 1

Предполагается, что это вызовет прерывания на частоте 100 Гц. Но если вам нужен выходной сигнал 100 Гц, вы должны запускать прерывания на частоте 200 Гц (два прерывания за цикл). Таким образом:

OCR1A = 9999; // = (16 MHz / 8) / (2 * 100 Hz) - 1

Затем,

// Установите биты CS12, CS11 и CS10 для 8 прескалеров
TCCR1B |= (0 << CS12) | (1 << CS11) | (0 << CS10);

Это настройка таймера 1 для внешнего источника синхронизации. Если вам нужен прескалер ÷8, вы должны установить только бит CS11. Проверьте данные.

uint16_t val = OCR1A/8;
ICR1 = val -1;
OCR1A = val/2 - 1 ; // 50% duty cycle for pin 3

Для меня это не имеет никакого смысла. Почему вы устанавливаете ICR1? Почему вы меняете OCR1A, хотя он уже был настроен в setup()? Вы можете удалить все это. Вот loop() Я использовал для тестирования:

void loop() {
    Serial.println(pulseIn(3, HIGH));
    delay(1000);
}

И он неоднократно печатал 4955, что довольно близко к ожидаемому значению (а именно 5000).

,

Спасибо за вашу помощь., @ram patel

TCR1B |= (0 << CS12) | (1 << CS11) | (0 << CS10); делится на 8. Это смещение пары нулей. Это как TCR1B |= (0b010 << CS10); но мне нравится `0b010<, @Dave X