欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【NUCLEO_F767ZI开发板系列】六、TIM1高级定时器——中断+PWM

程序员文章站 2022-03-13 19:25:53
...

 定时器是一个十分通用的外设,STM32F767的定时器有十几个,包含了基本定时器、通用定时器、高级定时器和低功耗定时器。

一、定时器中断


 配置CubeMX工程:

 1、选择Clock Source里的Internal Clock(内部时钟) 另外一个ETR2是外部触发输入 。

【NUCLEO_F767ZI开发板系列】六、TIM1高级定时器——中断+PWM


2、接着在TIM3 配置页弹出的界面中点击 Parameter Settings 选项卡,Counter Settings配置栏下面的四个选项用来配置定时器的预分频系数,自动装载值,计数模式以及时钟分频因子。TIM1挂载到APB1的时钟总线上,频率为108MHz,所以这里设置成1s。

【NUCLEO_F767ZI开发板系列】六、TIM1高级定时器——中断+PWM


3、 接着再使能定时器更新中断

【NUCLEO_F767ZI开发板系列】六、TIM1高级定时器——中断+PWM


4、再到NVIC的选项卡里设置中断优先级分组:

【NUCLEO_F767ZI开发板系列】六、TIM1高级定时器——中断+PWM

 生成代码,在"tim.c"里定时器1的初始化函数:

TIM_HandleTypeDef htim1;

/* TIM1 init function */
void MX_TIM1_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;

  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 10800-1;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 10000-1;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
}
5、在主循环之前添加代码,开启定时器和定时器中断:

	HAL_TIM_Base_Start_IT(&htim1);
6、在主函数后面的用户代码区写定时器溢出回调函数:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
}
编译下载到开发板就可以看到LED1以一定的频率闪烁了。

二、PWM输出


使用TIM1的CH2_N来输出PWM信号,来控制LED3的亮灭,TIM1的CH2_N在PB14口上,

1、设置IO口复用功能:

【NUCLEO_F767ZI开发板系列】六、TIM1高级定时器——中断+PWM【NUCLEO_F767ZI开发板系列】六、TIM1高级定时器——中断+PWM

2、修改预分频系数和时钟分频因子使输出的频率为1KHz,

【NUCLEO_F767ZI开发板系列】六、TIM1高级定时器——中断+PWM

【NUCLEO_F767ZI开发板系列】六、TIM1高级定时器——中断+PWM

3、关闭定时器中断使能。生成代码

 在定时器初始化的函数中,PWM的初始化部分:

  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 5400;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
4、为了方便后续程序里修改占空比,将pwm初始化的结构体定义为全局变量:

【NUCLEO_F767ZI开发板系列】六、TIM1高级定时器——中断+PWM

5、在"tim.c"后面的用户代码区添加修改占空比的函数并且在  tim.h  文件里声明:

/* USER CODE BEGIN 1 */

void PWM_Pulse_Change(uint16_t num)
{
	sConfigOC.Pulse = num;
	if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
	
	//开启高级定时器PWM开始函数
	HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);
}

/* USER CODE END 1 */
这里需要注意的是:

HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);
这里使用的是通道Channel 2N 。开启这个通道的pwm生成的函数在“stm32f7xx_hal_tim_ex.c”文件中定义的。

6、在 main.c 文件里添加变量:

  /* USER CODE BEGIN 1 */
	
	uint16_t pwm=0;		//修改的PWM的值
	int step;					//控制pwm增或减
	
  /* USER CODE END 1 */
7、主循环前添加:

  /* USER CODE BEGIN 2 */
	
	printf("Hello,Nucleo!\n");		//打印提示信息
	HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);	//初始化pwm通道CH2N
		
  /* USER CODE END 2 */
8、主循环内添加:

		HAL_Delay(30);  
		if(pwm == 0) step = 100;
		if(pwm == 10000) step = -100;
		pwm += step;
		PWM_Pulse_Change(pwm);
编译下载到开发板里,可以看到红色的led3逐渐变量变暗,达到了呼吸灯的效果。

以往经常使用的通用定时器,配制方法虽然差别不大,但是一些功能还是有些差别,比一般定时器功能更加强大:

【NUCLEO_F767ZI开发板系列】六、TIM1高级定时器——中断+PWM

PWM实验里开启Channel 2N通道,最初就被配置成了:

	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
结果LED灯怎么也不亮。上网查找资料也找不到,最终还是去看官方的例程发现了这个函数:

HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);