STM32F407野火霸天虎系列笔记(六)高级定时器

一、前言

        我在学习的过程中,经历过毫无头绪,找到一堆学习资料却不知从何开始的痛苦。我希望我整理的笔记,不光可以方便自己在以后的项目中拿来即用,也希望能够对那些喜欢玩硬件、爱折腾的小伙伴有所帮助。如果你们觉得我的文章对你们有用,欢迎大家点赞+收藏,让我知道,我的工作是有价值的。        

        这篇笔记,综合参考了野火、正点原子、st官方以及网络上的一些资料,然后经过我自己的思考、尝试与实践,从而整理出来的。感谢那些愿意在学习的路上分享自己知识与经验的前辈。

二、代码和理论

(一)、PWM输出编程思路

1.定时器GPIO初始化

选用三个引脚,输出引脚,互补输出引脚,断路输入引脚,配置好引脚相关参数,选择复用功能,再连接好各个引脚的复用功能。

/*定义一个GPIO_InitTypeDef类型的结构体*/
	GPIO_InitTypeDef GPIO_InitStructure;

	/*开启定时器相关的GPIO外设时钟*/
	RCC_AHB1PeriphClockCmd (ADVANCE_OCPWM_GPIO_CLK | ADVANCE_OCNPWM_GPIO_CLK| ADVANCE_BKIN_GPIO_CLK, ENABLE); 
  /* 指定引脚复用功能 */
	GPIO_PinAFConfig(ADVANCE_OCPWM_GPIO_PORT,ADVANCE_OCPWM_PINSOURCE, ADVANCE_OCPWM_AF); 
	GPIO_PinAFConfig(ADVANCE_OCNPWM_GPIO_PORT,ADVANCE_OCNPWM_PINSOURCE,ADVANCE_OCNPWM_AF); 
	GPIO_PinAFConfig(ADVANCE_BKIN_GPIO_PORT,ADVANCE_BKIN_PINSOURCE,ADVANCE_BKIN_AF); 
	
	/* 定时器功能引脚初始化 */															   
	GPIO_InitStructure.GPIO_Pin = ADVANCE_OCPWM_PIN;	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;    
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; 
	GPIO_Init(ADVANCE_OCPWM_GPIO_PORT, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = ADVANCE_OCNPWM_PIN;	
	GPIO_Init(ADVANCE_OCNPWM_GPIO_PORT, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = ADVANCE_BKIN_PIN;	
	GPIO_Init(ADVANCE_BKIN_GPIO_PORT, &GPIO_InitStructure);

2.定时器时基结构体TIM_TimeBaseInitTypeDef初始化

高级定时器属于APB2,内部时钟是168MHZ,在时基结构体中我们设置定时器周期参数为1000,频率为1MHz,使用向上计数方式。因为我们使用的是内部时钟,所以外部时钟采样分频成员不需要设置,重复计数器我们没用到,也不需要设置。

Period(定时器周期)范围是0~65535

ClockDivision(时钟分频)设置定时器时钟CK_INT频率与死区发生器以及数字滤波器采样时钟频率分频比。可以选择1、2、4分频。

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

// 开启TIMx_CLK,x[1,8] 
  RCC_APB2PeriphClockCmd(ADVANCE_TIM_CLK, ENABLE); 

  /* 累计 TIM_Period个后产生一个更新或者中断*/		
  //当定时器从0计数到1023,即为1024次,为一个定时周期,可以自己定义
  TIM_TimeBaseStructure.TIM_Period = 1024-1;
	// 高级控制定时器时钟源TIMxCLK = HCLK=168MHz 
	// 设定定时器频率为=TIMxCLK/(TIM_Prescaler+1)=100000Hz
  TIM_TimeBaseStructure.TIM_Prescaler = 1680-1;	
  // 采样时钟分频,配置死区时间要用到
  TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
  // 计数方式,向上
  TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
  // 重复计数器,没用到不用管
  TIM_TimeBaseStructure.TIM_RepetitionCounter=0;	
	// 初始化定时器TIMx, x[1,8]
	TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure);

3.定时器输出比较结构体TIM_OCInitTypeDef初始化

ChannelPulse是调节占空比的大小可以自己定义

配置完成后要使能通道,和使能定时器

TIM_OCInitTypeDef  TIM_OCInitStructure;


/*PWM模式配置*/
	//配置为PWM模式1,常用的为PWM1/PWM2
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	
	TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
//脉冲宽度,范围为0至65535
  TIM_OCInitStructure.TIM_Pulse = ChannelPulse;
//可选择高电平还是低电平有效,决定着定时器通道有效电平
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
  TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
  TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
  //使能通道1
  TIM_OC1Init(ADVANCE_TIM, &TIM_OCInitStructure);	 
  
	/* 使能通道1重载 */
	TIM_OC1PreloadConfig(ADVANCE_TIM, TIM_OCPreload_Enable);

4.定时器刹车和死区结构体TIM_BDTRInitTypeDef初始化

TIM_BDTRInitTypeDef TIM_BDTRInitStructure;

	/* 自动输出使能,断路、死区时间和锁定配置 */
  TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
  TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
  TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
  TIM_BDTRInitStructure.TIM_DeadTime = 11;
  TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
  TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low;
  TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
  TIM_BDTRConfig(ADVANCE_TIM, &TIM_BDTRInitStructure);
	
	// 使能定时器
	TIM_Cmd(ADVANCE_TIM, ENABLE);	
	
	/* 主动输出使能 */
  TIM_CtrlPWMOutputs(ADVANCE_TIM, ENABLE);

(二)、PWM输入编程思路

1.初始化相关GPOI口(连接通用定时器和高级定时器的)

/*定义一个GPIO_InitTypeDef类型的结构体*/
	GPIO_InitTypeDef GPIO_InitStructure;

	/*开启LED相关的GPIO外设时钟*/
	
	RCC_AHB1PeriphClockCmd (GENERAL_OCPWM_GPIO_CLK, ENABLE); 
	RCC_AHB1PeriphClockCmd (ADVANCE_ICPWM_GPIO_CLK, ENABLE); 	

	/* 定时器复用引脚 */
	GPIO_PinAFConfig(GENERAL_OCPWM_GPIO_PORT,GENERAL_OCPWM_PINSOURCE,GENERAL_OCPWM_AF); 
	GPIO_PinAFConfig(ADVANCE_ICPWM_GPIO_PORT,ADVANCE_ICPWM_PINSOURCE,ADVANCE_ICPWM_AF); 
	
	/* 通用定时器PWM输出引脚 */															   
	GPIO_InitStructure.GPIO_Pin = GENERAL_OCPWM_PIN;	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;    
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; 
	GPIO_Init(GENERAL_OCPWM_GPIO_PORT, &GPIO_InitStructure);
	
	/* 高级控制定时器PWM输入捕获引脚 */
	GPIO_InitStructure.GPIO_Pin = ADVANCE_ICPWM_PIN;	
	GPIO_Init(ADVANCE_ICPWM_GPIO_PORT, &GPIO_InitStructure);

2.通用定时器产生PWM配置

再通用定时器中配置时基结构体和输出结构体初始化

	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	// 开启TIMx_CLK,x[2,3,4,5,12,13,14] 
  RCC_APB1PeriphClockCmd(GENERAL_TIM_CLK, ENABLE); 

  /* 累计 TIM_Period个后产生一个更新或者中断*/		
  //当定时器从0计数到9999,即为10000次,为一个定时周期
  TIM_TimeBaseStructure.TIM_Period = 10000-1;       
	
	// 通用定时器2时钟源TIMxCLK = HCLK/2=84MHz 
	// 设定定时器频率为=TIMxCLK/(TIM_Prescaler+1)=100KHz
  TIM_TimeBaseStructure.TIM_Prescaler = 840-1;	
  // 采样时钟分频
  TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
  // 计数方式
  TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
	
	// 初始化定时器TIMx, x[1,8]
	TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);
	
	/* PWM输出模式配置 */
	/* 配置为PWM模式1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;	    
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	
	/* PWM脉冲宽度 */
  TIM_OCInitStructure.TIM_Pulse = 3000-1;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	/* 使能通道1 */
  TIM_OC1Init(GENERAL_TIM, &TIM_OCInitStructure);	
	/*使能通道1重载*/
	TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
	// 使能定时器
	TIM_Cmd(GENERAL_TIM, ENABLE);	
}

3.高级定时器PWM输入配置

再高级定时器中配置时基结构体,输入捕获结构体,从模式结构体初始化

先选定捕获通道IC1和IC2通道1,捕获周期,通道2,捕获占空比

I2C作为间接输入模式,我们需要配置他的从模式,即从模式复位模式,定时器触发源为TIM_TS_TI1FP1,最后使用函数HAL_TIM_SlaveConfigSynchronization进行配置。



static void TIM_PWMINPUT_Config(void)
{
	//初始化三个结构体,时基结构体,输入捕获结构体,模式结构体
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_ICInitTypeDef  TIM_ICInitStructure;
	
	// 开启TIMx_CLK,x[1,8] 
  RCC_APB2PeriphClockCmd(ADVANCE_TIM_CLK, ENABLE); 

  TIM_TimeBaseStructure.TIM_Period = 0xFFFF-1; 	
	// 高级控制定时器时钟源TIMxCLK = HCLK=168MHz 
	// 设定定时器频率为=TIMxCLK/(TIM_Prescaler+1)=100KHz
  TIM_TimeBaseStructure.TIM_Prescaler = 1680-1;	
  // 计数方式
  TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;	
	// 初始化定时器TIMx, x[1,8]
	TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure);
	
	/* IC1捕获:上升沿触发 TI1FP1 */
  TIM_ICInitStructure.TIM_Channel = ADVANCE_IC1PWM_CHANNEL;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  TIM_ICInitStructure.TIM_ICFilter = 0x0;
  TIM_PWMIConfig(ADVANCE_TIM, &TIM_ICInitStructure);
	
	/* IC2捕获:下降沿触发 TI1FP2 */	
	TIM_ICInitStructure.TIM_Channel = ADVANCE_IC2PWM_CHANNEL;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  TIM_ICInitStructure.TIM_ICFilter = 0x0;
  TIM_PWMIConfig(ADVANCE_TIM, &TIM_ICInitStructure);
	
//当工作在PWM输入模式时,只需要设置触发信号的那一路即可(用于测量周期)
//另一路(用于测量占空比)会有硬件自动设置,不需要再配置
	/* 选择定时器输入触发: TI1FP1 */
  TIM_SelectInputTrigger(ADVANCE_TIM, TIM_TS_TI1FP1);		

  /* 选择从模式: 复位模式 */
  TIM_SelectSlaveMode(ADVANCE_TIM, TIM_SlaveMode_Reset);
  TIM_SelectMasterSlaveMode(ADVANCE_TIM,TIM_MasterSlaveMode_Enable);

  /* 使能高级控制定时器 */
  TIM_Cmd(ADVANCE_TIM, ENABLE);

  /* 使能捕获/比较2中断请求 */
  TIM_ITConfig(ADVANCE_TIM, TIM_IT_CC1, ENABLE);

4.计算测量的频率和占空比,打印出来比较

/**
  * @brief  This function handles TIM interrupt request.
  * @param  None
  * @retval None
  */	
void  ADVANCE_TIM_IRQHandler (void)
{
  /* 清除定时器捕获/比较1中断 */
  TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);

  /* 获取输入捕获值 */
  IC1Value = TIM_GetCapture1(ADVANCE_TIM);
  IC2Value = TIM_GetCapture2(ADVANCE_TIM);	
  printf("IC1Value = %d  IC2Value = %d ",IC1Value,IC2Value);
	
  if (IC1Value != 0)
  {
    /* 占空比计算 */
    DutyCycle = (float)(IC2Value * 100) / IC1Value;

    /* 频率计算 */
    Frequency = 168000000/1680/(float)IC1Value;
		printf("占空比:%0.2f%%   频率:%0.2fHz\n",DutyCycle,Frequency);
  }
  else
  {
    DutyCycle = 0;
    Frequency = 0;
  }
}

你可能感兴趣的:(#,STM32,stm32,嵌入式)