воскресенье, 23 марта 2025 г.

Подсчёт времени на ATmega328P

В прошивке измерителя ёмкости аккумуляторов есть код, который считает время разряда аккумулятора. Этот код я нашёл на одном из форумов посвящённых Arduino тематике и он выглядит довольно простым:

volatile uint8_t runTimeIsr = 0;
uint8_t runTimeLoop;
uint32_t runTime;

// https://gist.github.com/raspberrypisig/8bf856ae9b55bb433d4c11ac9540a881
void timerInit() {
    noInterrupts();
    // Clear registers
    TCCR1A = 0;
    TCCR1B = 0;
    TCNT1 = 0;

    // 1 Hz (16000000/((15624+1)*1024))
    OCR1A = 15624;
    // CTC
    TCCR1B |= (1 << WGM12);
    // Prescaler 1024
    TCCR1B |= (1 << CS12) | (1 << CS10);
    // Output Compare Match A Interrupt Enable
    TIMSK1 |= (1 << OCIE1A);
    interrupts();
}

ISR(TIMER1_COMPA_vect) {
    runTimeIsr += 1;
}

После запуска таймера переменная runTimeIsr считывается в основном цикле и затем обнуляется. Поскольку операция сложения с четырёхбайтной переменной занимает несколько циклов, то используется промежуточная переменная runTimeLoop чтобы избежать конфликта с обработчиком прерывания

void timerDo() {
    runTimeLoop = runTimeIsr;
    runTimeIsr = 0;
    runTime += runTimeLoop;
}

В теории обработчик прерывания должен вызываться каждую секунду если микроконтроллер работает на частоте 16 МГц, но в реальности за 3 часа тестирования время, измеренное микроконтроллером отстало от реального на 35 секунд.

При этом посчитанная ёмкость составила 299 мАч вместо ожидаемых 300 - выглядит как допустимая погрешность, но стало любопытно в чём причина.

Кварцевый резонатор перед установкой на плату измерял тестером кварцев и он показал 15,999 МГц. На всякий случай проконтролировал частоту осциллографом - щуп осциллографа переключается в режим 10Х (чтобы снизить влияние ёмкости щупа на генератор микроконтроллера) и подключается к ножке XTAL2 (выход генератора частоты микроконтроллера)

Курсорные измерения показывают частоту 15,92 МГц, но это с округлением. Есть период колебания 62,8 наносекунды (BX - AX) и я могу вычислить частоту как F = 1 / (62,8 * 10^-9) = 15923566 Гц.

Таким образом значение OCR1A в коде нужно скорректировать на 15549 (15923566 / 1024 - 1 = 15549). Заливаю обновленную прошивку и оставляю на час поработать. В результате измеренное время опередило реальное на 11 секунд за один час тестирования.

Сделал несколько тестов каждый раз уточняя значение OCR1A. В итоге мне это надоело и я добавил на плату микросхему часов реального времени DS1307. Из всего функционала этой микросхемы используется только сигнал 1 Гц, который подключён ко входу прерывания INT0.

Батарейка резервного питания не используется. При инициализации часов реального времени устанавливается дата и время изменения прошивки.

За один час тестирования измеренное время отстало от реального на 2 с. Чтобы понять виноват сейчас часовой кварц или алгоритм нужно сравнить показания времени RTC с тем что считает по таймеру.

Комментариев нет:

Отправить комментарий