TIM
The timer is the most powerful and complex 32 structure.
- The functions used by 51 before, generate interrupts at regular intervals.
- Output comparison, often used to generate PWM waveforms, drive motors, etc.
- Input capture, measure square wave frequency.
- Encoder, reads the waveform of the quadrature encoder.
Maximum timing time: 72M/65536/65536=interrupt frequency, the reciprocal of the interrupt frequency is the maximum timing time.
The timer can be cascaded, for example, the maximum timing of 72MHz is 59.65s, cascading once * 65536 * 65536.
type | serial number | bus | Function |
---|---|---|---|
Advanced Timer | TEAM1、TEAM8 | APB2 | It has all the functions of a general-purpose timer, and additional functions such as repetition counter, dead zone generation, complementary output, brake input, etc. |
General purpose timer | TIM2、TIM3、TIM4、TIM5 | APB1 | It has all the functions of the basic timer, and has additional functions such as internal and external clock source selection, input capture, output comparison, encoder interface, master-slave trigger mode, etc. |
basic timer | TIM6、TIM7 | APB1 | It has the functions of timing interrupt and master mode triggering DAC |
Increasingly complex and powerful from bottom to top. f103c8t6 has TM1-4 (different chips are different, please refer to the manual!), we mainly study general-purpose timers.
PSC divides the frequency of RCC. For example, if writing 1 means 2 frequency division, it will output 72MHz/2=36MHz. Actual frequency division factor = prescaler value + 1.
The counter is continuously incremented according to the clock frequency, = cleared and an interrupt is generated when the register value is automatically reloaded. UI is interrupt, U is event.
Actively trigger DAC: DAC interrupts will be very frequent and occupy a lot of CPU resources. If the timer can manipulate the slave device to handle the DAC by itself, it will save a lot of CPU resources. TRGO in the picture above is.
On the basis of basic counters, general-purpose registers also support down counting and center-aligned counting (0-reload value-0-reload value...)
Clock optional internal 72MHz clock or external clock.
Timer cascading can be realized, refer to the manual to check which timers and which cascades. The self-output pin CH can also be used as its own clock input, and the function will be expanded later.
The four outputs are output compare circuits, and the left is the input capture circuit.
The shadows in the figure have buffer registers, and the buffer registers will be discussed immediately below.
The repetition counter allows several cycles before an interrupt is triggered.
Output CH1-3 can output complementary waves, useful. In order to prevent the straight-through phenomenon when switching (two inverting circuits switch at the same time, similar to x-shaped), through the DTG dead zone generating circuit, a dead zone is generated before switching, and the upper and lower tubes are all reset to zero before switching.
Brake input in the lower left corner, the timer can be terminated in an abnormal state.
The basic structure is as follows:
Running control is like setting up and down counting.
The interrupt output control is equivalent to a flag bit, which determines whether the interrupt is needed or not.
CK_PSC: Input clock for prescaler.
CNT_EN: Counter enable, high level open. The subsequent prescaler becomes 1, and the frequency is divided by /2, so two rising edges are triggered only once. The counter register is continuously incremented accordingly.
The event is updated when the autoreloader value is reached and the counter is zeroed.
After the prescaler register is modified, it is not changed immediately, but the prescaler buffer is modified after the next counting cycle after the interrupt is triggered, so that the prescaler buffer can be truly controlled.
The principle of frequency division can be seen in the prescaler counter. For example, if the prescaler buffer is set to 1, that is, the actual frequency division factor is 2, then the actual frequency division factor -1 is reached after counting 0 and 1, and the counter is cleared to ++.
C K _ C N T = C K _ P S C / ( P S C + 1 ) CK\_CNT=CK\_PSC / (PSC+1) CK_CNT=CK_PSC/(PSC+1)
For counters it's like this:
The actual frequency division factor is 2, 2 clock cycles before +1, and the update event and interrupt flag register prompt is now interrupted when overflow occurs. The interrupt flag register must be manually cleared in the interrupt routine.
Counter overflow frequency:
C K _ C N T _ O V = C K _ C N T / ( A R R + 1 ) = C K _ P S C / ( P S C + 1 ) / ( A R R + 1 ) CK\_CNT\_OV = CK\_CNT / (ARR + 1) = CK\_PSC / (PSC + 1) / (ARR + 1) CK_CNT_OV=CK_CNT/(ARR+1)=CK_PSC/(PSC+1)/(ARR+1)
arr is the auto-reload register value. Take the reciprocal of the overflow time.
arr also has a buffer register, you can choose whether to use it or not.
As shown in the figure, although arr has been changed to 36, the shadow register has to be updated after this round of interrupts is over.
It is better to turn on this, because if the value of arr is almost added, and then arr shrinks, the counter may have to be added until it overflows and returns to zero, and then it will trigger a small problem such as an interrupt.
Next look at the clock, the clock is what all peripherals need. The configuration is in the systemInit() function.
HSI HSE is an internal and external clock source, and the external one is more stable. Both provide the system clock and some peripherals (AHB APB12) rely on them.
LSE OSC is RTC.
LSI RC is a clock for independent watchdog.
SystemInit() starts the internal clock first, the system temporarily runs at 8MHz, then starts the external clock and enters the PLL phase-locked loop for frequency multiplication, and outputs it after reaching a stable 72MHz.
Therefore, there is a problem with the external clock circuit. When it cannot be switched normally, it may feel that the program runs slowly. It is running with the 8MHz system clock. Or the CSS clock security system may forcefully stop the external circuit. The CSS also participates in the brake input circuit in the Advanced Control Timer.
APB1 prescaler factor of this board is 2, APB2 is 1.
The division factor of the AHB prescaler directly divides PCLK1. Timer 2-7 is: "If the prescaler factor = 1, then the frequency = 36MHz unchanged; otherwise, the frequency * 2", so its internal reference clock is always 72MHz. So are timers 1,8 on APB2.
All clocks are connected with an AND gate, plus an enable circuit.
Code: Timer
process:
- RCC。
- Set the clock source.
- Set the time base unit of the clock source (initialize prescaler, auto-reloader, counter mode).
- Set interrupt control (on).
- Configure nvic, this uses the NIVC_Init learned earlier.
- Set up run controls.
- Start the counter.
List of functions needed:
TimeBaseInit: Initialize the prescaler, auto-reloader, counter mode.
TimeBaseStructInit: Assign an initial value to the time base unit.
Cmd: Start the clock.
ITConfig: Enable the corresponding clock interrupt.
The following six are clock source selection, internal clock, ITRx other timer clock, TIx capture channel clock, ETR mode 1, 2 clock, functions for configuring ETR time base unit, polarity, filter and other settings individually.
These five functions are functions to modify the configuration of the time base unit after Init (change the prescaler, change the counting mode, set whether to preload, change the counter value, change the automatic reload value, etc.
Finally there are four functions that get clear registers.
The code is slightly different from exti.
#include "stm32f10x.h" // Device header
extern uint16_t cnt;
void Timer_Init(void){
//rcc, set timer source, set psc + set arr + set cnt mode(time base unit), set it controller, set nvic it handler, set running control, enable counter
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_InternalClockConfig(TIM2);//默认也是这个时钟,不写也行
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//滤波器采样,频率越低,采样点数越多,滤波效果越好。不过延迟也越大。采样频率就是内部时钟和这个分频参数共同作用的结果
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
//比如我们想定1s中断一次,CK_CNT_OV = CK_CNT / (ARR + 1) = CK_PSC / (PSC + 1) / (ARR + 1),也就是72M / (PSC + 1) / (ARR + 1) = 1
//所以两者赋值可以是10000-1和7200-1,只要两者都在65535以内就行,赋值不唯一
TIM_TimeBaseInitStructure.TIM_Period=10000-1;//arr自动重装器值,72M 计数10000次,耗时 10000/72M s
TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;//预分频器值,分7200频,即 10000/(72M/7200) s=1s中断一次。
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器值,高级计数器才用
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);//设为更新中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2,ENABLE);
}
void TIM2_IRQHandler(void){
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){
//这里设置为update
cnt++;
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
Here the cnt variable is written in main.c, and the extern variable is used to declare "this variable is in another file, you can find the compiler". In fact, the function declaration in .h should also add extern, but it can be omitted.
After starting the development board, you can see that an interrupt is triggered immediately, why is this? The last sentence of TIM_BaseInit is this:
TIMx->EGR = TIM_PSCReloadMode_Immediate;
We know that the value written to the auto-reload register is not written immediately, but is written into the buffer until the event is updated. At the beginning, after we initialized the auto-reload register, we couldn't write it in, and couldn't trigger an interrupt.
Therefore, we need to manually trigger an update event in TIM_BaseInit, which is the above statement. The price is that an interrupt is triggered immediately after power-on. Update events and update interruptions occur simultaneously.
If you want to remove this interrupt, you can immediately follow TIM_BaseInit with a "TIM_ClearFlag".
Next, we write a use case, because TIM2 and PA0 are one pin, so we set TIM2 to be configured by external clock mode, so that after we connect the infrared shutter to PA0, manually blocking the light once is equivalent to simulating a cycle of the clock .
Modifications needed:
- Clock initialization plus GPIOInit, change the internal clock configuration to external clock (mode 2).
void Timer_Init(void){
//rcc, set timer source, set psc + set arr + set cnt mode(time base unit), set it controller, set nvic it handler, set running control, enable counter
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0x0F);//这里是滤波,太小的话一次红外检测加好多
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period=10-1;
TIM_TimeBaseInitStructure.TIM_Prescaler=1-1;//十次红外检测,定时器++
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM2, TIM_IT_Update);
TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2,ENABLE);
}
In this way, the effect is to create a clock waveform through the infrared sensor for the timer to read.