Юрий_СВ (22.07.2013 15:51 - 16:52, просмотров: 7850)
Не могу найти дырку в своём простом алгоритме. А желательно сделать это за пару часов. Суть: измерение оборотов, программно(старшее слово)-аппаратный(младшее слово) захват значения таймера . Для расчёта кол-ва оборотов в минуту - расчитывается период оборота.
Период оборота - разность временных отсчётов (текущего и прошлого)
Временной отсчёт состоит из старшего (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);
}