Timer1 на ATtiny85 не работает должным образом

Я пытаюсь использовать Timer1 на ATtiny85 (Adafruit Trinket), чтобы мигать светодиодом каждую секунду. Значение предварительного делителя — 1024, а значение регистра сравнения — 28. Я прокручиваю это 279 раз, чтобы получить задержку в 1 секунду.

1024   . 28   . 279 8   .10 6 1

С приведенным ниже кодом я получаю что-то вроде 8,5 секунд. Я установил -mmcu=attiny85 и -DF_CPU=8000000UL при компиляции. Что я мог упустить.

#include <stdint.h>
#include <avr/interrupt.h>

#define TIMER_OVERFLOW_COUNT 279

volatile uint16_t timerCount = TIMER_OVERFLOW_COUNT;
ISR(TIMER1_OVF_vect)
{
    timerCount++;
}

int main(void)
{
    DDRB = 1 << DDB1;
    OCR1C = 28;
    TIMSK = 1 << TOIE1;
    sei();
    TCCR1 = (1 << CS13) | (1 << CS11) | (1 << CS10);
    while( 1)
    {
        if( timerCount >= TIMER_OVERFLOW_COUNT)
        {
            timerCount = 0;
            PORTB ^= 1 << PORTB1;
        }
    }
    return 0;
}
Обновление timerCountкак обработчика прерывания, так и цикла - плохая идея. У вас тут состояние гонки. Почему бы не поместить всю логику в обработчик? Это не так уж и тяжело.
@ЕвгенийШ. хотя это правда, мне трудно поверить, что это происходит все время в системе, частота которой намного выше, чем частота прерывания. Отключение прерываний до и включение после изменения основной функции - все еще хорошая идея... Хотя мне не нравится тайная магия установки частоты с помощью опции компилятора - действительно ли она работает на частоте 8 МГц? Есть ли в ATTiny85 прескалеры для периферии?
Вы уверены, что MCU работает на частоте 8 МГц?
@EugeneSh., спасибо. Но это не решает проблему, с которой я столкнулся.
Зачем это F_CPUвообще нужно? Я думаю, что он используется только для некоторых библиотечных функций задержки, которые не используются в коде.
С тактовой частотой 1 МГц по умолчанию эта задержка должна составлять около 8 секунд.
Ждать. Вы не хотите прерывать переполнение, вы хотите прерывать сравнение совпадений
@БенсКауликс. Я заставил это работать с таймером 0. Я уверен, что это 8 МГц.
@EugeneSh понял, что вы получаете прерывание при переполнении, а не когда счетчик достигает 28. Вы должны установить бит, OCIE1Cа не TOIE1in TIMSK. Насколько я помню.
@ЕвгенийШ. Возможно, вы правы, я думаю. Моя проблема сейчас в том, что я не вижу, как это сделать.
@BenceKaulics В TIMSK нет бита OCIE1C. Таким образом, прерывание при сравнении совпадений невозможно, если только я не использую OCR1A или OCR1B?
@SubaThomas Я точно прав. Но способ сделать это должен быть описан в таблице данных и продемонстрирован в некоторых учебниках.
Это было просто предположение, как вы устанавливаете, OCR1C = 28но затем используйте OCR1A = 28;и установите OCIE1A.
@ЕвгенийШ. В даташите нет TIMER1_COMPC. Поэтому, хотя я согласен с тем, что вы правы, я не думаю, что это возможно вызвать прерывание сравнения совпадений. (Если я не смотрю достаточно внимательно.)
Есть TIMER1_COMPA.. вы можете использовать его очень хорошо. Или вы все еще можете использовать прерывание переполнения, если каждый раз правильно вычисляете начальное значение таймера (MAX-28).
@EugeneSh и Бенс Кауликс, спасибо за вашу помощь. Я внимательно прочитал техническое описание и обнаружил следующее: «В обычном режиме прерывание по переполнению (TOV1) генерируется, когда Timer/Counter1 считает от $FF до $00…» По сути, опция сравнения совпадений недоступна в нормальный режим. Я изменил TIMER_OVERFLOW_COUNT на 31 и установил OCR1C на 255 (что действительно излишне), и все работает, как и ожидалось.
По сути, опция сравнения матчей недоступна в обычном режиме. Звучит очень подозрительно для меня. Как вы пришли к такому выводу?
1) Когда я нахожусь в обычном режиме, TCNTI считает 255 раз. Задержка в моем исходном коде была 9.1
1024   . 255   . 279 8   .10 6
2) Я не смог найти задокументированного прерывания сравнения совпадений. В этом режиме задокументировано только прерывание переполнения.
Я написал код для прерывания на 1 секунду для другого avr в этом вопросе с прерыванием сравнения вывода и совпадения. Таймер должен находиться в режиме CTC (сброс таймера при совпадении сравнения).
@BenceKaulics, у этого таймера нет режима CTC. Есть бит CTC1, который сбрасывает счетчик таймера, когда есть совпадение с OCR1C, но нет прерывания для захвата, когда это происходит.
@SubaThomas - у этого таймера нет режима CTC. Я очень опаздываю в эту тему, но вы абсолютно правы. Спасибо, что заметили эту тонкую разницу — формулировка в таблице данных настолько запутана. Я обошел это, используя режим PWM1A и установив для OCR1A и OCR1C желаемый TOP — в моем случае 103 на частоте 1 МГц, чтобы получить 9600 бит/с. Еще раз спасибо. Спасительный комментарий прямо здесь!

Ответы (1)

Предохранитель CKDIV8 программируется на устройствах, только что выпущенных с завода. Если вы забудете перепрограммировать этот предохранитель, устройство будет работать на 1/8 ожидаемой тактовой частоты.