ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Пятница
26 апреля
426391
Юрий_СВ (22.07.2013 15:51 - 16:52, просмотров: 7510)
Не могу найти дырку в своём простом алгоритме. А желательно сделать это за пару часов. Суть: измерение оборотов, программно(старшее слово)-аппаратный(младшее слово) захват значения таймера . Для расчёта кол-ва оборотов в минуту - расчитывается период оборота. Период оборота - разность временных отсчётов (текущего и прошлого) Временной отсчёт состоит из старшего (16 бит) и младшего (11 бит - разрядность таймера под ШИМ) слов. Младшее слово считается и захватывается аппаратно (таймером). Старшее слово увеличивается и считается программно (асинхронно) в прерывании по переполнению таймера. Явно видна ошибка алгоритма. Алгоритм ошибается на единицу старшего слова в меньшую сторону. Т.е. неверный результат на 2048 единиц временного отсчёта меньше правильного. Ошибка происходит в 70% случаев. Правильность зависит от фазы захвата относительно младшего слова (0-2047). Обычный период тестового сигнала (50 Гц) - 9 ед. старшего слова + 1380 ед. младшего Частота прерываний примерно 500 Гц (от RC 1 МГц) (ATmega8A) (Фаза текущего отсчёта) Правильная работа в диапазоне 0x0301-0x05bc (769-1468) (длина 699) Неверная работа в диапазоне 0x05a6-0x0315 (1446-789) (длина 1391) Т.е. есть нахлёст диапазонов (20-22 единиц). 1-й захват происходит до TCNT1=52 (51-54) 2-й захват происходит до TCNT1=0x02b4 (0x02ac-0x02d7) (684-727) //-------------------------------------------------------------------------------- typedef struct { u32_t period; // период вращения вала в периодах кварцевого генератора (1 МГц) u32_t last_tick; // время появления предыдущего импульса от датчика оборотов u16_t cnt_high; // старшие (програмные) разряды счётчика тахометра (младшие разряды - аппаратные - таймер 1) u16_t idle_time; // кол-во периодов таймера после последнего сигнала от датчика оборотов u8_t last_pulse_too_old; // флаг "предыдущий импульс от датчика был слишком давно", т.е. непригоден для расчёта u8_t pure_val; // флаг "негодное значение тахо" (давно не было сигнала или недопустимый период) } tachometer; //-------------------------------------------------------------------------------- typedef struct { u16_t tcnt_1; u16_t tcnt_2; u16_t icr_1; u16_t icr_2; u8_t fl_1; u8_t fl_2; }icapture; //-------------------------------------------------------------------------------- void icapt(icapture * icap) { u32_t period; u32_t tick; tacho.cnt_high++; if ( (icap->fl_1==0)&&(icap->fl_2==0) ) // проверка наличия захвата и готовности измерителя { // таймер, проверяющий наличие сигналов от датчика оборотов if (tacho.idle_time<TACHO_MAX_IDLE_TIME) tacho.idle_time++; else {tacho.last_pulse_too_old=1; tacho.pure_val=1; } // 1/4 сек return; } else tacho.idle_time=0; if(icap->fl_1) // получение отсчёта с выяснением к какому периоду (tacho.cnt_high) таймера относиться отсчёт (текущему или предыдущему) {// учитываем когда произошёл захват ПОСЛЕ или ДО переполнения счётчика tick=(icap->icr_1 <= icap->tcnt_1)? tacho.cnt_high : tacho.cnt_high-1; tick<<=PWM_TIMER_WIDTH; tick+=icap->icr_1; } else { tick=tacho.cnt_high; tick<<=PWM_TIMER_WIDTH; tick+=icap->icr_2; } // === уже здесь видна (на ЖКИ или УАПП) ошибка в значении === // period=tick-tacho.last_tick; // вычитаем предыдущее // tacho.period=period; // ..... tacho.last_tick=tick; } //-------------------------------------------------------------------------------- ISR (TIMER1_OVF_vect) // 500 Гц { icapture icap; icap.fl_1=TIFR; icap.tcnt_1=TCNT1; icap.fl_1 &=0x20; if(icap.fl_1) {icap.icr_1=ICR1; TIFR|=0x20;} // 1-й захват // другие задачи icap.fl_2=TIFR; icap.tcnt_2=TCNT1; icap.fl_2&=0x20; if(icap.fl_2) {icap.icr_2=ICR1; TIFR|=0x20;} // 2-й захват icapt(&icap); }