赞
踩
【系列笔记为跟随UP主江协科技学习STM32过程的一些问题,同时方便日后忘记时复习,文中部分内容来源于UP主的PPT同时加入个人理解】
一.TIM简介
TIM(Timer)定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断 ,16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能 根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型。
类型 | 编号 | 总线 | 功能 |
高级定时器 | TIM1、TIM8 | APB2 | 拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能 |
通用定时器 | TIM2、TIM3、TIM4、TIM5 | APB1 | 拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能 |
基本定时器 | TIM6、TIM7 | APB1 | 拥有定时中断、主模式触发DAC的功能 |
二.定时器中断
1.定时器中断基本结构
2.定时器中断常用库函数
- void TIM_DeInit(TIM_TypeDef* TIMx);//将指定的 TIM 外设重置为默认值。
-
- void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);//配置 TIM 的时基结构体。
-
- void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);//将 TIM 时间基准结构体初始化为默认设置。
-
- void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);//使能或禁用指定的 TIM 外设。
-
- void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);//使能或禁用指定 TIM 的指定中断。
-
- void TIM_InternalClockConfig(TIM_TypeDef* TIMx);//将内部时钟驱动 TIM 外设。
-
- void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);//配置 TIM 的预分频器和自动重装载寄存器的重新加载方式。
-
- void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);//配置 TIM 的计数器模式。
-
- void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);//使能或禁用 TIM 的自动重装载寄存器预加载功能。
-
- void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);//设置 TIM 的计数器值。
-
- void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);//设置 TIM 的自动重装载寄存器值。
-
-
- uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);//获取 TIM 的当前计数器值。
-
- uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);//获取 TIM 的预分频器值。
-
- FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);//检查 TIM 的指定标志位的状态。
-
- void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);//清除 TIM 的指定标志位。
-
- ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);//检查 TIM 的指定中断标志位的状态。
-
- void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);//清除 TIM 的指定中断标志位。
3.定时器中断初始化
- void Timer_EXITInit()
- {
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM3, ENABLE); //使能 APB1 时钟
-
- //将定时器2配置为内部时钟模式
- TIM_InternalClockConfig(TIM2);
- TIM_InternalClockConfig(TIM3);
-
- //初始化定时器时间基数
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
- TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; // 设置时钟分频为不分频,对内部时钟无影响
- TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 设置计数模式
- TIM_TimeBaseInitStruct.TIM_Period = 10000-1; // 设置重载值
- TIM_TimeBaseInitStruct.TIM_Prescaler = 7200; // 设置预分频值
- TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; // 设置重复计数器为0,高级定时器参数
- TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);
-
- //清除中断标志位,避免上电进入中断
- TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
- TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
-
- //启用定时器的更新中断 (TIM_IT_Update 更新(溢出)中断)
- TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
- TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
-
- //设置中断优先级组为2位抢占优先级+2位子优先级
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
-
- //配置中断管理寄存器
- NVIC_InitTypeDef NVIC_InitStructure;
- NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //选择中断通道为TIM2
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //设置抢占式优先级为1(0~2^2)
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //设置子优先级为1 (0~2^2)
- NVIC_Init(&NVIC_InitStructure);
- }
4.定时器中断功能函数
- void TIM2_IRQHandler()
- {
- if(TIM_GetITStatus(TIM2,TIM_FLAG_Update) == SET)
- {
-
-
- TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);
- }
- }
五.TIM输出比较(PWM)
1.OC(Output Compare)输出比较,输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形 每个高级定时器和通用定时器都拥有4个输出比较通道。
2.输出比较模式:
模式 | 描述 |
冻结 | CNT=CCR时,REF保持为原状态 |
匹配时置有效电平 | CNT=CCR时,REF置有效电平 |
匹配时置无效电平 | CNT=CCR时,REF置无效电平 |
匹配时电平翻转 | CNT=CCR时,REF电平翻转 |
强制为无效电平 | CNT与CCR无效,REF强制为无效电平 |
强制为有效电平 | CNT与CCR无效,REF强制为有效电平 |
PWM模式1 | 向上计数:CNT<CCR时,REF置有效电平,CNT≥CCR时,REF置无效电平 向下计数:CNT>CCR时,REF置无效电平,CNT≤CCR时,REF置有效电平 |
PWM模式2 | 向上计数:CNT<CCR时,REF置无效电平,CNT≥CCR时,REF置有效电平 向下计数:CNT>CCR时,REF置有效电平,CNT≤CCR时,REF置无效电平 |
常用模式一/二产生PWM信号。
3.输出比较基本结构:
4.TIM3产生频率1khz,占空比50%PWM信号代码如下:
- void PWM_Init()
- {
- // 使能TIM3时钟
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
-
- // 使能GPIOA时钟
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
-
- // 配置GPIOA的引脚6为复用推挽输出
- GPIO_InitTypeDef GPIOA_InitStructure;
- GPIOA_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIOA_InitStructure.GPIO_Pin = GPIO_Pin_6;
- GPIOA_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOA, &GPIOA_InitStructure);
-
- // 配置定时器(TIM3)为内部时钟模式
- TIM_InternalClockConfig(TIM3);
-
- // 配置定时器(TIM3)的时间基准参数
- TIM_TimeBaseInitTypeDef TIM_TimeBase_InitStructure;
- TIM_TimeBase_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//决定数字滤波器采样频率的参数(输入捕获)
- TIM_TimeBase_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
- TIM_TimeBase_InitStructure.TIM_Period = 100 - 1; // 频率=72MHz/720/100=1khz
- TIM_TimeBase_InitStructure.TIM_Prescaler = 720 - 1; // 设置预分频值为720,分频后计数器频率为72Mhz/720=100000;
- TIM_TimeBase_InitStructure.TIM_RepetitionCounter = 0;//产生单个周期的PWM信号
- TIM_TimeBaseInit(TIM3, &TIM_TimeBase_InitStructure);
-
- // 配置定时器(TIM3)的输出比较参数
- TIM_OCInitTypeDef TIM_OCInit_InitStructure;
- TIM_OCStructInit(&TIM_OCInit_InitStructure);//不对结构体互补输出成员赋值,先赋默认值
- TIM_OCInit_InitStructure.TIM_OCMode = TIM_OCMode_PWM1;
- TIM_OCInit_InitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//极性选择,高电平有效,若比较器输出高电平则为PWM高电平;低电平有效,若比较器输出低电平则为PWM高电平
- TIM_OCInit_InitStructure.TIM_OutputState = TIM_OutputState_Enable;//定时器通道使能
- TIM_OCInit_InitStructure.TIM_Pulse = 50; // 设置占空比为50%
- TIM_OC1Init(TIM3, &TIM_OCInit_InitStructure);
-
- // 使能定时器(TIM3)
- TIM_Cmd(TIM3, ENABLE);
- }
5.运行过程修改预分频数和计数溢出值函数:
- void updatePWMFrequency(uint16_t newPrescaler, uint16_t newPeriod)
- {
-
- TIM_Cmd(TIM3, DISABLE); //关闭定时器后才可修改
- TIM_PrescalerConfig(TIM3, newPrescaler, TIM_PSCReloadMode_Immediate);// 配置新的预分频值,立即生效
- TIM_SetAutoreload(TIM3, newPeriod);//配置新的溢出值
-
- TIM_Cmd(TIM3, ENABLE);
- }
6.PWM实现呼吸灯:
- int main()
- {
- OLED_Init();
- PWM_Init();
- delay_init();
- EXTI_LEDInit();
- while(1)
- {
- OLED_ShowString(1,1,"frequency:");
- OLED_ShowNum(1,11,100-Pulse,3);
- OLED_ShowChar(1,14,'%');
- for(i = 0;i <= Pulse;i++)
- {
- TIM_SetCompare1(TIM3,i);
- delay_ms(10);
- }
- for(i = Pulse;i > 0;i--)
- {
- TIM_SetCompare1(TIM3,i);
- delay_ms(10);
- }
- }
- }
六.PWMI输入捕获
1.输入捕获简介:IC(Input Capture)输入捕获 输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数 每个高级定时器和通用定时器都拥有4个输入捕获通道 可配置为PWMI模式,同时测量频率和占空比 可配合主从触发模式,实现硬件全自动测量。
2.频率测量方法:
测频法:在时间T内,对上升沿计次,得到N,则频率 f=N / T,适用高频,频率越高标准时间内N越大,误差越小;
测周法:两个上升沿内,以标准频率fc计次,得到N ,则频率 f=f c/ N,适用低频,频率越低,周期越长,N越大,误差越小;
中界频率:测频法与测周法误差相等的频率点 f=sqrt(fc/T)。
3.主从触发模式:
主模式:可以将定时器内部的信号,映射到TRGO引脚,用于触发别的外设,所以这部分叫做主模式。
从模式:就是接收其他外设或者自身外设一些信号,用于控制自身定时器的运行,也就是被别的信号控制。
触发源选择:就是选择从模式的触发信号源,触发源选择,选择指定的一个信号,得到TRGI,TRGI去触发从模式,从模式可以在这个列表里,选这择项操作来在自动执行。
相关函数;
void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);
1.主模式输入信号选择(主模式暂不了解)
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
2. 从模式输入信号选择,TIM_InputTriggerSource选择通道。(TIM_TS_TI1FP1)
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);
3.从模式选择:
4.输入捕获基本结构:
TIM3从上升沿开始计数,到达下降沿后触发TI1FP2,CCR2=CNT,到达上升沿后CCR1=CNT,同时触发从模式,CNT重置。频率=fc/CCR1,占空比=CCR2/CCR1。
TIMx_CH1和TIMx_CH2可同时接入同一捕获寄存器测量不同参数。由TIxFPy进行配置,表示由通道x输入至通道y的捕获寄存器。
5.输入捕获初始化:
- void IC_Init(void)
- {
- // 使能TIM3定时器时钟
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
- // 使能GPIOA端口时钟
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
-
- // 配置GPIOA的GPIO_Pin_6引脚为上拉输入模式
- GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
-
- // 配置TIM3定时器为内部时钟模式
- TIM_InternalClockConfig(TIM3);
-
- // 配置TIM3定时器的基本参数
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
- TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
- TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
- TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //计数器的溢出周期
- TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //设置计数器的时钟频率 1000000
- TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
- TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
-
- // 配置TIM3定时器的输入捕获参数
- TIM_ICInitTypeDef TIM_ICInitStructure;
- TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; // 配置通道1
- TIM_ICInitStructure.TIM_ICFilter = 0xF; // 配置输入滤波器
- TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //配置输入极性为上升沿触发
- TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 设置输入分频系数为不分频
- TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; // 配置输入源为直接映射到TI1
- TIM_ICInit(TIM3, &TIM_ICInitStructure);
-
- TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);//配置TI1FP2,自动根据TIM_ICInitStructure配置为与TI1FP1相反,即下降沿触发计数,交叉映射到TI1FP2.
-
- // 选择TIM3从模式输入触发源为TI1FP1,即TI1FP1每次上升沿触发从模式
- TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
- // 选择TIM3定时器的从模式为自动清零(TI1PF1的上升沿清零CNT)
- TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
-
- // 启动TIM3定时器
- TIM_Cmd(TIM3, ENABLE);
- }
6.读取频率,占空比
- uint32_t IC_GetFreq(void)
- {
- return 1000000 / (TIM_GetCapture1(TIM3));
- }
-
- uint32_t IC_Getduty(void)
- {
- return TIM_GetCapture2(TIM3)*100/TIM_GetCapture1(TIM3);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。