Информация взята с сайта http://mycontroller.ru/old_site/stm32-timer-general-purpose-vneshnyaya-sinhronizatsiya/default.htm, и из переведённой главы по таймерам в reference manual/
http://pro-interes.com/wp-content/uploads/2018/12/RM0041_12_Tim1.pdf
Также пример кода по инициализации энкодера был взят из reference manual RM0091 на другую серию stm32 контроллеров, но таймеры у них аналогичные.
A.9.11 Encoder interface code example /* (1) Configure TI1FP1 on TI1 (CC1S = 01), configure TI1FP2 on TI2 (CC2S = 01) */ /* (2) Configure TI1FP1 and TI1FP2 non inverted (CC1P = CC2P = 0, reset value) */ /* (3) Configure both inputs are active on both rising and falling edges (SMS = 011) */ /* (4) Enable the counter by writing CEN=1 in the TIMx_CR1 register. */ TIMx->CCMR1 |= TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0; /* (1)*/ TIMx->CCER &= (uint16_t)(~(TIM_CCER_CC21 | TIM_CCER_CC2P); /* (2) */ TIMx->SMCR |= TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1; /* (3) */ TIMx->CR1 |= TIM_CR1_CEN; /* (4) */
В зависимости от способа синхронизации, возможно два режима работы таймеров: независимый и подчиненный (или Slave mode).
В подчиненном режиме таймер синхронизируется от внешнего сигнала, в качестве которого может быть выбран:
- один из внутренних таймеров;
- сигнал на выводе контроллера (ETR, TI1 или TI2)(нас интересует это)

Для перевода таймера в подчиненный режим и выбора источника, который будет его тактировать или синхронизировать, предназначены разряды SMS (Slave mode selection, т.е. выбор режима ведомого) регистра SMCR (Slave mode control register, т.е. управляющий регистр режима ведомого, или подчиненного).
Для перевода таймера в режим энкодера нужно в регистр SMCR в биты SMS записать 011
SMS=011 – режим энкодера №3; счетчик считает вверх или вниз по сигналам TI1FP1 и TI2FP2, в зависимости от уровня сигнала на другом входе;
TIM1->SMCR = TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1;

Затем нужно с помощью регистра TIM1->CCMR1 и битов ССxS выбрать направление канала и режим работы
01: Канал СС1 сконфигурирован как вход, IC2 отображается на TI1
01: Канал СС2 сконфигурирован как вход, IC2 отображается на TI2
Первый канал TIM1 выход PA8 подключаем к TI2 записью 01 в регистр TIM1->CCMR1 биты СС1S, второй канал выход PA9 подключаем к TI1 записью 10 в регистр TIM1->CCMR1 биты СС2S
TIM1->CCMR1 |= TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_1;
Затем нужно включить цифровой фильтр на входах энкодера для снижения влияния дребезга, это делается записью в регистрTIM1->CCMR1 в биты IСxF значения по таблице.
- 0000: No filter, sampling is done at f(dts)
- 0001: f(sampling)=f(ck_int), N=2
- 0010: f(sampling)=f(ck_int), N=4
- 0011: f(sampling)=f(ck_int), N=8
- 0100: f(sampling)=f(dts)/2, N=6
- 0101: f(sampling)=f(dts)/2, N=8
- 0110: f(sampling)=f(dts)/4, N=6
- 0111: f(sampling)=f(dts)/4, N=8
- 1000: f(sampling)=f(dts)/8, N=6
- 1001: f(sampling)=f(dts)/8, N=8
- 1010: f(sampling)=f(dts)/16, N=5
- 1011: f(sampling)=f(dts)/16, N=6
- 1100: f(sampling)=f(dts)/16, N=8
- 1101: f(sampling)=f(dts)/32, N=5
- 1110: f(sampling)=f(dts)/32, N=6
- 1111: f(sampling)=f(dts)/32, N=8
TIM1->CCMR1 |= TIM_CCMR1_IC1F_0 |TIM_CCMR1_IC1F_1 |TIM_CCMR1_IC1F_2 |TIM_CCMR1_IC1F_3 |TIM_CCMR1_IC2F_0 |TIM_CCMR1_IC2F_1 |TIM_CCMR1_IC2F_2 |TIM_CCMR1_IC2F_3;
Регистром TIM1->ARR = 1023; устанавливаем //значение, до которого считает CNT
в конце нужно включить таймер
Регистром TIM1->PSC предделитель делим 2 на чтобы при повороте энкодера на один тик таймер увеличивался также на 1. Чтобы получить предделитель делящий на2 нужно записать в регист TIM1->PSC = 1;.
перед включением таймера нужно инциализировать значения в регистре предделителя это делается путем программного вызова переполнения таймера, записью в регистр TIM1->EGR=TIM_EGR_UG;. По простому чтобы значения в предделителе стали те которые мы записали, мы должны вызвать событие переполнения таймера, только после него запишутся эти значения, это можно сделать программно до включения таймера.
Включаем таймер:
TIM1->CR1 = TIM_CR1_CEN;
Код программы:
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_adc.h"
#include "stm32f10x_dma.h"
volatile uint16_t ADCBuffer[] = {0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA};
void delay(uint32_t ms)
{
volatile uint32_t nCount;
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq (&RCC_Clocks);
nCount=(RCC_Clocks.HCLK_Frequency/10000)*ms;
for (; nCount!=0; nCount--);
}
//Функция включения тактирования на нужной периферии, установка значений делителей частоты
void RCC_ENABLE(void)
{
//подача тактирования на PORTA, настройка преддедлитля ADC, подача тактирования на ADC
RCC->APB1ENR |= RCC_APB2ENR_IOPAEN; // Разрешить тактирование порта PORTA
RCC->CFGR |=RCC_CFGR_ADCPRE_0|RCC_CFGR_ADCPRE_1 ; //входной делитель
//обнуляем биты чтобы установить предделитель 2(наименьшее значение)
//clock for ADC (max 14MHz --> 8/2=4MHz)
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; //подаем тактирование АЦП
RCC->AHBENR |= RCC_AHBENR_DMA1EN; //подаем тактирование на DMA
}
void GPIO_Configuration(void)
{
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; //включить тактирование порта
//Вывод GPIOA.9
GPIOA->CRH &= ~GPIO_CRH_MODE9; //очистить разряды MODE
GPIOA->CRH &= ~GPIO_CRH_CNF9; //очистить разряды CNF
GPIOA->CRH |= GPIO_CRH_CNF9_1; //дискретный вход, подтяжка к плюсу
GPIOA->BSRR = GPIO_BSRR_BS9; //включить подтягивающий резистор
//Вывод GPIOA.8
GPIOA->CRH &= ~GPIO_CRH_MODE8; //очистить разряды MODE
GPIOA->CRH &= ~GPIO_CRH_CNF8; //очистить разряды CNF
GPIOA->CRH |= GPIO_CRH_CNF8_1; //дискретный вход, подтяжка к плюсу
GPIOA->BSRR = GPIO_BSRR_BS8; //включить подтягивающий резистор
//Вывод GPIOA.3
GPIOA->CRL &= ~GPIO_CRL_MODE3; //Очистить биты MODE
GPIOA->CRL &= ~GPIO_CRL_CNF3; //Очистить биты CNF
//Вывод GPIOA.5
GPIOA->CRL &= ~GPIO_CRL_MODE5; //Очистить биты MODE
GPIOA->CRL &= ~GPIO_CRL_CNF5; //Очистить биты CNF
}
void TIM(void)
{
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; //тактирование таймера
TIM1->CCMR1 |= TIM_CCMR1_IC1F_0| TIM_CCMR1_IC1F_1| TIM_CCMR1_IC1F_2|TIM_CCMR1_IC1F_3
| TIM_CCMR1_IC2F_0|TIM_CCMR1_IC2F_1|TIM_CCMR1_IC2F_2|TIM_CCMR1_IC2F_3;
TIM1->CCMR1 |= TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0; //
//TIM1->CCER = TIM_CCER_CC1P | TIM_CCER_CC2P;
TIM1->SMCR = TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1; //режим энкодера
TIM1->ARR = 1023; //значение, до которого считает CNT
TIM1->PSC = 1;
TIM1->EGR=TIM_EGR_UG;
TIM1->CR1 = TIM_CR1_CEN; //включаем таймер
}
void ADC_DMA_init(void)
{
//Настройка DMA
DMA1_Channel1->CNDTR = 4;
DMA1_Channel1->CCR &= ~DMA_CCR1_DIR;
DMA1_Channel1->CMAR = (uint32_t)ADCBuffer;
DMA1_Channel1->CCR |= DMA_CCR4_MSIZE_0;
DMA1_Channel1->CCR |= DMA_CCR1_MINC;
DMA1_Channel1->CCR |= DMA_CCR1_CIRC;
DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;
DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_0;
DMA1_Channel1->CCR &= ~DMA_CCR1_PINC;
DMA1_Channel1->CCR |= DMA_CCR1_EN;
ADC1->CR2 |= ADC_CR2_ADON; //включить АЦП
//настройка АЦП происходит в режиме power down mode
ADC1->CR1 = 0; //т.к. не используем AWD и прерывания в данном примере то обнуляем CR1
ADC1->CR1 |= ADC_CR1_SCAN; //Включение прерывания, и сканирование группы
ADC1->CR2 |= ADC_CR2_CONT|ADC_CR2_DMA; //режим непрерывного преобразования
ADC1->SMPR2 |= ADC_SMPR2_SMP3_1|ADC_SMPR2_SMP5_1; //установка t выборки для 3 и 5 канала 13,5 цикла
//Калибровка
//В даташите
//Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) for
//at least two ADC clock cycles. enable ADC
// до начала калибровки нужно enable ADC
// в даташите в разделе 11.3.1 ADC on-off control сказано что первое включение ADON bit = ‘1’
// выводит из режима power down mode, а повторное запускает преобразование через tSTAB
ADC1->CR2 |= ADC_CR2_RSTCAL; // reset calibration
while (ADC1->CR2 & ADC_CR2_RSTCAL) {}
//start self-calibration
ADC1->CR2 |= ADC_CR2_CAL;
while(ADC1->CR2 & ADC_CR2_CAL) {}
ADC1->SQR1 |= ADC_SQR1_L_1|ADC_SQR1_L_0; //т.к. в регулярной группе 4 выборки то биты L[3:0] = 3 регистра SQR1
ADC1->SQR3 &= ~ ADC_SQR3_SQ1; // в начале обнуляем биты
ADC1->SQR3 |= ADC_SQR3_SQ1_0
|ADC_SQR3_SQ1_1
|ADC_SQR3_SQ2_0
|ADC_SQR3_SQ2_2
|ADC_SQR3_SQ3_0
|ADC_SQR3_SQ3_1
|ADC_SQR3_SQ4_0
|ADC_SQR3_SQ4_2; //затем устанавливаем 0 бит в 1, чтобы выбрать 1 канал в SQ2,SQ4, SQ1,SQ3 оставляем равным 0 т.к. 0 канал
//Start conversion
ADC1->CR2 |= ADC_CR2_ADON;
}
int main(void)
{
RCC_ENABLE();
GPIO_Configuration();
TIM();
ADC_DMA_init();
lcd_init();
lcd_out("Vzad");
while (1)
{
lcd_set_xy(4,0);
BCD_4IntLcd(TIM1->CNT);
lcd_set_xy(1,1);
lcd_out("V");
lcd_set_xy(3,1);
BCD_4IntLcd(ADCBuffer[0]/124);
lcd_set_xy(9,1);
lcd_out("I");
lcd_set_xy(10,1);
BCD_4IntLcd(ADCBuffer[1]/124);
delay(100);
}
}