[Home] [Donate!] [Контакты]

Функции таймера TIM1 и примеры использования

Оглавление
Таймер TIM1 с расширенным управлением (общие сведения)
Устройство таймера TIM1
Устройство каналов таймера. Защитное отключение выходов
Функции таймера TIM1 и примеры использования
Подготовка таймера
Времязадающий блок таймера
Режимы работы счётчика
Событие обновления и счётчик циклов
Выбор источника тактового сигнала для счётчика таймера
Продолжение следует...
Регистры таймера TIM1
Смотрите также
Частотомер на основе микроконтроллера STM32. Конвейерный принцип измерения частоты

Подготовка таймера

Прежде всего, чтобы получить возможность работать с таймером, требуется включить для него тактовый сигнал. Таймер подключён к шине APB2, так что его тактирование включается с помощью регистра RCC_APB2ENR, бит TIM1EN. Не забываем, что если используется понижение тактовой частоты шины с помощью её предделителя (возможные коэффициенты деления 2, 4, 8, 16), то в отличие от других периферийных устройств, таймер будет тактироваться с вдвое большей частотой. Однако, по умолчанию предделитель не используется (коэффициент равен 1) и частота тактирования таймера равна частоте шины, которая, в свою очередь, по умолчанию равна частоте ядра.

    // Пример %smpl:clk_on.
    // Включаем тактирование таймера.
    RCC->APB2ENR|=RCC_APB2ENR_TIM1EN;

Если планируется обрабатывать прерывания от таймера, следует также настроить NVIC: задать уровень приоритета прерываний и разрешить их. Как обычно, для того, чтобы прерывания генерировались и обрабатывались, они должны быть разрешены как на уровне NVIC, так и на уровне периферийного устройства. В случае таймера TIM1, генерация прерываний и запросов DMA разрешается с помощью регистра TIM1_DIER. В устройствах STM32F10x Medium Density Value Line (например, STM32F100RB) для таймера TIM1 выделено 4 прерывания:
TIM1_BRK_TIM15_IRQ,
TIM1_UP_TIM16_IRQ,
TIM1_TRG_COM_TIM17_IRQ,
TIM1_CC_IRQ
(имена обработчиков: TIM1_BRK_TIM15_IRQHandler и т.д.). Как видим, только TIM1_CC_IRQ используется таймером TIM1 монопольно, остальные используются совместно с другими устройствами. Это не вызывает трудностей, но данный факт следует иметь в виду.

Таймер TIM1 - таймер с большим набором возможностей, и если используется он, а не более простой, то, скорее всего, потребуется задействовать некоторые выводы таймера для ввода/вывода сигналов. В этом случае следует сконфигурировать используемые таймером выводы GPIO. Если вывод используется как выход, он должен быть обязательно настроен для выполнения альтернативной функции (alt. push-pull или alt. open drain). Если используется как вход, то и настроен данный вывод GPIO должен быть как вход - плавающий или с подтягивающим резистором (но, естественно, не аналоговый). Интересно, что вход периферийного устройства будет получать сигнал и в том случае, если соответствующий вывод микроконтроллера настроен как выход. В некоторых случаях этот приём может быть полезным.

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

/**
*  Пример %smpl:prep.
*  Фрагмент кода, выполняющего подготовку к работе с таймером TIM1;
*  предполагается обработка прерывания TIM1_UP_TIM16_IRQ.
*/

#include "stm32f10x.h"

// Обработчик прерывания.
extern "C" void TIM1_UP_TIM16_IRQHandler()
{
    // Этот обработчик может обслуживать разные прерывания, поэтому,
    // сначала выясняем причину прерывания, затем выполняем
    // соответствующий ситуации код.
    if(TIM1->SR&TIM_SR_UIF)
    {
        // Сбрасываем флаг записью 0, те биты регистра SR, в которые
        // запишем 1, не изменятся.
        TIM1->SR=~TIM_SR_UIF;

        // Выполняем действия...
    }
}

int main()
{
    // ... где-то в недрах функции main, перед использованием таймера...

    // Чтобы получить возможность обрабатывать прерывание, требуется
    // настроить NVIC, как минимум, задав приоритет и разрешив
    // обработку этого прерывания.
    // Функция NVIC_SetPriority принимает в качестве второго аргумента
    // значение приоритета - число от 0 (высший приоритет) до
    // (1<<__NVIC_PRIO_BITS)-1 (низший приоритет).

    uint32_t priority=(1<<__NVIC_PRIO_BITS)-1; // низший приоритет

    // Задаём приоритет.
    NVIC_SetPriority(TIM1_BRK_TIM15_IRQn, priority);
    // Разрешаем прерывание.
    NVIC_EnableIRQ(TIM1_BRK_TIM15_IRQn);

    // Включаем тактирование таймера.
    RCC->APB2ENR|=RCC_APB2ENR_TIM1EN;
    
    // Далее выполняем конфигурирование таймера и прочие полезные действия.
    // .....

    // Чтобы обрабатывать прерывания от таймера, нужно разрешить их
    // генерацию; здесь разрешаем генерацию прерывания при
    // событиях обновления.
    TIM1->DIER|=TIM_DIER_UIE;

    // .....
}

Времязадающий блок таймера

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

Времязадающий блок таймера.
Рис. %img:tbu

Кратко рассмотрим функционирование данного блока таймера, а кроме того, поясним назначение некоторых битов в регистре управления TIMx_CR1 (TIM1 control register 1):
CEN - разрешение счёта (значение 1 разрешает счёт);
UDIS - запрет обновления буферизируемых регистров (значение 1 запрещает обновление);
URS - источник событий обновления (0 - любой: переполнение счётчика, установка бита UG, сигнал от контроллера подчинённого режима; 1 - только переполнение);
OPM - режим одиночного импульса (значение 1 включает режим);
DIR - направление счёта (0 - счёт вверх, 1 - счёт вниз); в некоторых режимах этот бит доступен только для чтения и информирует о направлении счёта в текущий момент);
CMS[1:0] - выбор выравнивания по краю или одного из режимов с выравниванием по центру (0 - обычный режим, направление счёта задаём с помощью бита DIR; 1..3 - режимы с выравниванием по центру, направление счёта автоматически переключается);
ARPE - включение буферизации регистра TIMx_ARR (значение 1 включает буферизацию).

Счётчик в таймере TIM1 может выполнять суммирующий, вычитающий счёт или счёт с автоматическим реверсом, в зависимости от используемых настроек. Если в регистре TIMx_CR1 битовое поле CMS[1:0] содержит 0, то направление счёта определяется битом DIR этого же регистра TIMx_CR1: при DIR=0 происходит счёт вверх, при DIR=1 - счёт вниз. Если выбран режим с выравниванием по центру (CMS[1:0] содержит любое ненулевое значение), то направление счёта изменяется автоматически на противоположное всякий раз, когда счётчик достигает одного из крайних значений. Бит DIR в таком случае недоступен для записи, а доступен только для чтения и содержит значение, показывающее направление счёта в данный момент.

Для запуска счёта требуется установить в 1 бит CEN (counter enable bit) в регистре TIMx_CR1. Счёт начинается спустя 1 такт после установки бита CEN. При работе таймера в подчинённом режиме с запуском входным триггерным сигналом, бит CEN устанавливается аппаратно. Для остановки счётчика необходимо сбросить бит CEN. В режиме одиночного импульса сброс бита CEN происходит аппаратно, в момент ближайшего события обновления (режим одиночного импульса включается установкой в 1 бита OPM в регистре TIMx_CR1).

Имеется большое количество вариантов для выбора источника сигнала, используемого в качестве тактового для счётчика таймера. Путём соответствующего конфигурирования таймера могут быть выбраны как внешние, так и внутренние сигналы. Выбранный сигнал после предобработки (смотрите далее) поступает на вход предделителя (сигнал CK_PSC) с программируемым коэффициентом деления частоты. Этот предделитель построен на базе 16-битового счётчика, что обеспечивает возможность выбора коэффициента деления в диапазоне 1..65536. Выход предделителя (сигнал CK_CNT) подключается ко входу счётчика таймера.

Регистр автоматической перезагрузки TIMx_ARR определяет максимальное значение, до которого осуществляется счёт в суммирующем режиме работы счётчика, после чего происходит переполнение и сброс счётчика в нулевое значение. В вычитающем режиме работы счётчика, значение из регистра автоматической перезагрузки используется в качестве начального, оно загружается в счётчик после антипереполнения (когда приходит следующий подсчитываемый импульс при нулевом значении счётчика). Как видим, в любом случае TIMx_ARR задаёт наибольшее значение, которое может содержать счётчик. Если не брать в расчёт особые случаи, например, когда намеренно записываем в TIMx_CNT значение, большее TIMx_ARR, либо записываем значение в TIMx_ARR, при отключённой буферизации регистра, меньшее, чем содержится в TIMx_CNT в данный момент.

Если значение в регистре TIMx_RCR отлично от 0, то значение счётчика циклов уменьшается на 1 при каждом переполнении/антипереполнении счётчика таймера. Если счётчик циклов содержит 0, то очередное переполнение/антипереполнение таймера приведёт к инициализации счётчика циклов начальным значением из его регистра автоперезагрузки TIMx_RCR и генерации события обновления. Теперь несколько слов об обновлении регистров в таймере.

Некоторые из регистров таймера являются регистрами с предзагрузкой или, иначе говоря, буферизируемыми (из рассмотренных в этом пункте - это TIMx_PSC, TIMx_ARR). Это означает, что каждый из этих регистров на самом деле является связкой из двух взаимодействующих регистров. Один из них буферный, именно он является доступным программно, т.е. с ним взаимодействует программа, выполняя операции чтения и записи. Другой регистр называют активным, так как именно записанное в него значение управляет функционированием таймера; ещё его иногда называют "теневым" регистром, это название отражает программную недоступность данного регистра - с этой точки зрения он является "тенью" своего буфера, и доступ к нему из программы происходит через буфер. На блок-схемах будем изображать регистры с предзагрузкой в виде прямоугольников с тенью (или с серым фоном), что будет символизировать наличие теневого регистра.

Буферизацией некоторых регистров с предзагрузкой можно управлять (из регистров времязадающего блока - это TIMx_ARR; как увидим далее, это относится и к регистрам захвата/сравнения в каналах таймера). Для управления буферизацией TIMx_ARR служит бит ARPE в регистре TIMx_CR1: при нулевом значении бита предзагрузка не используется и записываемое в регистр значение сразу передаётся в активный (теневой) регистр; при единичном значении бита предзагрузка используется и записываемое в регистр значение попадает сначала в буферный регистр, а передача значения в активный (теневой) регистр происходит тогда, когда наступает событие обновления. Для других регистров с предзагрузкой, например, для TIMx_PSC, не предусмотрено отключение буферизации, но имеются некоторые возможности по управлению обновлением их теневых регистров. Можно запретить на некоторое время обновление, установив в 1 бит UDIS в регистре TIMx_CR1. Можно наоборот, принудительно обновить регистры, программно сгенерировав событие обновления записью 1 в бит UG регистра TIMx_EGR.

Режимы работы счётчика

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

Если используется счётчик циклов, событие обновления (UEV) генерируется после того, как количество переполнений достигнет заданного в регистре TIMx_RCR (repetition counter register) значения. Если не используется - событие обновления генерируется при каждом переполнении счётчика.

Событие обновления также генерируется при записи 1 в бит UG регистра TIMx_EGR, что может быть выполнено программно или при работе таймера в подчинённом режиме.

Генерация события обновления может быть программно отключена путём установки бита UDIS в регистре TIMx_CR1. Это позволяет избежать обновления теневых регистров до полного завершения записи новых значений в буферизируемые регистры (в процессе конфигурирования таймера во время счёта). После того, как бит UDIS будет сброшен, очередное событие UEV приведёт к обновлению содержимого теневых регистров. Кроме того, обновление можно инициировать программно записью 1 в бит UG регистра TIMx_EGR (но при этом будет также сброшен счётчик).

Когда происходит событие обновления, не только обновляются теневые регистры, но и устанавливается флаг обновления (бит UIF в регистре TIMx_SR). В зависимости от заданных настроек таймера, при этом может происходить генерация прерывания или выполнение запроса DMA. Если при этом был установлен бит URS в регистре TIMx_CR1, то установка бита UIF будет происходить только в ответ на "аппаратные" события обновления и UIF не будет устанавливаться при программной генерации события обновления с помощью бита UG.

// Пример %smpl:up. Включение таймера, счёт вверх.
// Предполагаем, что изначально регистры таймера содержат значения по умолчанию.

// Тактовая частота шины 24 МГц, устанавливаем частоту тактового
// сигнала счётчика 1000 Гц (делитель 24000).
TIM1->PSC=24000-1;
// Задаём частоту событий обновления (переполнений счётчика) равной 1 Гц.
TIM1->ARR=1000-1;
// Для обновления буферизируемого регистра PSC (а также ARR, если бы
// его буферизация была включена, т.е. CR1.ARPE==1), выполняем:
TIM1->EGR=TIM_EGR_UG;
// Программная генерация события обновления в данном случае (при CR1.URS==0)
// устанавливает флаг SR.UIF; сбрасываем его, если обрабатываем
// прерывание по флагу и не хотим получить одного "лишнего" прерывания.
TIM1->SR=~TIM_SR_UIF;

// Разрешаем счёт.
TIM1->CR1=TIM_CR1_CEN;

Счёт вверх хорошо подходит при использовании таймера для измерения времени. В этом случае TIMx_CNT в любой момент будет содержать значение - количество тактов тактового сигнала счётчика с момента последнего переполнения. Также этот режим удобен, когда таймер используется просто как счётчик импульсов некоторого сигнала (этот сигнал должен быть выбран в качестве тактового сигнала счётчика).

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

Если счётчик повторений не используется, при каждом антипереполнении счётчика происходит генерация события обновления (UEV), а если используется, то UEV генерируется только после того, как количество антипереполнений достигнет значения, заданного в регистре TIMx_RCR.

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

При этом генерацию событий UEV можно временно отключить установкой бита UDIS в регистре TIMx_CR1. Наступление события UEV сопровождается установкой бита UIF в регистре TIMx_SR, что может приводить к генерации прерывания или запроса DMA при соответствующей настройке таймера. Установив бит URS в регистре TIMx_CR1, можно отключить установку бита UIF при генерации события обновления с помощью бита UG (тогда UIF будет устанавливаться только в ответ на те события обновления, которые были вызваны переполнениями счётчика).

После возникновения события UEV происходит обновления теневых регистров.

// Пример %smpl:down. Включение таймера, счёт вниз.
// Предполагаем, что изначально регистры таймера содержат значения по умолчанию.

// Тактовая частота шины 24 МГц, устанавливаем частоту тактового
// сигнала счётчика 1000 Гц (делитель 24000).
TIM1->PSC=24000-1;
// Для обновления буферизируемого регистра PSC выполняем:
TIM1->EGR=TIM_EGR_UG;
// Программная генерация события обновления в данном случае (при CR1.URS==0)
// устанавливает флаг SR.UIF; сбрасываем его, если обрабатываем
// прерывание по флагу и не хотим получить одного "лишнего" прерывания.
TIM1->SR=~TIM_SR_UIF;

// Записываем в счётчик начальное значение
// (здесь для срабатывания таймера через 10000 мс).
TIM1->CNT=10000-1;

// Выбираем режим одиночного импульса, счёт вниз, разрешаем счёт.
TIM1->CR1=
        TIM_CR1_DIR|    // счёт вниз
        TIM_CR1_OPM|    // одиночный импульс
        TIM_CR1_CEN;    // разрешаем счёт

// Через заданное время: генерируется прерывание, счёт останавливается
// (значение счётчика равно значению в ARR, в нашем случае 0xFFFF). 

Как видно из этого простого примера, счёт вниз удобен, например, в случае, когда требуется сформировать интервал времени заданной длительности. В этом режиме достаточно записать в счётчик длительность интервала в тактах тактового сигнала счётчика и разрешить счёт.

Реверсивный счёт (режим с выравниванием по центру). В данном режиме происходит счёт сначала от 0 до (значение в регистре TIMx_ARR)-1, после чего происходит переполнение счётчика и счёт возобновляется от значения TIMx_ARR до 1, после чего возникает антипереполнение и счёт возобновляется, начиная с 0.

Данный режим работы активируется в том случае, если битовое поле CMS в регистре TIMx_CR1 имеет отличное от '00' значение. При этом, срабатывание схемы сравнения и установка флага прерывания по сравнению (в каналах, настроенных в режим выхода) происходит:
во время счёта вниз (режим с выравниванием по центру 1, CMS='01');
во время счёта вверх (режим с выравниванием по центру 2, CMS='10');
во время счёта как вверх, так и вниз (режим с выравниванием по центру 3, CMS='11').

В данном режиме невозможна запись в бит направления счёта DIR в регистре TIMx_CR1. Значение бита устанавливается аппаратно и содержит текущее направление счёта счётчика таймера.

Режим используется преимущественно при генерации PWM сигналов. Этот вопрос рассмотрим немного позже.

Событие обновления и счётчик циклов

Событие обновления возникает при каждом переполнении/антипереполнении, если счётчик циклов в этот момент имеет нулевое значение или независимо от значения счётчика циклов при записи 1 в бит UG регистра TIMx_EGR (что может быть выполнено программно или аппаратно при работе в подчинённом режиме). Событие обновления сбрасывает счётчик таймера, счётчик предделителя, счётчик циклов. Значение в счётчике таймера после сброса зависит от текущего направления счёта: 0 при счёте вверх или TIMx_ARR при счёте вниз. В счётчик циклов при сбросе загружается значение TIMx_RCR.

Можно программно отключить генерацию события обновления установкой бита UDIS в регистре TIMx_CR1. Это используется при необходимости модифицировать сразу несколько буферизируемых регистров в процессе работы таймера - установка бита позволяет избежать обновления теневых регистров до окончания записи новых значений в буферные регистры, и гарантирует корректность конфигурации таймера в любой момент времени. Таймер продолжает работу, используя значения теневых регистров, в частности, счётчик использует прежнее значение автоперезагрузки. После завершения модификации буферизируемых регистров можно снова разрешить события обновления, записав 0 в бит UDIS. После ближайшего события обновления, теневые регистры будут обновлены. Принудительное обновление установкой бита UG сбрасывает счётчик, поэтому подходит не во всех случаях. Этого следует избегать, например, если таймер используется для генерации PWM сигнала.

Следует добавить, что если установлен бит URS в регистре TIMx_CR1, то установка бита UG будет приводить к возникновению события обновления UEV, но флаг UIF не будет устанавливаться (так что не будет происходить генерации прерывания или формирования запроса DMA). Это позволяет избежать генерирования одновременно прерываний обновления и захвата, когда происходит обнуление счётчика при возникновении события захвата.

Когда происходит событие обновления, буферизируемые регистры обновляются и устанавливается флаг UIF в регистре TIMx_SR (если мы не установили в 1 бит URS):

Событие обновления генерируется при переполнении счётчика таймера только тогда, когда счётчик циклов достиг нулевого значения. Поэтому, с помощью регистра TIMx_RCR можно уменьшить частоту генерации событий обновления. Счётчик циклов декрементируется при каждом переполнении/антипереполнении счётчика таймера (в любом режиме счёта: при счёте вверх, вниз и при реверсивном счёте). С учётом сказанного, данные передаются из регистров с предзагрузкой в теневые (TIMx_ARR, TIMx_PSC, TIMx_CCRx) каждые N переполнений счётчика таймера, где N=TIMx_RCR+1. Это может быть полезно при генерации сигналов с ШИМ.

Выбор источника тактового сигнала для счётчика таймера

Выше было рассмотрено несколько простых примеров работы с таймером. В каждом из них для счётчика использовался тактовый сигнал по умолчанию, т.е. тактовый сигнал самого таймера, получаемый с шины APB (APB2 в данном случае). В действительности, таймер TIM1 обеспечивает большую гибкость в выборе источнике тактового сигнала. На рисунке %img:clk_sel изображена схема, показывающая возможные варианты выбора тактового сигнала.

Источники тактового сигнала для счётчика таймера TIM1.
Рис. %img:clk_sel

Тактовым сигналом счётчика может быть:

За выбор источника тактового сигнала отвечает регистр TIMx_SMCR (TIM1 slave mode control register, регистр управления подчинённым режимом таймера) и прежде всего, биты:
SMS[2:0] (slave mode selection, выбор подчинённого режима);
TS[2:0] (trigger selection, выбор триггерного сигнала);
ECE (external clock enable, включение режима 2 внешнего тактового сигнала).

SMS=000: контроллер подчинённого режима отключён, тактовым сигналом счётчика будет внутренний тактовый сигнал CK_INT, при условии, что бит ECE=0. Или сигнал ETRF, если ECE=1 (внешний триггерный сигнал ETR после прохождения входных цепей выбора полярности, предделителя, ресинхронизации и цифровой фильтрации). Таймер будет управляться битами CEN, DIR (в регистре TIMx_CR1) и битом UG (в регистре TIMx_EGR), которые в этом случае могут быть изменены только программно, если не считать автоматического аппаратного сброса бита UG. Именно этот вариант (SMS=000, ECE=0) рассматривался в приведённых выше примерах.

SMS=001, 010, 011: режимы энкодера 1..3, счётчик управляется интерфейсом энкодера, который задаёт направление счёта и формирует подсчитываемые импульсы на основе сигналов, снимаемых с входов каналов 1 и 2 таймера. Таким образом, тактовый сигнал здесь - импульсы от энкодера.

SMS=100, 101, 110: подчинённые режимы (соответственно: режим сброса, стробирующий, триггерный). В режиме сброса под действием входного триггерного сигнала происходит сброс таймера. В стробирующем режиме счёт разрешён только при высоком уровне входного триггерного сигнала (если установлен бит CEN), а при низком уровне сигнала счёт останавливается. В триггерном режиме счёт запускается фронтом импульса входного триггерного сигнала; в отличие от стробирующего режима, переход сигнала к низкому уровню не останавливает счёт; в этом режиме не следует устанавливать бит CEN, он устанавливается аппаратно, для остановки счёта следует программно сбросить бит. Источник входного триггерного сигнала задаётся битами TS (об этом немного далее).

Используемый в этих режимах тактовый сигнал для счётчика - внутренний тактовый сигнал при ECE=0 или сигнал ETRF при ECE=1, т.е. как и в случае, когда SMS=000. Интересно, что сигнал ETRF может быть также и входным триггерным сигналом - при TS=111.

SMS=111: режим 1 внешнего тактового сигнала, счётчик тактируется нарастающими фронтами на выбранном триггерном входе (TRGI), источник сигнала для которого выбирается исходя из значения поля TS. Если для предыдущих трёх режимов (SMS=100, 101, 110), триггерный сигнал управлял сбросом или запуском счёта, то в данном режиме этот сигнал становится тактовым для счётчика.

ECE бит включает режим 2 внешнего тактового сигнала. Проще говоря, он позволяет делать выбор тактового сигнала счётчика в режимах SMS=000, 100, 101, 110. При ECE=0 используется внутренний тактовый сигнал (с шины), а при ECE=1 - сигнал ETRF, получаемый из сигнала на внешнем выводе ETR. Заметим, что сигнал ETRF в режимах SMS=100, 101, 110 может быть использоваться и как входной триггерный сигнал, если TS=111 (в этом случае он не должен использоваться как внешний тактовый сигнал, т.е. в указанных режимах при TS=111 должно быть ECE=0 - не следует включать режим 2 внешнего тактового сигнала). Режим 1 внешнего тактового сигнала, когда выбран сигнал ETRF (SMS=111, TS=111) сходен с режимом 2 (ECE=1) - в обоих случаях тактовым сигналом счётчика является ETRF. Однако, режим 2 даёт больше возможностей, так как одновременно с этим режимом может быть выбран один из подчинённых режимов (SMS=100, 101, 110), тогда мы получаем больший контроль над таймером с помощью внешних сигналов: один внешний сигнал (ETRF) будет тактовым сигналом счётчика, а другой будет сбрасывать счётчик (при SMS=100), разрешать счёт (при SMS=101) или запускать счёт (при SMS=110). С другой стороны, режим 1 даёт большую свободу в выборе используемого сигнала. Если одновременно включить режимы 1 и 2 внешнего тактового сигнала, тактовым сигналом счётчика будет ETRF.

Если тем или иным образом используется сигнал ETRF, то с помощью битов ETP, ETPS[1:0], ETF[3:0] можно настраивать преобразования над исходным сигналом на входе ETR, из которого ETRF формируется. Бит ETP задаёт полярность сигнала, если ETP=0, то входной сигнал не инвертируется, а если ETP=1 - инвертируется. Битовое поле ETPS управляет предделителем внешнего сигнала и позволяет установить коэффициенты деления частоты 1, 2, 4 или 8. Битовое поле ETF[3:0] используется для включения и настройки цифрового фильтра (подробнее - смотрите в описании регистров таймера, регистр TIMx_SMCR).

Важное преимущество входа ETR по сравнению с другими входами таймера состоит в том, что данный вход может использоваться для работы с более высокочастотными сигналами. Это объясняется особенностями схемотехники входных цепей: на других входах таймера сразу осуществляется ресинхронизация сигнала (что накладывает ограничение на максимальную частоту), а на входе ETR сигнал сначала проходит через асинхронный предделитель и только после этого подвергается ресинхронизации. При использовании предделителя, максимально допустимая частота на входе увеличивается. В соответствии с требованиями документации, частота на выходе предделителя не должна превышать 1/4 от тактовой частоты таймера, т.о., частота сигнала на входе ETR может достигать fTIMxCLK*N/4, где N - коэффициент деления частоты предделителя. При максимальном коэффициенте предделителя, равном 8 (ETPS=11), максимально допустимая частота на входе ETR составит 2*fTIMxCLK.

TS[2:0]: это битовое поле определяет источник сигнала, используемого как входной триггерный сигнал (режимы SMS=100, 101, 110) или как тактовый сигнал счётчика (режим SMS=111).

000: Internal Trigger 0 (ITR0) - внутренний триггерный сигнал 0; для TIM1 - TRGO (выходной триггерный сигнал) таймера TIM15 или TIM5, TIM5 может быть выбран средствами AFIO (бит MISC_REMAP в регистре AFIO_MAPR2) при наличии этого таймера в данном микроконтроллере.

001: Internal Trigger 1 (ITR1) - внутренний триггерный сигнал 1; для TIM1 - TRGO (выходной триггерный сигнал) таймера TIM2.

010: Internal Trigger 2 (ITR2) - внутренний триггерный сигнал 2; для TIM1 - TRGO (выходной триггерный сигнал) таймера TIM3.

011: Internal Trigger 3 (ITR3) - внутренний триггерный сигнал 3; для TIM1 - TRGO (выходной триггерный сигнал) таймера TIM4.

100: TI1 Edge Detector (TI1F_ED) - детектор фронта сигнала TI1; формирует импульс при обнаружении нарастания или спада сигнала на входе канала 1 таймера.

101: Filtered Timer Input 1 (TI1FP1) - сигнал TI1 (со входа канала 1 после цифрового фильтра, полярность сигнала задаётся настройками канала 1).

110: Filtered Timer Input 2 (TI2FP2) - сигнал TI2 (со входа канала 2 после цифрового фильтра, полярность сигнала задаётся настройками канала 2).

111: External Trigger input (ETRF) - сигнал ETRF, получаемый из сигнала внешнего триггерного входа.

Изменять TS следует, когда это битовое поле не используется (SMS=0), иначе при переключении возможно ошибочное обнаружение фронта сигнала.

Теперь простой пример: фрагмент кода для подсчёта импульсов на входе первого канала таймера (входу CH1 таймера TIM1 соответствует вывод PA8 микроконтроллера). Что нужно сделать:

  1. Выбрать полярность сигнала (бит CC1P регистра TIM1->CCER) и настроить цифровой фильтр (битовое поле IC1F[3:0] регистра TIM1->CCMR1). Если не нужно инвертировать входной сигнал и не нужен цифровой фильтр, оставляем нулевые значения по умолчанию.
  2. Выбрать режим 1 внешнего тактового сигнала (SMS=111 в регистре TIM1->SMCR).
  3. Выбрать вход TI1 в качестве источника сигнала (TS=101 в регистре TIM1->SMCR).
  4. Разрешить счёт (CEN=1 в регистре TIM1->CR1).

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

// Пример %smpl:clk1.

// Все биты сбрасываем в 0, кроме полей SMS, TS.
TIM1->SMCR=
        0x7|        // SMS=111; External Clock Mode 1.
        (0x5<<4);    // TS=101; выбираем TI1FP1 - тактовый сигнал счётчика.

// Все биты регистра сбрасываем в 0, кроме CEN=1;
// в частности, DIR=0 (счёт вверх).
TIM1->CR1=TIM_CR1_CEN;

// Теперь счётчик будет инкрементироваться по каждому переднему
// фронту сигнала TI1FP1, получаемого из TI1 - входного
// сигнала канала 1, который привязан к выводу PA8 микроконтроллера.
// .....

Заметим, что здесь нам не требуется ни конфигурирование канала, ни перевод его в режим входа, ни включение канала. Дело в том, что в данном случае мы не используем сам канал, а только лишь пользуемся его входом для получения сигнала с вывода микроконтроллера. То, что в приведённом выше примере канал настроен как выход (в регистре TIMx->CCMR1 битовое поле CC1S=0 - используется значение по умолчанию) ничуть не мешает работе входных цепей канала, которые и в этом случае получают сигнал с вывода микроконтроллера. Для корректной работы примера достаточно настроить порт ввода-вывода микроконтроллера таким образом, чтобы вывод PA8, соответствующий входу первого канала CH1 таймера был настроен как вход (плавающий или с подтягивающим резистором):

GPIOA->CRH=GPIOA->CRH&~0xF|0x4;

Единственное, что мы можем сделать с помощью настроек канала, это задать полярность сигнала и включить цифровой фильтр. Полярность задаётся с помощью регистра TIM1->CCER, бит CC1P для первого канала и бит CC2P для второго канала (бит сброшен - используется сам сигнал, бит установлен - используется инвертированный сигнал). Соответственно, если сигнал не инвертируются, счётчик будет срабатывать по переднему фронту входного сигнала, а если сигнал инвертируется - то по спаду сигнала. Для включения и настройки цифрового фильтра используется регистр TIM1->CCMR1, битовое поле IC1F[3:0] для первого канала, IC2F[3:0] для второго; при нулевом значении (значение после сброса) фильтр отключён.

Использование режима 2 внешнего тактового сигнала ещё проще - основные конфигурирующие биты для этого режима находятся в одном регистре TIM1->SMCR. В данном случае мы имеем возможность не только задать полярность сигнала, но и использовать предделитель (асинхронный), который включён перед схемами цифровой фильтрации и ресинхронизации. Порядок действий следующий:

  1. Настраиваем цифровой фильтр для сигнала (битовое поле ETF[3:0], если фильтр не нужен, задаём ETF=0).
  2. Выбираем коэффициент деления частоты для предделителя равным 1, 2, 4 или 8 (битовое поле ETPS[1:0], соответственно битовые значения 00, 01, 10, 11).
  3. При необходимости включаем инвертирование входного сигнала (для инвертирования следует установить бит ETP).
  4. Включаем режим 2 (устанавливаем в 1 бит ECE).
  5. Разрешаем счёт (в регистре TIM1->CR1 устанавливаем в 1 бит CEN).
// Пример %smpl:clk2.

// Устанавливаем бит ECE;
// ETP, ETPS, ETF и прочие биты сбрасываем
// (сигнал не инвертируем, предделитель и фильтр не используем).
TIM1->SMCR=TIM_SMCR_ECE;

// Разрешаем счёт (DIR=0 - счёт вверх).
TIM1->CR1=TIM_CR1_CEN;

// Теперь счётчик будет инкрементироваться по каждому переднему
// фронту внешнего триггерного сигнала ETR (вывод PA12 MCU).
// .....

Рассмотренные примеры являются простейшими, показывают различные варианты конфигурирования таймеров, но не создают целостной картины их использования, не демонстрируют реальных возможностей таймеров и различных техник работы с таймерами в реальных устройствах. Хорошим, сложным и практически полезным примером является реализация частотомера, например такого:
Частотомер на основе микроконтроллера STM32. Конвейерный принцип измерения частоты

Смотрите далее:
Регистры таймера TIM1

author: hamper; date: 2018-04-06
  Рейтинг@Mail.ru