Вступление.
В завершение изучения таймеров, в частности таймеров общего назначения, рассмотрим оставшийся без внимания блок - 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 Мгц.
- С приемного датчика снимается сигнал и измеряется отставание импульсов от излучателя.
Для реализации такой логики хорошо подходит связка двух таймеров:
- Первый таймер выдает ШИМ-сигнал, его триггерный выход TRGO настроен в режим обновления.
- Второй таймер работает в режиме захвата, являясь при этом ведомым по отношению к первому таймеру со сбросом по триггерному сигналу.
Таким образом, на начало каждого импульса ШИМ-сигнала счетчик второго таймера сбрасывается, и, заведомо зная параметры ШИМ, можно измерить отставание сигнала с приемника.
Примерный код, реализующий предложенное решение:
// Настройка ШИМ, МК работает на частоте 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::