Измерение частоты с помощью таймеров

Таймеры-счетчики

Таймером называется средство микропроцессора, служащее для измерения времени и реализации задержек. Основой таймера служит суммирующий счетчик, который считает количество импульсов генератора тактовой частоты.
Для таймера могут быть указаны:

  • разрядость таймера;
  • коэффициент предварительного деления;
  • диапазон изменения счетного регистра;
  • режим работы.

Разрядность таймера представляет собой разрядность двоичного счетчика, используемого для его реализации и определяет верхнюю допустимую границу счетного регистра. Например, для 8-разрядного таймера верхняя граница счетного регистра будет 2 8 -1 = 255.

Предварительный делитель – делитель частоты тактового сигнала, работающий как один или несколько последовательно соединенных T-триггеров. Таймер изменяет свое значение на 1 каждые n сигналов тактового импульса. n называют коэффициентом предварительного деления .

Зная частоту тактового генератора fosc и коэффициент предварительного деления Kpre, легко определить частоту таймера по формуле:

Время одного тика таймера соответственно будет

Полное время счета таймера (время перебора всех допустимых значений двоичного счетчика) определится как

Например, если требуется реализовать задержку 1с на 8-разрядном таймере с коэффициентом предварительного деления Kpre=1 и тактовой частотой fosc=8 МГц, имеем

tic = 0,125 мкс;
Tcount = 0,125*2 8 = 32 мкс
1с/32мкс = 31250 повторений

Широтно-импульсная модуляция

Широтно-импульсная модуляция (ШИМ) – импульсный сигнал постоянной частоты и переменной скважности.
Скважность есть отношения периода следования импульса к длительности импульса.
С помощью задания скважности (длительности импульсов) можно менять среднее напряжение на выходе ШИМ.
Обратная величина, то есть отношение длительности импульса к периоду, называется коэффициентом заполнения .

Разрядностью ШИМ называется разрядность таймера, используемого для формирования ШИМ-сигнала.
Существуют два основных режима работы ШИМ:

Быстрый ШИМ

Период ШИМ определяется максимальным значением, до которого считает счетчик. В этот момент ШИМ-сигнал устанавливается в «1». При достижении счетчиком значения, поданного на второй вход цифрового компаратора, осуществляется сброс выходного ШИМ-сигнала.

Фазовый ШИМ

В данном режиме счетчик работает как суммирующий и считает от 0 до максимального значения, а при достижении максимального значения работает как вычитающий, считая до 0.

При совпадении значения счетчика с некоторым установленным значением, происходит переключение выхода ШИМ.

Частотно-импульсная модуляция — сигнал переменной частоты и постоянной скважности, равной 2. При таком виде модуляции изменяется период сигнала, а длительность импульса всегда составляет половину периода.

Источник

Схема

Логика программы

Структура проекта

Проект состоит из 4-ех программных модулей.
bcd.c – содержит функцию для перевода 16-ти разрядных двоичных чисел в двоично-десятичные. На ней мы останавливаться не будем.
timer.c – содержит функцию инициализации таймера Т1, обработчик прерывания по событию захват и функцию возвращающую содержимое буфера.
lcd_lib.c – библиотека для работы с символьным дисплеем.
main.c — основная программа.

Рассмотрим содержимое модуля timer.c

Инициализация таймера/счетчика Т1

void TIM_Init( void )
<
TIMSK = (1
volatile unsigned int
tachBuf = 0; //буфер

#pragma vector=TIMER1_CAPT_vect
__interrupt void Timer1Capt( void )
<
TCNT1 = 0; //обнуляем счетный регистр
tachBuf = ICR1; //сохраняем значение регистра захвата в буфере
>

volatile unsigned int tachBuf = 0;
unsigned long tachFltr = 0;
unsigned char count = 0;

//прерывание по событию захват
#pragma vector=TIMER1_CAPT_vect
__interrupt void Timer1Capt( void )
<
TCNT1 = 0;

//накапливаем 8 измерений и вычисляем среднее арифметическое
tachFltr += ICR1;
count++;
if (count == 8)
<
tachBuf = ( unsigned int )(tachFltr >> 3);
tachFltr = 0;
count = 0;
>
>

Функция, возвращающая содержимое буфера

__monitor unsigned int TIM_GetTachBuf( void )
<
unsigned int tmp = tachBuf;
tachBuf = 0;
return tmp;
>

Основная программа

//****************************************************
// Author(s). Pashgan http://ChipEnable.Ru
// Target(s). ATMega8535
// Compiler. IAR 5.11A
// Description.: Таймер Т1. Прерывание по событию захват.
// Простой частотомер на AVR
// Data. 13.02.10
//*****************************************************
#include
#include
#include «lcd_lib.h»
#include «bcd.h»
#include «timer.h»

int main( void )
<
unsigned int tachValue;

PORTD = 0xff;
DDRD = 0x00;

__enable_interrupt ();
while (1) <
__delay_cycles (1000000);

//берем “захваченное” значение и выводим его на lcd
tachValue = TIM_GetTachBuf();
LCD_Goto(0,1);
BCD_5IntLcd(tachValue);

//вычисляем значение частоты и выводим его на lcd
tachValue = ( unsigned int ) (8000000UL/tachValue);
LCD_Goto(0,0);
BCD_5IntLcd(tachValue);
>
return 0;
>

tachValue = ( unsigned int ) (8000000UL/tachValue);

UL – указание компилятору, что тип констаныт unsigned long. Конечно, он и сам может догадаться, но это не будет лишним.
(unsigned int) – указание компилятору преобразовать результат вычисления к типу unsigned int.

Погрешность

20 __interrupt void Timer1Capt(void)
\ Timer1Capt:
21 <
\ 00000000 93AA ST -Y, R26
\ 00000002 939A ST -Y, R25
\ 00000004 938A ST -Y, R24
\ 00000006 93FA ST -Y, R31
\ 00000008 93EA ST -Y, R30
\ 0000000A 934A ST -Y, R20
\ 0000000C 933A ST -Y, R19
\ 0000000E 932A ST -Y, R18
\ 00000010 931A ST -Y, R17
\ 00000012 930A ST -Y, R16
\ 00000014 B74F IN R20, 0x3F
22 TCNT1 = 0;
\ 00000016 E000 LDI R16, 0
\ 00000018 BD0D OUT 0x2D, R16
\ 0000001A BD0C OUT 0x2C, R16
.

34 тактам и это время мы не учитываем при расчете частоты.

Исправим этот момент.

volatile unsigned int tachBuf = 0;
unsigned long tachFltr = 0;
unsigned char count = 0;
#define ERROR 34

//прерывание по событию захват
#pragma vector=TIMER1_CAPT_vect
__interrupt void Timer1Capt( void )
<
TCNT1 = 0;

tachFltr += (ICR1 + ERROR);
count++;
if (count == 8)
<
tachBuf = ( unsigned int )(tachFltr >> 3);
tachFltr = 0;
count = 0;
>
>

Прошиваем микроконтроллер и снова проверяем частотомер. Ого, намного лучше.

Файлы

Если честно, я так и сделал. Но это нисколько не обесценивает вышеизложенного объяснения.

Источник

Измерение частоты с помощью таймеров

16-битный таймер-счетчик 1 (16-bit Timer/Counter1) микроконтроллера ATmega32A позволяет точно вычислять время выполнения программы (может использоваться для обработки событий, event management), генерации звука, измерения длительностей цифровых сигналов.

Упрощенная блочная диаграмма 16-bit Timer/Counter показана на рисунке. Для того, чтобы определить действительное назначение выводов, относящихся к счетчику, см. даташит микроконтроллера, в котором имеется разводка выводов кристалла (Pinout ATmega32A).

Пояснения к диаграмме: буква n в именах регистров и битов может быть заменена на цифру 0, 1 или 2, в зависимости от того, какой счетчик используется — в разных моделях микроконтроллеров AVR может быть разное количество счетчиков с разными номерами. В нашем примере будет использоваться 16-bit Timer/Counter1 микроконтроллера ATmega32A, поэтому n=1.

[Измерение длительности импульсов с помощью 16-bit Timer/Counter1]

Импульсы можно регистрировать аппаратно (и измерять их длительность), если подать цифровой сигнал на вывод ICP1. Регистрация импульсов в даташите Atmel также называется «захватом событий» (capture event) и «захватом по входу» (Input Capture). Отсюда понятна аббревиатура ICP1 — Input Capture Pin 1: ножка захвата, относящаяся к таймеру/счетчику 1.

Для микроконтроллера ATmega32A в корпусе TQFP44 ножкой ICP1 будет порт PD6, ножка 15 корпуса TQFP44, у макетной платы AVR-USB-MEGA16 [2] это будет контакт P21.

Для измерения длительности импульсов нужно сделать следующее:

— Настроить тактирование таймера 1 от внутреннего тактового генератора.
— Создать обработчик прерывания для события захвата (Timer/Counter1 Input Capture Interrupt) и разрешить прерывание по событию захвата.
— Разрешить работу узла захвата по входу ICP1.

Настройка тактирования таймера и разрешение работы узла захвата производится записью в соответствующие регистры (см. раздел «Регистры 16-bit Timer/Counter 1»). В обработчике прерывания Input Capture нужно сохранить или проанализировать значение счетчика, чтобы по нему определить длительность входного импульса.

[Подсчет импульсов с помощью 16-bit Timer/Counter1]

Импульсы можно считать аппаратно, если подать цифровой сигнал на вывод T1. У микроконтроллера ATmega32A это порт PB1, ножка 41 корпуса TQFP44, контакт P9 макетной платы AVR-USB-MEGA16.

Чтобы подсчитывать импульсы, нужно сделать следующее:

— Настроить тактирование таймера/счетчика 1 от входа T1.
— Настроить обработчик прерывания по переполнению таймера/счетчика (Timer/Counter1 Overflow Interrupt).
— Организовать в программе анализ и сброс значения таймера/счетчика 1.

Обычно подсчет импульсов нужен для измерения частоты некоторого цифрового сигнала. В этом случае нужно анализировать и сбрасывать значение таймера/счетчика через равные, заранее определенные интервалы времени. Если произошло переполнение (когда сработало прерывание по переполнению) до истечения интервала времени, то значит входная частота на T1 слишком высокая и для измерения частоты нужно либо подсчитывать переполнения, либо уменьшить интервал времени опроса таймера/счетчика.

Пример измерения частоты на входе T1

[Регистры 16-bit Timer/Counter 1]

Для измерения длительностей и подсчета импульсов нам потребуются следующие регистры (остальные регистры типа TCCR1A, OCR1AH, OCR1AL, OCR1BH, OCR1BL за ненадобностью здесь не рассматриваются, подробное описание всех регистров см. в даташите).

TCCR1B – Timer/Counter1 Control Register B

• Bit 7 – ICNC1: Input Capture Noise Canceler. Установка этого бита в лог. 1 активирует входной подавитель шума, при этом будет фильтроваться входной сигнал Input Capture Pin (ICP1). Функция фильтрации требует 4 последовательных одинаковых значений, поступивших на вывод ICP1, чтобы было зарегистрировано изменение уровня сигнала. Таким образом, захват входных импульсов (Input Capture) будет задержан на 4 такта генератора микроконтроллера, когда возможность фильтрации разрешена.

• Bit 6 – ICES1: Input Capture Edge Select. Этот бит выбирает тип среза (фронт или спад) на входе ICP1, который вызовет событие захвата импульса. Когда в ICES1 записан лог. 0, то спад (отрицательный срез) вызовет срабатывание триггера, и когда в ICES1 записан лог. 1, срабатывание триггера вызовет уже фронт (положительный срез) сигнала.

Когда срабатывает триггер захвата события по входу в соответствии с установкой ICES1, значение счетчика (TCNT1, регистры TCNT1H и TCNT1L) копируется в регистр захвата Input Capture Register (ICR1). Событие также вызовет установку флага Input Capture Flag (ICF1), и это может использоваться для срабатывания прерывания Input Capture Interrupt, если оно разрешено.

• Bit 2:0 – CS12:10: Clock Select. Эти 3 бита задают источник тактового сигнала для счетчика.

CS12 CS11 CS10 Описание
0 0 0 Источник тактов не задан (таймер/счетчик остановлен).
0 0 1 clkI/O (без делителя частоты)
0 1 0 clkI/O / 8 (с выхода делителя)
0 1 1 clkI/O / 64 (с выхода делителя)
1 0 0 clkI/O / 256 (с выхода делителя)
1 0 1 clkI/O / 1024 (с выхода делителя)
1 1 0 Внешний тактовый сигнал, поданный на вход T1. Тактирование происходит по срезу (спаду) уровня сигнала.
1 1 1 Внешний тактовый сигнал, поданный на вход T1. Тактирование происходит по фронту (нарастанию) уровня сигнала.

Для подсчета импульсов на входе T1 можно выбрать последние 2 варианта в таблице. Если для подсчета выбрана ножка T1, Импульсы будут подсчитываться даже тогда, когда порт T1 настроен как выход. Эта возможность позволяет программно управлять счетом.

ICR1H и ICR1L – Input Capture Register 1

Эти два регистра составляют 16-битный регистр ICR1. Событие захвата по входу (Input Capture, на выводе ICP1 или опционально на выходе аналогового компаратора) вызывает обновление содержимого ICR1 содержимым счетчика (TCNT1). Регистр ICP1 16-битный, поэтому к нему также применяется правило атомарного доступа, как и к другим 16-битным регистрам (см. [1]).

Когда ICR1 используется как значение TOP (см. описание битов WGM13:0, размещенных в регистрах TCCR1A и TCCR1B), вывод ICP1 будет отключен, и следовательно функция захвата Input Capture будет запрещена.

TCNT1H и TCNT1L – Timer/Counter1

Эти два регистра, размещенные в пространстве I/O, совместно образуют 16-битный регистр TCNT1, и предоставляют прямой доступ к содержимому счетчика. Для того, чтобы удостовериться в том, что старший и младший байты будут прочитаны одновременно при доступе CPU к этим регистрам, доступ выполняется с использованием временного 8-битного регистра для старшего байта, High Byte Register (TEMP). Этот регистр является общим для доступа ко всем 16-битным регистрам таймера (подробнее см. [1]).

TIMSK – Timer/Counter Interrupt Mask Register

• Bit 5 – TICIE1: Timer/Counter1, Input Capture Interrupt Enable. Когда этот бит установлен в 1, и установлен флаг I в регистре статуса SREG (прерывания разрешены глобально), то разрешено прерывание захвата таймера/счетчика 1 (Timer/Counter1 Input Capture Interrupt). При срабатывании прерывания (когда произошло событие захвата и установился флаг ICF1 в регистре TIFR) будет вызвана подпрограмма обработчика по соответствующему вектору (см. раздел «Interrupts» даташита).

• Bit 2 – TOIE1: Timer/Counter1, Overflow Interrupt Enable. Когда этот бит установлен в 1, и установлен флаг I в регистре статуса SREG (прерывания разрешены глобально), то разрешено прерывание переполнения таймера/счетчика 1 (Timer/Counter1 Overflow Interrupt). При срабатывании прерывания (когда произошло переполнение и установился флаг TOV1 в регистре TIFR) будет вызвана подпрограмма обработчика по соответствующему вектору (см. раздел «Interrupts» даташита).

TIFR – Timer/Counter Interrupt Flag Register

Примечание: TIFR содержит биты, относящиеся к нескольким таймерам/счетчикам (не только к Timer/Counter1), но здесь рассмотрены только те биты, которые нас интересуют — ICF1 и TOV1.

• Bit 5 – ICF1: Timer/Counter1, Input Capture Flag. Этот флаг устанавливается, когда произошло событие захвата на выводе ICP1. ICF1 автоматически очищается, когда вызывается обработчик прерывания по вектору Input Capture Interrupt. Альтернативно ICF1 может быть очищен записью в этот бит лог. 1.

• Bit 2 – TOV1: Timer/Counter1, Overflow Flag. Установка этого флага зависит от установки битов WGM13:10. В режимах нормального счета и при очистке таймера на сравнении (Clear Timer on Compare, CTC) флаг TOV1 будет установлен, когда таймер переполнится. Обратитесь к таблице «Waveform Generation Mode Bit Description» для определения поведения флага TOV1 в других режимах установки бит WGM13:10. TOV1 автоматически очищается, когда вызывается обработчик прерывания по вектору Input Capture Interrupt. Альтернативно TOV1 может быть очищен записью в этот бит лог. 1.

Источник

ОБОРУДОВАНИЕ
ТЕХНОЛОГИИ
РАЗРАБОТКИ

Блог технической поддержки моих разработок

Урок 16. Таймеры STM32 в режиме счетчиков. Генерация циклических прерываний от таймеров.

В уроке познакомимся с таймерами микроконтроллера, научимся конфигурировать их в режиме счетчика и организовывать циклические прерывания.

В предыдущем уроке я рассказывал о выполнении задач параллельными процессами. Для реализации такого способа необходимо формировать циклические прерывания с заданным периодом. Опять же в предыдущем уроке было сказано, что логичнее и проще это делать с помощью аппаратных таймеров.

В этом уроке мы будем рассматривать таймеры в качестве именно такого функционального применения. Т.е. будем использовать их для генерации циклических прерываний.

Таймеры STM32.

У нашего микроконтроллера STM32F103C8T6 есть 4 таймера:

  • TIM1 – расширенный таймер, ориентированный на управление электродвигателем.
  • TIM2 … TIM4 – таймеры общего назначения.

Все таймеры имеют одинаковую архитектуру. Расширенный таймер отличается наличием дополнительных аппаратных узлов для формирования противофазных сигналов ШИМ. В результате его можно конфигурировать на работу в режиме 6-канального ШИМ и управлять им тремя полумостовыми усилителями мощности.

Но сейчас нас это не интересует. Для нашей задачи — формирования циклических прерываний, все таймеры имеют одинаковую архитектуру.

Таймеры STM32 — многофункциональные устройства. С помощью каждого из них можно реализовать:

  • Счетчик импульсов, а значит и времени с автоматической перезагрузкой.
  • Захват входного сигнала (4 канала).
    • Обнаружение фронта входного сигнала, запоминание времени, генерация события.
    • Измерение временных параметров входного ШИМ-сигнала: периода и длительности импульсов.
    • Интерфейс энкодера. Измерение параметров импульсов энкодера.
  • Сравнение кодов таймера (4 канала).
    • Генерация события по совпадению кода таймера с заданным значением.
    • Формирование ШИМ-сигнала.
    • Формирование одиночных импульсов, режим одновибратора.

У таймеров большой выбор источников тактирования, есть предделители, обеспечивается цифровая фильтрация входных сигналов, возможна синхронизация между собой и много еще чего.

Но сейчас нас интересует исключительно режим счетчика с перезагрузкой. Именно в этом режиме удобнее всего формировать циклические прерывания.

Функциональная схема таймера достаточно сложная. Я выделил только необходимую нам часть.

Собственно отсчет импульсов или времени происходит на 16-ти разрядном счетчике CNT. Когда код счетчика достигает значения регистра перезагрузки, счетчик сбрасывается в 0. Таким образом, счетчик считает по циклу от 0 до значения регистра перезагрузки.

Частота сигнала тактирования таймера может быть уменьшена с помощью 16-ти разрядного предделителя PSC.

Перезагрузка счетчика формирует событие (прерывание). Частота его появления также может быть уменьшена счетчиком повторов (8 разрядов). Коэффициент деления задается в регистре повторов.

Код счетчика используется другими узлами таймера, например, для формирования ШИМ. Но об этом в других уроках.

В качестве источника тактирования могут быть выбраны:

  • Внутренние синхросигналы шин APB1 иAPB2, про которые мы говорили в уроке 5 (система тактирования микроконтроллера).
    • Для таймера TIM1 используется синхросигнал шины APB2;
    • Для таймеровTIM2- TIM4 используется синхросигнал шины APB1.
  • Внешнее тактирование, режим 1. Используется выходной сигнал другого таймера или внешний сигнал входов захвата.
  • Внешнее тактирование, режим 2. Используется вывод микроконтроллера ETR.
  • Особый режим синхронизации – интерфейс подключения энкодера.

Сейчас мы будем использовать только внутренний источник тактирования.

Режимы счета таймера.

При использовании таймера в качестве счетчика импульсов можно выбрать один из режимов:

  • прямой счет;
  • обратный счет;
  • двунаправленный.

При прямом счете содержимое счетчика с каждым импульсом тактирования увеличивается на 1. Когда оно достигает значения регистра перезагрузки, то счетчик сбрасывается. Таким образом,таймер считает по циклу от 0 до значения перезагрузки. В момент перезагрузки формируется прерывание.

В режиме обратного (реверсивного) счета с каждым входным импульсом содержимое счетчика уменьшается на 1. При достижении 0 в счетчик загружается значение регистра перезагрузки и реверсивный счет продолжается. Таймер считает по циклу от значения перезагрузки до 0. В момент перезагрузки формируется прерывание.

Двунаправленный режим означает, что счетчик считает в прямом направлении от 0 до значения перезагрузки, а затем переходит в реверсивный режим и счет ведется до 0. При изменении направления счета и сбросе генерируется прерывание.

Установка конфигурации таймера с помощью STM32CubeMX.

Давайте научимся конфигурировать таймеры через STM32CubeMX. Заодно в строгой форме перечислим регистры, задающие режимы таймера и выясним, что конкретно в них загружать.

Создадим проект Lesson16_1. Настроим конфигурацию системы тактирования. Обратим внимание на то, что частота тактирования таймеров на шинах APB1 и APB2 задана 72 мГц.

  • PC13 – активный выход;
  • PB13 – активный выход;
  • PB12 – вход с подтягивающим резистором.

Теперь будем конфигурировать таймер 1. В нашем микроконтроллере он самый многофункциональный.

Открываем вкладку Timers ->TIM1.

Выбираем в качестве источника тактирования внутреннее тактирование: Clock Source -> Internal Clock.

Ниже появилось поле Parameter Settings.

Давайте подробно разберем, что в нем.

Prescaler (PSC).

Это регистр предделителя. Предделитель делит частоту тактирования таймера, поступающую на основной счетчик. По сути, он, вместе с входной частотой, определяет разрешающую способность таймера.

Счетчик предделителя считает входные импульсы от 0 до значения этого регистра. При равенстве кода счетчика и регистра счетчик сбрасывается и начинает считать заново. В момент сброса формируется импульс тактирования основного счетчика таймера. Таким образом, значение регистра предделителя определяет коэффициент деления частоты входного сигнала.

Счетчик и регистр предделителя 16-ти разрядные. Т.е. максимальный коэффициент деления 65536.

Надо помнить, что реальный коэффициент деления на 1 больше, чем значение регистра предделителя. Например:

Значение регистра предделителя Коэффициент деления
0 1
999 1000
65535 (максимальное значение) 65536

Регистр предделителя имеет буферный регистр. Поэтому его значение можно устанавливать в любой момент. Реальное изменение коэффициента деления произойдет при перезагрузке буферного регистра в момент перезагрузки основного счетчика таймера.

Counter mode.

Режим счетчика, определяет в какую сторону считать.

  • Up – прямой счет.
  • Down – реверсивный счет.
  • Center Aligned mode 1 – двунаправленный счет, прерывание генерируется в момент, когда счетчик считает в обратную сторону и доходит до 0.
  • Center Aligned mode 2 – двунаправленный счет, прерывание генерируется, когда счетчик считает в прямом направлении и достигает значения перезагрузки.
  • Center Aligned mode 3 – двунаправленный счет, прерывание генерируется, в обоих случаях — при достижении 0 и значения перезагрузки.

Counter Period (Auto Reload Register).

Регистр перезагрузки. Его значение задает период работы таймера. Конечно, на время периода влияет еще режим счета.

Счетчик 16-ти разрядный. Значит, для однонаправленного счета период может длиться от 1 до 65536 длительностей импульсов предделителя. Реальная длительность периода на 1 больше значения регистра перезагрузки. Все как для регистра предделителя.

Internal Clock Division (CKD).

Делитель входной частоты для внутренних нужд таймера.

Частота используется при фильтрации внешних сигналов, формировании “мертвого времени” ШИМ и т.п. Сейчас это нам не интересно.

Repetition Counter (RCR).

Регистр счетчика повторов. Присутствует не во всех таймерах. Счетчик повторов считает импульсы событий на выходе таймера и при достижении значения регистра повторов сбрасывается и формирует реальное событие. Т.е. он делит частоту генерации событий (прерываний) таймера.

Счетчик 8-ми разрядный. Коэффициент деления на 1 больше значения регистра повторов и может быть в диапазоне 1 — 256. Регистр буферизирован, можно изменять его значения в любой момент.

Auto-reload preload.

Регистр перезагрузки буферизирован. Разработчики микроконтроллера предоставляют программисту выбор — при записи значения перезагрузки передавать его в регистр моментально или дождаться крайнего состояния счетчика.

Управляет режимом перезагрузки специальный бит, а в STM32CubeMX выбор делается в выпадающем меню.

Вкладка NVIC Settings позволяет выбрать нужный тип прерывания, связанного с таймером.

Пример конфигурации таймера и реализации программы.

Сделаем практическую задачу. Установим конфигурацию таймера 1, обеспечивающую циклические прерывания с периодом 0,5 секунд. В обработчике прерывания будем инвертировать состояние светодиода. В результате получим мигающий светодиод, но с использованием таймера и прерывания.

Частота тактирования у нас 72 мГц. Превратим ее с помощью предделителя в круглое значение.

Например, если задать 720 – 1 = 719, то частота после предделителя будет 72 000 000 / 720 = 100 000 Гц, или период 10 мкс.

Если в регистр перезагрузки задать значение 50 000, то получим требуемый период 0,5 секунд.

Во вкладке NVIC Settings выберем прерывание по перезагрузке счетчика.

Создаем проект и открываем его в Atollic TrueStudio.

В папке Src проекта создан файл stm32f1xx_it.c. Он существовал и во всех предыдущих проектах. Просто мы на него до времени не обращали внимания.

Это файл обработчиков прерываний. Хороший стиль размещать функции обработки прерываний в нем.

В самом конце файла появилась функция:

void TIM1_UP_IRQHandler(void) <

/* USER CODE BEGIN TIM1_UP_IRQn 0 */
/* USER CODE END TIM1_UP_IRQn 0 */

/* USER CODE BEGIN TIM1_UP_IRQn 1 */
/* USER CODE END TIM1_UP_IRQn 1 */
>

Это и есть обработчик прерывания таймера 1. Код, который мы поместим в функцию, будет вызываться с периодом 0,5 секунд.

Вызовем в обработчике прерывания функции инверсии состояния для обоих светодиодов.

void TIM1_UP_IRQHandler(void) <

/* USER CODE BEGIN TIM1_UP_IRQn 0 */

HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_13);

Мы установили конфигурацию таймера, но не запустили его. Сделаем это HAL-функцией в файле main.c.

/* Initialize all configured peripherals */

/* USER CODE BEGIN 2 */

HAL_TIM_Base_Start_IT(&htim1); // запуск таймера

Функция запускает таймер в режиме генерации прерываний.

Все. Компилируем, загружаем, проверяем. Оба светодиода мигают раз в секунду.

Полностью проект можно загрузить по ссылке:

Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта!

Основной цикл у нас пустой. Программа просто крутится в нем.

while (1) <

/* USER CODE END WHILE */

По отношению к нему светодиоды мигают в фоновом режиме, сами по себе. Если мы будем выполнять в цикле какие-либо действия, это никак не скажется на равномерном мигании светодиодов. Единственное условие – надолго не запрещать прерывания.

В следующем уроке будем разрабатывать программу, обрабатывающую сигнал кнопки параллельным процессом. Научимся связывать переменные разных файлов одной программы. Разберемся в специфике использования функций обработки прерываний.

Источник

Поделиться с друзьями
Моя стройка
Adblock
detector