Таймеры Arduino UNO — Часть 5. Измерение длительности импульсов и частоты (Input Capture)
Теория
Режим Input Capture (ICP1)
Режим Input Capture — это специальная функция Timer1 в микроконтроллере ATmega328P, которая позволяет с высокой точностью измерять моменты прихода фронтов сигнала (нарастающего или спадающего) на пине ICP1 (Arduino UNO — пин D8).
Когда на вход ICP1 поступает выбранный фронт сигнала, текущее значение счётчика TCNT1 автоматически копируется в регистр ICR1. Это позволяет точно зафиксировать момент события без задержек, которые могли бы возникнуть при опросе пина в обычном коде.
Как измерить частоту и длительность
- Частота рассчитывается как
F = F_CPU / (Prescaler * ΔTCNT), гдеΔTCNT— разница между двумя захватами, аPrescaler— выбранный делитель таймера. - Длительность импульса можно определить, измерив время между фронтами (нарастающим и спадающим) одного импульса.
Input Capture полезен в задачах, где требуется высокая точность измерений — например, при создании тахометров, анализаторов сигналов, частотомеров.
Практика
Измерение частоты сигнала от датчика Холла
Пример кода для измерения частоты вращения колеса с датчиком Холла:
volatile uint16_t lastCapture = 0;
volatile uint16_t period = 0;
float frequency = 0;
void setup() {
Serial.begin(9600);
pinMode(8, INPUT);
TCCR1A = 0; // Обычный режим
TCCR1B = 0;
TCCR1B |= (1 << ICES1); // Захват по нарастающему фронту
TCCR1B |= (1 << CS11); // Предделитель 8
TIMSK1 |= (1 << ICIE1); // Разрешение прерывания захвата
}
ISR(TIMER1_CAPT_vect) {
uint16_t capture = ICR1;
period = capture - lastCapture;
lastCapture = capture;
}
void loop() {
if (period > 0) {
frequency = 16000000.0 / (8.0 * period);
Serial.print("Частота: ");
Serial.print(frequency);
Serial.println(" Гц");
delay(500);
}
}
Проект: Тахометр на Arduino UNO
В этом проекте мы используем Input Capture для создания тахометра, измеряющего обороты в минуту (RPM) двигателя.
volatile uint16_t lastCapture = 0;
volatile uint16_t period = 0;
float rpm = 0;
void setup() {
Serial.begin(9600);
pinMode(8, INPUT);
TCCR1A = 0;
TCCR1B = 0;
TCCR1B |= (1 << ICES1); // Захват по нарастающему фронту
TCCR1B |= (1 << CS11); // Предделитель 8
TIMSK1 |= (1 << ICIE1); // Прерывание захвата
}
ISR(TIMER1_CAPT_vect) {
uint16_t capture = ICR1;
period = capture - lastCapture;
lastCapture = capture;
}
void loop() {
if (period > 0) {
float frequency = 16000000.0 / (8.0 * period);
rpm = frequency * 60.0; // 1 импульс на оборот
Serial.print("RPM: ");
Serial.println(rpm);
delay(500);
}
}
Такой тахометр можно использовать в моделях автомобилей, мотоциклов, вентиляторах и других механизмах, где нужно измерять скорость вращения.





