STM32-高级定时器

以STM32F429为例。

目录

高级定时器

功能框图

时钟源

内部时钟源CK_INT

外部时钟模式1:外部输入引脚TIx(x=1/2/3/4)

外部时钟模式2:外部触发输入ETR

内部触发输入ITRx(x=1/2/3/4)

控制器

时基单元

输入捕获

输出比较

死区发生器

输出控制

断路功能

实验环节:PWM互补输出

常规操作

TIM8配置

测试环节

实验操作及现象


高级定时器

高级定时器比通用定时器增加了可编程死区互补输出、重复计数器、带刹车(断路)功能,这些功能都是针对工业电机控制方面。

功能框图

16位向上、向下、向上/向下自动重装载计数器。

16位可编程预分频器,1~65536。

多达4个独立通道,用于:

        输入捕获

        输出比较

        PWM产生(边沿对齐模式和中心对齐模式)

        单脉冲模式输出

具有可编程死区时间的互补输出。

用外部信号控制定时器的同步电路,并将多个定时器互连在一起。

重复计数器,仅在给定次数的计数器循环后更新定时器寄存器。

中断输入,使定时器的输出信号处于复位状态或已知状态。

中断/DMA生成以下事件:

        更新:计数器溢出/下溢,计数器初始化(由软件或内部/外部触发)

        触发事件(计数器启动、停止、初始化或由内部/外部触发计数)

        输入捕获

        输出比较

        断路输入

支持增量(正交)编码器和霍尔传感器电路的定位目的。

触发输入外部时钟或逐周期电流管理。

时钟源

高级控制定时器可选四种时钟源:

内部时钟源CK_INT

外部时钟模式1:外部输入引脚TIx(x=1/2/3/4)

外部时钟模式2:外部触发输入ETR

内部触发输入ITRx(x=1/2/3/4)

内部时钟源CK_INT

时钟信号来自芯片内部,为主频168M(STM32F407为例)。一般情况下都是使用内部时钟。当从模式控制寄存器TIMx_SMCR:SMS位为000时使用内部时钟。

外部时钟模式1:外部输入引脚TIx(x=1/2/3/4)

时钟信号来自定时器的输入通道TI1/2/3/4,即TIMx_CH1/2/3/4。具体使用哪一路信号,由TIM_CCMRx:CCxS[1:0]配置。CCMR1控制TI1/2,CCMR2控制TI3/4。

如果来自外部时钟信号的频率过高或混杂有高频干扰信号的话,就需要使用滤波器对信号重新采样,来达到降频或者去除高频干扰的目的,具体由TIMx_CCMRx:ICxF[3:0]配置。

边沿检测的信号来自于滤波器的输出,在成为触发信号前需要进行边沿检测,决定是上升沿有效还是下降沿有效,具体由TIMx_CCER:CCxP和CCxNP位配置。

触发源有两个:滤波后的定时器输入1(TI1FP1)、滤波后的定时器输入2(TI1FP2),具体由TIMx_SMCR:TS[2:0]配置。

选定了触发源信号后,需要把信号连接到TRGI引脚,让触发信号成为外部时钟模式1的输入,最终等于CK_PSC,然后驱动计数器CNT计数。具体由TIMx_SMCR:SMS[2:0]配置,000时为外部时钟模式1。

经过上面的5个步骤后,最后只需使能计数器开始计数,外部时钟模式1的配置就算完成了。具体由TIMx_CR1:CEN位配置。

外部时钟模式2:外部触发输入ETR

时钟信号来自定时器的特定输入通道TIMx_ETR,只有一个。

外部触发极性来自ETR引脚输入的信号,可以选择上升沿有效还是下降沿有效,具体由TIMx_SMCR:ETP位配置。

由于ETRP的信号频率不得超过TIMx_CLK的1/4,当触发信号的频率很高时必须使用分频器来降频,具体由TIMx_SMCR:ETPS[1:0]配置。

如果ETRP的信号频率过高或混杂有高频干扰信号的话,就需要使用滤波器对信号重新采样,来达到降频或者去除高频干扰的目的,具体由TIMx_SMCRx:ETF[3:0]配置。fDTS是由内部时钟CK_INT分频得到,具体由TIMx_CR1:CKD[1:0]配置。

经过滤波器滤波的信号连接到ETPF引脚后,触发信号成为外部时钟模式2的输入,最终等于CK_PSC,然后驱动计数器CNT计数。具体由TIMx_SMCR:ECE位配置,1时为外部时钟模式2。

经过上面的5个步骤后,最后只需使能计数器开始计数,外部时钟模式2的配置就算完成了。具体由TIMx_CR1:CEN位配置。

内部触发输入ITRx(x=1/2/3/4)

内部触发输入是使用一个定时器作为另一个定时器的预分频器。硬件上高级控制定时器和通用定时器在内部连接在一起,可以实现定时器同步和级联。主模式的定时器可以对从模式定时器只需复位、启动、停止或提供时钟。

高级控制定时器和部分通用定时器(TIM2~TIM5)可以设置为主模式或从模式,TIM9和TIM10可以设置为从模式。

如图,主模式定时器TIM1为从模式定时器TIM2提供时钟,即TIM1用作TIM2的预分频器。

控制器

触发控制器用来针对片内外设输出触发信号,比如为其它定时器提供时钟和触发DAC/ADC转换。

编码器接口专门针对编码器计数而设计。

从模式控制器可以控制计数器复位、启动、递增/递减、计数。

时基单元

高级控制定时器时基单元组成:计数器寄存器(CNT,16位有效)、预分频器寄存器(PSC,16位有效)、自动重装载寄存器(ARR,16位有效)、重复计数器寄存器(RCR,8位有效,高级定时器专有)。

PSC预分频器寄存器有一个输入时钟CK_PSC和一个输出时钟CK_CNT。输入时钟CK_PSC就是时钟源的输出,输出时钟CK_CNT用来驱动计数器CNT计数。通过设置预分频器PSC的值可以得到不同的CK_CNT,值为1~65536分频。

三种计数模式:递增、递减、中心对齐。

递增计数模式:计数器从0开始计数,每一CK_CNT脉冲,计数器就加1,直到计数器的值与ARR值相等,然后计数器又从0开始计数并生成计数器上溢事件,如此循环。如果禁用重复计数器,在计数器生成上溢事件就马上生成更新事件(UEV);如果使能重复计数器,每生成一次上溢事件,重复计数器就减1,直到减为0时才会生成更新事件(UEV)。

递减计数模式:计数器从ARR值开始计数,每一CK_CNT脉冲,计数器就减1,直到计数器的值减为0,然后计数器又从ARR值开始计数并生成计数器下溢事件,如此循环。如果禁用重复计数器,在计数器生成下溢事件就马上生成更新事件(UEV);如果使能重复计数器,每生成一次下溢事件,重复计数器就减1,直到减为0时才会生成更新事件(UEV)。

中心对齐模式:计数器从0开始递增,直到计数器的值与(ARR-1)值相等,生成计数器上溢事件。然后计数器又从ARR开始递减,直到计数器的值为1时生成计数器下溢事件。然后重新重0开始,如此循环。每次发送计数器上溢和下溢事件都会生成更新事件。

ARR自动重装载寄存器用来存放与CNT比较值。如果CNT值等于ARR值,就递减重复计数器。可以通过TIMx_CR1:ARPE位控制自动重装载影子寄存器功能,如果ARPE位置1,只有在事件更新时才把TIMx_ARR值赋给影子寄存器。如果ARPE位置0,则修改TIMx_ARR值时马上赋给影子寄存器。

在基本/通用定时器发生上溢/下溢事件时直接就生成更新事件,但对于高级控制定时器在硬件结构上多出了RCR重复计数器寄存器,在定时器发生上溢/下溢事件会递减重复计数器的值,当重复计数器的值为0时才生成更新事件。在发生N+1个上溢/下溢事件时产生更新事件(N为RCR的值)。

输入捕获

输入捕获可以对输入的信号上升沿、下降沿或双边沿进行捕获,常用的有测量输入信号的脉宽和测量PWM输入信号的频率和占空比。

大概原理是当捕获到信号的跳变沿时,把CNT计数器的值锁存到捕获寄存器CCR中,把前后两次捕获到的CCR寄存器中的值相减,就可以算出脉宽和频率。如果捕获的脉宽的时间长度超过捕获定时器的周期,就会发生溢出,需要额外做处理。

TIx为输入通道,需要被测量的信号从定时器的外部引脚TIMx_CH1/2/3/4进入

当输入的信号存在高频干扰时,需要对输入信号进行滤波,根据采样定律(采样频率必须大于或等于两倍的输入信号),比如输入信号为1M,存在高频信号干扰时就要进行滤波,可以设置采样频率为2M,这样可以在保证采样到有效信号的基础上把高于2M的高频干扰信号过滤掉。

输入滤波器的配置由TIMx_CR1:CKD[1:0]和TIMx_CCMR1/2:ICxF[3:0]控制。根据ICxF位的描述,采样频率Fsample可以由Fck_int(内部时钟)和Fdts(Fck_int经过分频后的频率,分频因子由CKD[1:0]决定,1/2/4分频)分频后的时钟提供。

边沿检测器用来设置信号在捕获时什么边沿有效(上升沿、下降沿、双边沿),具体由TIMx_CCER:CCxP、CCxNP决定。

捕获通道:IC1/2/3/4。每个捕获通道都有对应的捕获寄存器CCR1/2/3/4,当发生捕获时,计数器CNT的值就会被锁存到捕获寄存器中。

输入通道TIx是用来输入信号的,捕获通道ICx是用来捕获输入信号的通道。一个输入通道的信号可以同时输入给两个捕获通道。比如TI1的信号经过滤波和边沿检测器后TI1FP1和TI1FP2可以进入到捕获通道IC1和IC2。输入通道和捕获通道的映射关系具体由TIMx_CCMR:CCxS[1:0]配置。

ICx的输出信号会经过预分频器,用于决定发生多少个事件时进行一次捕获。具体由TIMx_CCMR:ICxPSC配置。如果希望捕获信号的每一个边沿,则不分频。

经过预分频器的信号ICxPS是最终被捕获的信号,当发生捕获时(第一次),计数器CNT的值会被锁存到捕获寄存器TIMx_CCR中,还会产生CCxI中断,相应的中断位CCxIF(在SR寄存器中)会被置位,通过软件或读取CCR的值可以将CCxIF清0。如果发生第二次捕获(即重复捕获,CCR寄存器中已捕获到计数器值且CCxIF标志已置1),则捕获溢出标志位CCxOF(在SR寄存器中)会被置位,CCx_OF只能通过软件清零

输出比较

输出比较就是通过定时器的外部引脚对外输出控制信号

输出比较八种模式:冻结、将通道x(x=1/2/3/4)设置为匹配时输出有效电平、将通道x(x=1/2/3/4)设置为匹配时输出无效电平、翻转、强制变为无效电平、强制变为有效电平、PWM1和PWM2。具体有寄存器CCMRx:OCxM[2:0]配置,PWM模式是输出比较的特例,使用的也最多。

当计数器CNT的值跟比较寄存器CCR的值相等时,输出参考信号OCxREF的信号极性就会发生改变(OCxREF=1,是有效电平;OCxREF=0,是无效电平),并且会产生比较中断CCxl,SR寄存器中的标志位CCxIF会置位。然后OCxREF再经过一系列的控制后就成为真正的输出信号OCx/OCxN。

输出比较的输出信号最终是通过定时器的外部IO来输出的,分别是CH1/2/3/4,其中前面三个通道还有互补的输出通道CH1N/2N/3N。

死区发生器

在生成的参考信号OCxREF的基础上,可以插入死区时间,用于生成两路互补的输出信号OCx和OCxN。死区时间的大小具体由BDTR:DTG[7:0]配置。死区时间的大小必须根据与输出信号相连接的器件及其特性来调整。

举个例子:带死区的PWM信号的应用,以一个半桥驱动电路为例。

在这个半桥驱动电路,Q1导通、Q2截止。如果想让Q1截止、Q2导通,肯定是先让Q1截止一段时间,再等待一段时间才让Q2导通,这个等待时间就是死区时间。

因为Q1关闭需要时间(由MOS管的工艺决定),如果Q1关闭后马上打开Q2,那么此时一段时间内相当于Q1和Q2都导通了,电路会短路。

输出控制

在输出比较的输出控制中,参考信号OCxREF在经过死区发生器后会产生两路带死区的互补信号OCx_DT和OCxN_DT(通道1~3才有互补信号,通道4没有),这两路带死区的互补信号然后进入输出控制电路。如果没有加入死区控制(不经过死区发生器),那么进入输出控制电路的信号就直接是OCxREF。

进入输出控制电路的信号会被分为两路(一路为原始信号,一路为被反向的信号),具体由CCER:CCxP、CCxNP位控制。经过极性选择的信号是否由OCx引脚输出到外部引脚CHx/CHxN则由CCER:CxE/CxNE位配置。

如果加入了断路(刹车)功能,则断路和死区寄存器TIMx_BDTR:MOE、OSSI和OSSR位会共同影响输出的信号。

断路功能

断路功能就是电机控制的刹车功能。使能断路功能时,根据相关控制位状态修改输出信号电平。在任何情况下,OCx和OCxN输出都不能同时为有效电平,这关系到电机控制常用的H桥电路结构原因。

断路源可以是时钟故障事件,其内部复位时钟控制器的时钟安全系统(CSS)生成,也可以是外部断路输入IO,两者是或运算关系。

系统复位启动都默认关闭断路功能,将断路和死区寄存器TIMx_BDTR:BKE=1,使能断路功能。可通过TIMx_BDTR:BKP位设置断路输入引脚的有效电平,为1时输入BRK为高电平有效,否则低电平有效。

发生断路时,将产生以下效果:

TIMx_BDTR:MOE主输出模式使能位被清零,输出处于无效、空闲或复位状态。

根据相关控制位状态去控制输出通道引脚电平;当使能通道互补输出时,会根据情况自动控制输出通道电平。

将TIMx_SR:BIF位置1,并可产生中断和DMA传输请求。

如果TIMx_BDTR:AOE自动输出使能位置1,则MOE位会在发生下一个UEV事件时自动再次置1。

实验环节:PWM互补输出

常规操作

配置按键KEY1和KEY2。

TIM8配置

TIM8_CH1:OCPWM:PC6 

TIM8_CH1N:OCNPWM:PA5

TIM8_BKIN:BKIN:PA6

TIM_HandleTypeDef htim8;

void MX_TIM8_Init(void)
{
	TIM_ClockConfigTypeDef 			sClockSourceConfig = {0};
	TIM_MasterConfigTypeDef 		sMasterConfig = {0};
	TIM_OC_InitTypeDef 				sConfigOC = {0};
	TIM_BreakDeadTimeConfigTypeDef 	sBreakDeadTimeConfig = {0};

	htim8.Instance 					= TIM8;
	htim8.Init.Prescaler 			= 167;
	htim8.Init.CounterMode 			= TIM_COUNTERMODE_UP;
	htim8.Init.Period 				= 999;
	htim8.Init.ClockDivision 		= TIM_CLOCKDIVISION_DIV1;
	htim8.Init.RepetitionCounter 	= 0;	// 重复计数器
	htim8.Init.AutoReloadPreload 	= TIM_AUTORELOAD_PRELOAD_ENABLE;
	if (HAL_TIM_Base_Init(&htim8) != HAL_OK)
	{
		Error_Handler();
	}
	
	sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
	if (HAL_TIM_ConfigClockSource(&htim8, &sClockSourceConfig) != HAL_OK)
	{
		Error_Handler();
	}
	if (HAL_TIM_PWM_Init(&htim8) != HAL_OK)
	{
		Error_Handler();
	}
	
	sMasterConfig.MasterOutputTrigger 	= TIM_TRGO_RESET;
	sMasterConfig.MasterSlaveMode 		= TIM_MASTERSLAVEMODE_DISABLE;
	if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK)
	{
		Error_Handler();
	}
	
	sConfigOC.OCMode 		= TIM_OCMODE_PWM1;			// PWM1为跳变后电平,PWM2为跳变前电平
	sConfigOC.Pulse 		= 500;						
	sConfigOC.OCPolarity 	= TIM_OCPOLARITY_HIGH;		// 达到跳变值Pulse,电平跳变为高电平
	sConfigOC.OCNPolarity 	= TIM_OCNPOLARITY_HIGH;		// 达到跳变值Pulse,电平跳变为高电平
	sConfigOC.OCFastMode 	= TIM_OCFAST_DISABLE;
	sConfigOC.OCIdleState 	= TIM_OCIDLESTATE_SET;		// 空闲状态下经过死区时间后定时器通道输出高电平
	sConfigOC.OCNIdleState 	= TIM_OCNIDLESTATE_RESET;	// 空闲状态下经过死区时间后定时器通道输出低电平
	if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
	{
		Error_Handler();
	}
	
	sBreakDeadTimeConfig.OffStateRunMode 	= TIM_OSSR_ENABLE;			// 运行模式下的关闭状态选择
	sBreakDeadTimeConfig.OffStateIDLEMode 	= TIM_OSSI_ENABLE;  		// 空闲模式下的关闭状态选择
	sBreakDeadTimeConfig.LockLevel 			= TIM_LOCKLEVEL_1;			// 锁定级别配置,(不能写入某些寄存器的某些位,防止意外修改)
	sBreakDeadTimeConfig.DeadTime 			= 11;               		// 死区持续时间
	sBreakDeadTimeConfig.BreakState 		= TIM_BREAK_ENABLE;
	sBreakDeadTimeConfig.BreakPolarity 		= TIM_BREAKPOLARITY_LOW;	// 断路输入通道BRK极性,低电平触发刹车
	sBreakDeadTimeConfig.AutomaticOutput 	= TIM_AUTOMATICOUTPUT_ENABLE;
	if (HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig) != HAL_OK)
	{
		Error_Handler();
	}
  
	HAL_TIM_MspPostInit(&htim8);

	/* 定时器通道1输出PWM */
    HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);
    /* 定时器通道1互补输出PWM */
    HAL_TIMEx_PWMN_Start(&htim8, TIM_CHANNEL_1);
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	if(tim_baseHandle->Instance==TIM8)
	{
		__HAL_RCC_TIM8_CLK_ENABLE();
		__HAL_RCC_GPIOA_CLK_ENABLE();
		
		/**TIM8 GPIO Configuration
		PA6     ------> TIM8_BKIN
		*/
		GPIO_InitStruct.Pin 		= GPIO_PIN_6;
		GPIO_InitStruct.Mode 		= GPIO_MODE_AF_PP;
		GPIO_InitStruct.Pull 		= GPIO_NOPULL;
		GPIO_InitStruct.Speed 		= GPIO_SPEED_FREQ_LOW;
		GPIO_InitStruct.Alternate 	= GPIO_AF3_TIM8;
		HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	}
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	if(timHandle->Instance==TIM8)
	{
		__HAL_RCC_GPIOA_CLK_ENABLE();
		__HAL_RCC_GPIOC_CLK_ENABLE();
		
		/**TIM8 GPIO Configuration
		PA5     ------> TIM8_CH1N
		PC6     ------> TIM8_CH1
		*/
		GPIO_InitStruct.Pin 		= GPIO_PIN_5;
		GPIO_InitStruct.Mode 		= GPIO_MODE_AF_PP;
		GPIO_InitStruct.Pull 		= GPIO_NOPULL;
		GPIO_InitStruct.Speed 		= GPIO_SPEED_FREQ_LOW;
		GPIO_InitStruct.Alternate 	= GPIO_AF3_TIM8;
		HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	
		GPIO_InitStruct.Pin 		= GPIO_PIN_6;
		GPIO_InitStruct.Mode 		= GPIO_MODE_AF_PP;
		GPIO_InitStruct.Pull 		= GPIO_NOPULL;
		GPIO_InitStruct.Speed 		= GPIO_SPEED_FREQ_LOW;
		GPIO_InitStruct.Alternate	= GPIO_AF3_TIM8;
		HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
	}
}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{
	if(tim_baseHandle->Instance==TIM8)
	{
		__HAL_RCC_TIM8_CLK_DISABLE();
	
		/**TIM8 GPIO Configuration
		PA5     ------> TIM8_CH1N
		PA6     ------> TIM8_BKIN
		PC6     ------> TIM8_CH1
		*/
		HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6);	
		HAL_GPIO_DeInit(GPIOC, GPIO_PIN_6);
	}
}

测试环节

__IO uint16_t ChannelPulse = 500;

void test(void)
{
	初始化
	
	while (1)
    {
        /* 扫描KEY1 */
        if (Key_Scan(KEY1_GPIO_PORT, KEY1_PIN) == KEY_ON)
        {
            /* 增大占空比 */
            if (ChannelPulse < 950)
            {
                ChannelPulse += 50;
            }
            else
            {
                ChannelPulse = 1000;
            }

            __HAL_TIM_SetCompare(&htim8, TIM_CHANNEL_1, ChannelPulse);
        }

        /* 扫描KEY2 */
        if (Key_Scan(KEY2_GPIO_PORT, KEY2_PIN) == KEY_ON)
        {
            /* 减小占空比 */
            if (ChannelPulse >= 50)
            {
                ChannelPulse -= 50;
            }
            else
            {
                ChannelPulse = 0;
            }

            __HAL_TIM_SetCompare(&htim8, TIM_CHANNEL_1, ChannelPulse);
        }
    }
}

实验操作及现象

将PC6(OC)和PA5(OCN)引脚接在示波器的两个输入通道上(注意共地),将PA6(BKIN)接在带上拉的输入按键上(保持3.3V高电平)。

可观察示波器波形。

按下KEY1和KEY2按键可增加或减少PWM波形的占空比大小,可实现0%到100%的波形输出。

控制断路输入引脚PA6为低电平,两个通道保持直接输出相反电平。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值