目录
作用:
基本知识:
简介:
一.高级控制定时器:
二.通用定时器:
三.基本定时器:
工作原理概括
程序编写
1.使用定时器可以替代延延时函数,延时函数占用CPU。
2.定时器计算固定脉冲,时间可准确计算:
公式:
Ft=168Mhz/4*时钟分频
Tout(us)=((arr+1)*(psc+1))/Ft(Mhz)
arr:自动重装载值
psc:定时器分频 (分频系数) //-1为参考手册要求
Ft:定时器时钟频率 Mhz
例:
定时器时钟84Mhz,8400分频,500重装值
Tout=(8400*500)/84M=0.05us=500ms 500ms定时器溢出一次
注意:
理想情况下,通过设定合适的psc将定时器周期设置为1s,但是很可惜,定时器只有16位的预分频寄存器,最大2^16-1,而这里我们的STM32F4定时器频率84Mhz,理想设置的psc应该为84000,但是达不到,
可以设置为8400,这样一个加载频率就是10Khz,一个加载周期0.1s.我们在此基础上,可以更改arr,让总体的定时器周期增大.
3.使用定时器中断利于程序的模块化设计,使能或失能即可对模块开关进行掌控。
定时器种类:
1.高级控制定时器:TIM1,TIM8
2.通用定时器:TIM2-TIM5,TIM9-TIM14
3.基本定时器:TIM6,TIM7
1.16位递增、递减、递增/递减自动重载计数器。
2.16 位可编程预分频器,用于对计数器时钟频率进行分频(即运行时修改),分频系数 介于 1 到 65536 之间。
3.多达 4 个独立通道,可用于:输入捕获,输出比较,PWM 生成(边沿和中心对齐模式),单脉冲模式输出
4. 发生如下事件时生成中断/DMA 请求:
①更新:计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发)
②触发事件:计数器启动、停止、初始化或通过内部/外部触发计数
③输入捕获
④输出比较
⑤断路输入
●TIM2-TIM5
1.(TIM3,TIM4)16位或者(TIM2,TIM5)32位递增、递减和递增/递减自动重载计数器。
2.16 位可编程预分频器,用于对计数器时钟频率进行分频(即运行时修改),分频系数介 于 1 到 65536 之间。
3.多达 4 个独立通道,可用于:输入捕获,输出比较,PWM 生成(边沿和中心对齐模式),单脉冲模式输出
4.发生如下事件时生成中断/DMA 请求:
①更新:计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发)
②触发事件:计数器启动、停止、初始化或通过内部/外部触发计数
③输入捕获
④输出比较
●TIM9-TIM14
1.16 位自动重载递增计数器(属于中等容量器件)。
2.16 位可编程预分频器,用于对计数器时钟频率进行分频(即运行时修改),分频系数 介于 1 和 65536 之间。
3.多达 2个独立通道,可用于:输入捕获,输出比较,PWM 生成(边沿和中心对齐模式),单脉冲模式输出
4.发生如下事件时生成中断/DMA 请求:
①更新:计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发)
②触发事件:计数器启动、停止、初始化或通过内部/外部触发计数
③输入捕获
④输出比较
1.16 位自动重载递增计数器
2.16 位可编程预分频器,用于对计数器时钟频率进行分频(即运行时修改),分频系数 介于 1 和 65536 之间
3.用于触发 DAC 的同步电路
4.发生如下更新事件时会生成中断/DMA 请求:计数器上溢
先介绍下几个寄存器:
1.TIMX_CNT:当前定时器计数值
2.TIMX_ARR(预加载寄存器):存放预设定的自动重载值,而非定时器内的溢出值
3.影子寄存器(自动重加载寄存器):存放当前定时器溢出值
我们注意到,在时间计算公式上,arr的值被减了1,这是因为我们定义的自动重载值会放入自动重载寄存器,当定时器使能时,自动重载寄存器会将值给影子寄存器,而CNT从0开始计数,所以设定的值需要减一
定时器使能,自动重载寄存器会将值给影子寄存器,CNT开始计数,达到溢出值后,定时器周期结束,产生了一个更新中断,但是此时我们在中断服务程序中修改预加载寄存器(TIMX_ARR),但是并没有直接写入到自动重装载寄存器,而是要等到下一个定时器周期结束,在更新中断刚产生,前于中断服务程序时,将预加载寄存器的值赋给自动重加载计时器。
以TIM3为例,利用定时器的计数器上溢中断为例,编写简单定时器中断程序利用draw()函数完成屏幕刷新。
首先完成定时器中断的初始化
void TIM3_Int_Init(u16 arr,u16 psc) //通用定时器3初始化
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //使能计时器的APB1时钟
TIM_TimeBaseInitStructure.TIM_Period = arr; //自动重装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //定时器分频
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //上溢
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure); //初始化TIM3
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //使用更新中断
TIM_Cmd(TIM3,ENABLE); //使能定时器
NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //定时器三中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; //中断抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
再开始编写定时器中断服务函数
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出,中断
{
draw(); //屏幕刷新
}
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //重置计数器
}
在main函数中,就可以利用全局变量或者指针对各种数据更改,从而通过定时器中断将交互显示在屏幕上
int main(void)
{
delay_init(168);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart_init(115200);
LED_Init();
LCD_Init();
key_Configuration();
TIM3_Int_Init(500 - 1, 8400 - 1);
draw();
POINT_COLOR=RED;
delay_ms(100);
while(1)
{
KEYCODE=KEY_Scanf();
lock();
}
}
整体代码和驱动放在github上:https://github.com/wu58430/STM32F4-LOCK
更多原理细节后续补充