zeleny (22.07.2013 16:33 - 16:59, просмотров: 344) ответил Юрий_СВ на Не могу найти дырку в своём простом алгоритме. А желательно сделать это за пару часов. Суть: измерение оборотов, программно(старшее слово)-аппаратный(младшее слово) захват значения таймера .
не совсем понятна логика вашего прерывания. Вот мой вариант (под Ардуино-Мега8), пока никаких заскоков не замечено:
volatile uint16_t rpm; //об/мин
volatile uint8_t rpm_rdy; //флаг готовности счетчика (0-не готов, 1-готов, 2-переполнение (стоп/или медленные обороты)
volatile uint32_t rpm_cnt; //значение счетчика
volatile uint16_t rpm_high_cnt; //старшая половина счетчика
//настройка
void rpm_setup() {
//вывод ICR1 - на вход
pinMode(8, INPUT_PULLUP);
digitalWrite(8, HIGH);
//запуск таймера 1, разрешение прерываний
TCCR1A = 0;
TCCR1B = (1<<ICNC1)|(1<<CS10);
TIMSK |= (1<<TICIE1)|(1<<TOIE1);
}
//осн.программа
void main() {
while (1) { //гл.цикл
if (rpm_rdy) { //готовность счетчика ?
if (rpm_rdy == 1) { //==1 - расчет RPM + фильтр
rpm = (rpm + (F_CPU * 60UL) / rpm_cnt) >> 1;
} else if (rpm_rdy == 2) { //==2 - переполнение, обнуление RPM
rpm = 0;
rpm_cnt = 0;
}
rpm_rdy = 0; //сброс флага
}
}}
//прерывание захвата
ISR(TIMER1_CAPT_vect) {
if (!rpm_rdy) { //флаг сброшен ?
rpm_cnt = ((uint32_t)rpm_high_cnt << 16) | ICR1; //рассчитать значение счетчика из двух половин
rpm_rdy = 1; //установить флаг
}
TCNT1 = rpm_high_cnt = 0; //сбросить таймер/счетчик
}
//прерывание переполнения - инкремент старшей половины счетчика
ISR(TIMER1_OVF_vect) {
if (rpm_high_cnt < 1000) { //ограничить максимум
rpm_high_cnt++;
if (rpm_high_cnt == 1000) { //переполнение - выставить флаг переполнения
rpm_rdy = 2;
}
}
}