Top.Mail.Ru

Stm32. Переходим на современный C++. Часть 8. Таймеры. Режим энкодера. Режимы Master/Slave.

Вступление.

В завершение изучения таймеров, в частности таймеров общего назначения, рассмотрим оставшийся без внимания блок - Trigger controller:

Таймер в режиме ведомого.

Таймеры также могут работать в режиме ведомого с реакцией на внешнее событие, задаваемой битами SMS регистра TIMx_SMCR:

  • 100 (Reset Mode): режим сброса, выбранный триггер сбрасывает счетчик;
  • 101 (Gated Mode): режима шлюза, счетчик включен только при высоком уровне сигнала триггера. При переходе его в низкий уровень счет останавливается, но счетчик не сбрасывается. При переходе триггерного сигнала обратно в высокий уровень счет возобновляется;
  • 110 (Trigger Mode): режим триггера, счет запускается по восходящему фронту триггерного сигнала (счетчик не сбрасывается, при переходе триггерного сигнала в низкий уровнеь ничего не происходит);
  • 111 (External Clock Mode 1): режим внешнего тактирования, триггерный сигнал управляет изменением счетчика.

Источником триггерного сигнала могут служить:

  • выходы TRGO других таймеров (мастер-таймеров), конкретные списки можно найти в Reference Manual;
  • внешняя линия ETR;
  • сигнал детектора фронта первого канала таймера;
  • сигналы 1 и 2 каналов таймера после фильтрации (TI1FP1 и TI2FP2).

Источник триггерного сигнала задается битами TS регистра TIMx_SMCR:

  • 000*: источником триггерного сигнала является внутренний триггер ITR0;
  • 001*: источником триггерного сигнала является внутренний триггер ITR1;
  • 010*: источником триггерного сигнала является внутренний триггер ITR2;
  • 011*: источником триггерного сигнала является внутренний триггер ITR3;
  • 100*: источником триггерного сигнала является детектор фронта первого канала TI1F_ED;
  • 101*: источником триггерного сигнала является фильтрованный сигнал первого канала TI1FP1;
  • 110*: источником триггерного сигнала является фильтрованный сигнал второго канала TI2FP2;
  • 111*: источником триггерного сигнала является внешний сигнал ETRF.

Библиотека Zhele и ведомый режим таймера.

Для тонкой настройки поведения таймера по внешнему событию класс таймера содержит вложенный класс SlaveMode, предоставляющий следующий интерфейс:

  • void EnableSlaveMode(Mode mode): активирует режим ведомого, Mode является перечислением со следующими возможными значениями:
    • SlaveModeDisabled - режим ведомого отключен;
    • EncoderMode1 - режим энкодера 1;
    • EncoderMode2 - режим энкодера 2;
    • EncoderMode3 - режим энкодера 3;
    • ResetMode - режим сброса счетчика;
    • GatedMode - режим шлюза;
    • TriggerMode - режим триггера;
    • ExternalClockMode - режим внешнего тактирования.
  • void DisableSlaveMode(): отключает режим ведомого (равносильно вызову предыдущего метода с аргументом SlaveModeDisabled;
  • void SelectTrigger(Trigger trigger): позволяет выбрать источник триггерного сигнала, Trigger является перечислением со следующими возможными значениями:
    • InternalTrigger0 - триггером является сигнал ITR0;
    • InternalTrigger1 - триггером является сигнал ITR1;
    • InternalTrigger2 - триггером является сигнал ITR2;
    • InternalTrigger3 - триггером является сигнал ITR3;
    • Ti1EdgeDetector - триггером является детектор фронта первого канала TI1F_ED;
    • FilteredTimerInput1 - триггером является сигнал TI1FP1;
    • FilteredTimerInput2 - триггером является сигнал TI2FP2;
    • FilteredTimerInput1 - триггером является внешний сигнал ETRF.
  • void SetTriggerPrescaler(ExternalTriggerPrescaler prescaler): устанавливает предделитель триггерного сигнала, ExternalTriggerPrescaler является перечислением со значениями, соответствующими значениям битов ETF регистра TIMx_SMCR, их описание можно найти в Reference Manual (слишком объемно, чтобы вставлять в статью).

Таймер в режиме ведущего.

Входные линии ITR0 ... ITR3 являются выходными для соответствующих мастер-таймеров. Работа таймера в режиме ведущего задается битами MMS регистра TIMx_CR2:

  • 000 (Reset): бит UG регистра TIMx_EGR используется как выход TRGO;
  • 001 (Enable): включение таймера (бит CNT_EN) используется как выход TRGO;
  • 010 (Update): событие обновления (переполнения) счетчика используется как выход TRGO, такой режим позволяет строить каскады из таймеров для подсчета больших промежутков;
  • 011 (Compare Pulse): флаг CC1IF используется как выход TRGO;
  • 100 (Compare 1): сигнал OC1REF (сравнение первого канала) используется как выход TRGO;
  • 101 (Compare 2): сигнал OC2REF (сравнение второго канала) используется как выход TRGO;
  • 110 (Compare 3): сигнал OC3REF (сравнение третьего канала) используется как выход TRGO;
  • 111 (Compare 4): сигнал OC4REF (сравнение четвертого канала) используется как выход TRGO;

Библиотека Zhele и ведущий режим таймера.

Поддержка режима ведущего таймера реализована в виде метода шаблона класса базового таймера void SetMasterMode(MasterMode mode), MasterMode является перечислением со следующими возможными значениями:

  • Reset: сброс таймера используется как TRGO;
  • Enable: включение счетчика таймера используется как TRGO;
  • Update: обновление таймера используется как TRGO;
  • ComparePulse: CC1F используется как TRGO;
  • CompareCh1: OC1REF таймера используется как TRGO;
  • CompareCh2: OC2REF таймера используется как TRGO;
  • CompareCh3: OC3REF таймера используется как TRGO;
  • CompareCh4: OC4REF таймера используется как TRGO;

Пример.

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

  1. На излучатель подается ШИМ-сигнал частотой 1 Мгц.
  2. С приемного датчика снимается сигнал и измеряется отставание импульсов от излучателя.

Для реализации такой логики хорошо подходит связка двух таймеров:

  1. Первый таймер выдает ШИМ-сигнал, его триггерный выход TRGO настроен в режим обновления.
  2. Второй таймер работает в режиме захвата, являясь при этом ведомым по отношению к первому таймеру со сбросом по триггерному сигналу.

Таким образом, на начало каждого импульса ШИМ-сигнала счетчик второго таймера сбрасывается, и, заведомо зная параметры ШИМ, можно измерить отставание сигнала с приемника.

Примерный код, реализующий предложенное решение:

// Настройка ШИМ, МК работает на частоте 80 Мгц
void Sensor::ConfigureOutputPwm()
{
   // Включение таймера
   OutputTimer::Enable();
   // Предделитель = 4
   OutputTimer::SetPrescaler(3); // 80 Mhz / 4 = 20 Mhz
   // Период = 20
   OutputTimer::SetPeriod(19); // 20 Mhz / 20 = 1 MHz частота PWM. Период = 1 us.
   // Выход TRGO на событие обновления
   OutputTimer::SetMasterMode(OutputTimer::MasterMode::Update);

   // Настройка таймера в режим ШИМ
   OutputPwmChannel::SelectPins<OutputPwmPin>();
   OutputPwmChannel::Enable();
   OutputPwmChannel::SetOutputMode(OutputPwmChannel::OutputMode::PWM1);
   OutputPwmChannel::SetPulse(10); // 50% скважность.
}

// Настройка таймера для захвата
void Sensor::ConfigureInputTimer()
{
   // Включение таймера
   InputTimer::Enable();
   // Без дополнительного деления, для максимальной точности
   InputTimer::SetPrescaler(0); // 80 Mhz / 1 = 80 Mhz. 1 tick = 1/80 us
   InputTimer::SetPeriod(0xffff);

   // Настройка ведомого режима: сброс по внутреннему сигналу ITR1
   InputTimer::SlaveMode::SelectTrigger(InputTimer::SlaveMode::Trigger::InternalTrigger1);
   InputTimer::SlaveMode::EnableSlaveMode(InputTimer::SlaveMode::