4.基于STM32CubeMX使用TIM定时器

1.基础定时器

基础定时器相关函数
HAL_TIM_Base_Init(TIM_HandleTypeDef *htim); 定时器初始化,设置各种参数和连续定时模式
HAL_TIM_Base_MspInit() 弱函数,在HAL_TIM_Base_Init()里被调用,需重新实现
HAL_TIM_OnePulse_Init() 将定时器配置为单次定时模式,需要先执行HAL_TIM_Base_Init()
HAL_TIM_Base_Start() 以轮询工作方式启动定时器,不会产生中断
HAL_TIM_Base_Stop() 停止轮询工作方式的定时器
HAL_TIM_Base_Start_IT() 以中断工作方式启动定时器,发生UEV事件时产生中断
HAL_TIM_Base_Stop_IT() 停止中断工作方式定时器的
HAL_TIM_Base_Start_DMA() 以DMA工作方式启动定时器
HAL_TIM_Base_Stop_DMA() 停止DMA工作方式的定时器
HAL_TIM_Base_GetState(TIM_HandleTypeDef *htim) 获取基础定时器的当前状态
其他通用操作函数
__HAL_TIM_ENABLE(__HANDLE__) 启 用 某 个 定 时 器 , 就 是 将 定 时 器 控 制 寄 存 器TIMx_CR1的CEN位置1
__HAL_TIM_DISABLE() 禁用某个定时器
__HAL_TIM_GET_COUNTER() 在运行时读取定时器的当前计数值 , 就 是读 取TIMx_CNT寄存器的值
__HAL_TIM_SET_COUNTER() 在运行时设置定时器的计数值,就是设置TIMx_CNT寄存器的值
__HAL_TIM_GET_AUTORELOAD() 在运行时读取自重载寄存器TIMx_ARR的值
__HAL_TIM_SET_AUTORELOAD() 在运行时设置自重载寄存器TIMx_ARR的值,并改变定时的周期
__HAL_TIM_SET_PRESCALER() 在运行时设置与分频系数,就是设置分频寄存器TIMx_PSC的值
4.中断处理
__HAL_TIM_GET_FLAG() 获取某个事件是否触发的标志,就是读取状态寄存器TIMx_SR中相应的中断事件位是否置1
__HAL_TIM_GET_IT_SOURCE() 判断是否是某个事件产生的中断,返回值为SET或RESET
__HAL_TIM_CLEAR_IT() 清除某个事件的中断标志,就是将状态寄存器TIMx_SR中相应的中断事件位是否置0
__HAL_TIM_ENABLE_IT() 启用某个事件的中断,就是将中断使能寄存器TIMx_DIER中相应事件位置1
__HAL_TIM_DISABLE_IT() 禁用某个事件的中断,就是将中断使能寄存器TIMx_DIER中相应事件位置0
HAL_TIM_IRQHandler() 定时器ISR函数里的通用处理函数
HAL_TIM_PeriodElapsedCallback(htim) 弱函数,UEV事件中断的回调函数
5使用示例
有tim6和tim7,使用tim6举例:
    1.在引脚界面选择引脚对应模式为tim6_ch1
    2.将HCLK设置为100MHz,APB1和APB2时钟50MHz,方便计算
    3.在Timer界面选择Tim6,勾选Actived启动Tim6,Prescalar预分频值49999,实际分频值为50000,Counter Period计数周期,也就是自动重装载寄存器ARR的值,设置为500,NVIC界面使能TIM6全局中断及UEV事件中断使能,此时Tim6每500ms产生一次硬件中断。要时勾选One Pulse Mode则只中断一次。
    4.在程序中使用HAL_TIM_Base_Start_IT(&htim6);以中断方式启动TIM6.
    5.在void TIM6_DAC_IRQHandler(void)中会调用回调函数,所以只需要重写回调函数。
    6.编写void HAL_TIM_PeriodElapsedCallback(TIM_HandlerTypeDef *htim)
            {
            if(htim->Instance==TIM6)//或者使用htim==&htim6判断
             代码部分
              }

2.HAL_通用定时器TIM
基础定时器6,7挂载总线APB1,高级定时器1,8,通用定时器为其它定时器
时基单元包括3个寄存器:
(1)计数寄存器(CNT),这个寄存器存储计数器当前的计数值,可以在运行时被读取。
(2)预分频寄存器(PSC),寄存器数值范围0至65535,对应于分频系数1至65536。 
(3)自动重载寄存器(ARR),这个寄存器存储的是定时器计数周期。

2.生成PWM波相关HAL函数
HAL_TIM_PWM_Init() 生成PWM波的配置初始化,需先执行
HAL_TIM_Base_Init()进行定时器初始化
HAL_TIM_PWM_ConfigChannel() 配置PWM输出通道
HAL_TIM_PWM_Start() 启动生成PWM波,需要先执行
HAL_TIM_Base_Start()启动定时器
HAL_TIM_PWM_Stop() 停止生成PWM波
HAL_TIM_PWM_Start_IT() 以中断方式启动生成PWM波,需要先执行
HAL_TIM_Base_Start_IT()启动定时器
HAL_TIM_PWM_Stop_IT() 停止生成PWM波
HAL_TIM_PWM_GetState() 返回定时器状态,与HAL_TIM_Base_GetState()功能相同
__HAL_TIM_ENABLE_OCxPRELOAD() 使能CCR寄存器的预装载功能,为CCR设置的新值在下个UEV事件发生时才更新到CCR寄存器
__HAL_TIM_DISABLE_OCxPRELOAD() 禁止CCR寄存器的预装载功能,为CCR设置的新值立刻更新到CCR寄存器
__HAL_TIM_ENABLE_OCxFAST() 启用一个通道的快速模式
__HAL_TIM_DISABLE_OCxFAST() 禁用一个通道的快速模式
HAL_TIM_PWM_PulseFinishedCallback() 当计数器的值等于CCR寄存器的值时产生输出比较事件这是对应的回调函数

定时器中断事件类型与回调函数
TIM_IT_CC1:
CC1/2通道输入捕获 HAL_TIM_IC_CaptureCallback(htim)
CC1/2通道输出比较 HAL_TIM_OC_DelayElapsedCallback(htim);HAL_TIM_PWM_PulseFinishedCallback(htim);
TIM_IT_UPDATE 更新事件(UEV) HAL_TIM_PeriodElapsedCallback(htim);
TIM_IT_TRIGGER TRGI触发事件 HAL_TIM_TriggerCallback(htim);
TIM_IT_BREAK 短路输入事件 HAL_TIMEx_BreakCallback(htim);
TIM_IT_COM 换相事件 HAL_TIMEx_CommutCallback(htim);

3.使用步骤(生成PWM波)
   

1.在引脚界面选择引脚对应模式为tim16_ch1
    2.将HCLK设置为100MHz,APB1和APB2 timer clocks 设置为50MHz(不是外设时钟),方便计算
    3.在Timer界面选择Tim16,勾选Actived启动Tim16,Channel1设置为PWM Generation CH1;        
       Prescalar预分频值4999,实际分频值为5000,经过预分频后进入计数器的时钟频率就10 kHz,
       Counter Period计数周期,也就是自动重装载寄存器ARR的值,设置为200,所以一个计数周期200ms;
       auto-reload preload,自动重载预装载,即设置TIM14_CR1寄存器中的ARPE位;
       Pulse,PWM脉冲宽度,就是设置16位的捕获/比较寄存器CCR的值。脉冲宽度的值应该小于计数周期的值,这里设置为50,因为计数器的时钟频率是10kHz,所以脉冲宽度为5ms。
       CH Polarity,通道极性,就是CCR与CNT比较输出的有效状态,可以设置为高电平(High)或低电平(Low),此时Tim16每200ms产生一次硬件中断。要时勾选One Pulse Mode则只中断一次。
       NVIC中开启TIM中断,优先级为2;
    4.在程序中必须调用函数启动定时器,再启动定时器的PWM输出。
        HAL_TIM_Base_Start_IT(&htim14); //以中断方式启动TIM14
        HAL_TIM_PWM_Start_IT(&htim14,TIM_CHANNEL_1);//TIM14通道1, 启动生成PWM
    5.在void TIM6_DAC_IRQHandler(void)中会调用回调函数,所以只需要重写回调函数。
    6.重新实现回调函数HAL_TIM_PWM_PulseFinishedCallback(),在此回调函数里编写代码改变占空比。
    {
        if(htim->Instance==TIM16){
            __HAL_TIM_SET_COMPARE(htim,TIM_CHANNEL_1,PulseWidth);//PulseWidth为变量脉冲宽度,之前CUBEMX设置的是50ms;
            Frequency=HAL_TIM_ReadCapturedValue (htim,TIM_CHANNEL_2);//获取CCR当前的值。
		    Frequency =10000/Frequency;
		 CCR=(10000*FreqDiv*Voltage)/Frequency/330;
		 ARR=10000*FreqDiv/Frequency;//如果要动态修改的两个值
		CCR=(CCR>=1)?CCR:1; ARR=( ARR>=2)?ARR:2;//记得写入前对数据范围进行判断。方式写0进入之后,没有脉冲,不会调用回调函数!!!
		__HAL_TIM_SetCompare (&htim3,TIM_CHANNEL_2,CCR);
	 __HAL_TIM_SetAutoreload (&htim3,ARR );
/*
	__HAL_TIM_SetAutoreload(&htim2,ch1);这两个函数可以设置ARR计数器的值;
	__HAL_TIM_SET_AUTORELOAD(&htim2,ch1);
*/
            }}


    如图4-1

4.基于STM32CubeMX使用TIM定时器_第1张图片

4.TIM输出比较:

步骤:
1.LED对应引脚选择为TIMx_CHy;APB1/2时钟定时器为50MHz;timer中设置工作模式为Ouput Compare CH1;
2.Prescaler分频系数49999。Counter默认UP,即增量计数。Counter Period设置为500,即设置ARR寄存器,翻转周期。
3.Mode为Toggle on match.就是在计数器的值与CCR的值相等时使CH1输出翻转。Pulse脉冲宽度,这里设置为300,即300ms;
4.这样设置后,如果CCR和计数器的值匹配后,就会使CH1的输出翻转,且不管CCR的值为多少,方波的占空比都为50%,脉宽总与ARR的值相等。
5.main函数中加入HAL_TIM_Base_Start(&htim3);
                HAL_TIM_OC_Start(&htim4,TIM_CHANNEL_1);
6。下载程序:LED 500ms翻转一次

注意:在定时器初始化函数中,会将对应引脚工作模式设置为GPIO_MODE_AF_PP复用推挽输出,而使用LCD_Init()时G431开发板上的PC会设置为OUT_PP推挽输出,导致不正常工作。

5.输入PWM计算脉冲长短(双通道):
 

原理:输入比较通道CC1捕获上跳沿时,将计数器的值存入寄存器CCR1,同时复位计数器,输入比较通道CC2捕获下降沿时,将计数器的值存入寄存器CCR2,所以寄存器CCR1中的值表示PWM波的周期,CCR2中的值是PWM的脉宽。
步骤:
1.时钟APB1为50MHZ;TIM8时钟源为Internal Clock,引脚PA15设置为TIM8_CH1
2.Conbined Channals选择PWM Inout on Ch1;(CH1和CH2结合起来)
3.Prescaler预分频寄存器值设为4999,所以分频值为10KHz,Counter Period:ARR的值设置为50000,所以TIM8定时器周期应大于输入PWM周期,
4.Polarity Selection :CH1设置为RisingEdge上跳沿捕获,而CH2设置为相反的下降沿捕获,InputFilter设置为0,无需设置滤波,
5.NVIC打开中断,设置优先级
6.HAL_TIM_Base_Start(&htim8);
HAL_TIM_IC_Start_IT(&htim8,TIM_CHANNEL_1);启动TIM8_CH1的IC功能
HAL_TIM_IC_Start_IT(&htim8,TIM_CHANNEL_2);两个通道都要启动
6.重写回调函数void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
 uint16_t IC1_Width=__HAL_TIM_GET_COMPARE(&htim8,TIM_CHANNEL_1);//CH1_CCR寄存器中放的是周期
 uint16_t IC2_Pulse=__HAL_TIM_GET_COMPARE(&htim8,TIM_CHANNEL_2);//CH2_CCR寄存器中放的是脉宽
 uint16_t temp=IC1_Width ;//获取了两个寄存器的值,分别代表周期和脉冲宽度
 if((IC1_Width==0)||(IC2_Pulse==0))return;
 temp=temp%10000;
 LCD_DisplayChar(Line2,319-(12*16),'0'+temp/1000);temp=temp%1000;
 LCD_DisplayChar(Line2,319-(13*16),'0'+temp/100);temp=temp%100;
 LCD_DisplayChar(Line2,319-(14*16),'0'+temp/10);temp=temp%10;
 LCD_DisplayChar(Line2,319-(15*16),'0'+temp);
 temp=IC2_Pulse;
 temp=temp%10000;
 LCD_DisplayChar(Line3,319-(12*16),'0'+temp/1000);temp=temp%1000;
 LCD_DisplayChar(Line3,319-(13*16),'0'+temp/100);temp=temp%100;
 LCD_DisplayChar(Line3,319-(14*16),'0'+temp/10);temp=temp%10;
 LCD_DisplayChar(Line3,319-(15*16),'0'+temp);
}

7.单通道捕获PWM

关于普通的输入模式捕获PWM。主要工作流程:

1、第一次捕获到上升沿,计数器清零,存捕获寄存器值的变量清零,存中断次数的变量清零。改变触发边沿为下降沿触发,并将触发标志位为设置为1,使下次下降沿触发时,能进行相对应的处理。

2、第一次捕获到下降沿,将捕获寄存器(CCR寄存器)的值,中断次数存入相应的变量。同时更改触发边沿为上升沿触发,并将触发标志位为设置为2,使下次上升沿触发时,能进行相对应的处理。

3、第二次捕获到上升沿,再次将捕获寄存器(CCR寄存器)的值,中断次数存入相应的变量。将触发标志设置为0,目的为能够循环捕获。同时捕获完成标志为置1。

 4、在main函数中,使用在while循环,使用if语句进行捕获标志的轮询,从而在捕获完成后进行相应的数据处理。
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim==&htim2)
	{
		switch(ICFlag)
		{
			case 0://第一次上升沿
				__HAL_TIM_SetCounter (htim,0 );//计数器清零
				__HAL_TIM_SET_CAPTUREPOLARITY (htim,TIM_CHANNEL_2,TIM_ICPOLARITY_FALLING);//设置下降沿捕获
			  ICFlag=1;break;
			case 1:
				Count1=HAL_TIM_ReadCapturedValue (htim,TIM_CHANNEL_2);//捕获到下降沿,读出的值为高电平长度,单位为定时器定时一次时长
				__HAL_TIM_SET_CAPTUREPOLARITY (htim,TIM_CHANNEL_2,TIM_ICPOLARITY_RISING);//等待下一个上升沿
				__HAL_TIM_SetCounter (htim,0 );
				ICFlag=2;break;
			case 2:
				Count2=HAL_TIM_ReadCapturedValue (htim,TIM_CHANNEL_2);//读出的值为低电平长度
				ICFlag=0;break;
		}
	}
}
如果不用知道占空比,则不用改变捕获极性,两次上升沿间隔即为周期

你可能感兴趣的:(STM32,stm32)