Неточность частоты таймера AVR CTC - PullRequest
0 голосов
/ 05 ноября 2018

Я новичок в программировании устройств AVR, пытаясь отойти от неэффективных функций блокировки _ms_delay () и _us_delay (), которые я пробовал запрограммировать, используя встроенные таймеры для управления синхронизацией основного светодиода. мигает программа с режимом таймера CTC на 16-битном таймере. Моя цель - сделать так, чтобы светодиод мигал с частотой 2 Гц, включался на 0,5 с, выключался на 0,5 с.

В соответствии с таблицей ATMega328P частота вывода CTC должна быть f_CTC = f_Clock / (2N (OCR1A + 1), поскольку мой чип представляет собой мини-процессор 328P Xplained mini, по умолчанию скорость процессора составляет 16 МГц, используя приведенную выше формулу, с N = 64, требуемое значение OCR1A для достижения желаемой частоты должно быть 62499. Учитывая все это, я написал следующий код:

#include <avr/io.h>

int main(void)
{
    // Setup for timer TC1 (16-bit) in CTC mode to run at 2 Hz
    TCCR1A = 0x00;
    OCR1A = 62499; // Sets time resolution to 0.5 s
    TCCR1B = 0x0b;
    TCCR1C = 0x00;

    // Set pin directions
    PORTD &= ~(1<<PORTD6);
    DDRD |= (1<<DDD6);

    while (1) 
    {
        if(TIFR1 & (1<<OCF1A))
        {
             PORTD ^= (1<<PORTD6);
        }
        TIFR1 |= (1<<OCF1A);
    }
}

Однако, когда я запускаю код, светодиод мигает с частотой 1 Гц, которую я смог рассчитать на моем телефоне. Кроме того, когда я изменяю OCR1A на 31249, что должно увеличить частоту до 4 Гц, он, кажется, мигает с частотой 8 Гц или включается и выключается 4 раза в секунду. Мне кажется, что я неправильно понимаю что-то о том, как работает режим CTC, если кто-то может объяснить это просто мне или о любых других проблемах с моим кодом, я был бы признателен.

1 Ответ

0 голосов
/ 05 ноября 2018

Я заметил одну вещь, которая может вызвать проблемы, которые вы видите.

Вы используете строку TIFR1 |= (1<<OCF1A); для сброса бита OCF1A. Вы запускаете эту строку очень часто, поэтому есть большая вероятность, что когда OCF1A будет установлен, ваш код просто очищает его непосредственно перед тем, как оператор if увидит, что он был установлен. Вы не можете контролировать, когда этот бит будет установлен; это может произойти в любой точке вашего цикла.

Вы должны очистить OCF1A только после того, как убедитесь, что оно равно 1, например:

if (TIFR1 & (1 << OCF1A))
{
    PORTD ^= (1 << PORTD6);
    TIFR1 |= (1 << OCF1A);
}
...