STM32CubeMX_定时器中断_PWM

文章目录

    • 前言
    • STM32CubeMX新建工程
    • 基本定时器配置
    • 生成代码
    • 定时器中断
    • PWM配置
    • 工程代码
    • 微信公众号

前言

STM32CubeMX_环境搭建_GPIO_外部中断
上节整理的是GPIO和外部中断, 这一节整理下定时器中断和PWM的使用. 仍用NUCLEO-F767ZI的板子, 使用定时器3的中断实现LED2(Blue, PB7)的翻转, 然后刚好LED2的PB7又是TIM4_CH2, 可以用PWM来控制LED的亮度. 好, 先来看基本定时器的配置.

STM32CubeMX新建工程

步骤如下:

  • MCU选择: 打开 STM32CubeMX, 点击 ACCESS TO MCU SELECTOR, 选择 STM32F767ZI
  • 调试端口配置为SWD: Pinout & Configuration -> System Core -> SYS -> Debug 选择 Serial Wire
  • 单击引脚图中的PB7, 选择 GPIO_Output, 右键选择Enter User Label, 输入LED2
  • Pinout & Configuration -> System Core -> RCC -> HSE 选择 Crystal/Ceramic Resonator
  • Clock Configuration:
    STM32CubeMX_定时器中断_PWM_第1张图片

以上步骤不太熟悉的话, 可以参考上节 STM32CubeMX_环境搭建_GPIO_外部中断

基本定时器配置

Pinout & Configuration -> Timers -> TIM3 -> Clock Source 选择 Internal Clock.
Timer3挂到的是上图中的APB1 Timer clocks(MHz), 108MHz, 预分频(Prescaler)设为108-1, 这样时钟变成1MHz, 从0向上计数(Up), 记到自动重载寄存器(AutoReload Register)的值10000-1也就是10K/1M = 10ms就触发中断:
STM32CubeMX_定时器中断_PWM_第2张图片
Pinout & Configuration -> System Core -> NVIC中勾选 TIM3 global interrupt, 优先级就不设置保持默认了:
STM32CubeMX_定时器中断_PWM_第3张图片

生成代码

Project Manager -> Project -> Browse 选择工程位置(Project Location), 填入工程名(Project Name), Toolchain/IDE 选择 MDK-ARM.

Project Manager -> Code Generator -> 勾选Copy only the necessary library files, 还有Generate peripheral initialization as a pair of .c/.h files per periphral

点击右上角 GENERATE CODE 按钮生成代码, 打开工程.

Keil 点击魔术棒或者Project -> Options for Target ..., 默认配置DebugST-link Debugger, 点击Setting -> Flash Download -> 勾选Reset and Run, 这样下载后可以自动复位运行.

定时器中断

main.c 中开启定时器中断:

  /* USER CODE BEGIN 2 */	
	//Starts the TIM Base generation in interrupt mode.
	HAL_TIM_Base_Start_IT(&htim3);		
  /* USER CODE END 2 */

至于中断函数怎么写:

  • startup_stm32f767xx.s 文件中可以找到中断向量表 DCD TIM3_IRQHandler ; TIM3. 按F12跳转.
  • stm32f7xx_it.cvoid TIM3_IRQHandler(void), 调用了HAL_TIM_IRQHandler(&htim3);, 按F12跳转.
  • stm32f7xx_hal_tim.cvoid HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim) 中找到 /* TIM Update event */ 一段, 发现调用了HAL_TIM_PeriodElapsedCallback(htim);, 按F12跳转.
  • __weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim), __weak修饰的, 找个地方补全 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) 这个函数即可.

stm32f7xx_it.c 中:

/* USER CODE BEGIN 1 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
	//if(htim->Instance == htim3.Instance)
	static uint32_t count_10ms = 0;
	if(htim == &htim3) {	
		if(count_10ms >= 99) {
			count_10ms = 0;
			HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
		}
	}
	++count_10ms;
}
/* USER CODE END 1 */

10ms中断一次, 计数100次翻转1次LED的状态, 调试运行, 发现板子上的蓝灯1s闪烁一次, 符合预期.

PWM配置

上面说到 LED2PB7又是TIM4_CH2, 设置定时器4周期为2s, 1s翻转一次电平就可以实现上面同样的效果.
注释掉上小节的 HAL_TIM_PeriodElapsedCallback 函数, 关闭Keil, 打开STM32CubeMX, 单击PB7, 选择弹出的TIM4_CH2(引脚重映射), 然后配置TIM4:
STM32CubeMX_定时器中断_PWM_第4张图片
TIM4时钟源依然是APB1 Timer clocks(MHz), 108MHz, 预分频(Prescaler)设为10800-1, 这样时钟变成10KHz, 从0向上计数(Up), 记到自动重载寄存器(AutoReload Register)的值20000-1也就是20K/10K = 2s周期, 而下面的 Pulse 填入10000 或者10000-1 表示计数到10000翻转一次电平, 总共下来是 2s周期, 10000/20000 = 50%的占空比. main.c 中填入:

  /* USER CODE BEGIN 2 */
	//HAL_TIM_Base_Start_IT(&htim3);
		HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2);
  /* USER CODE END 2 */

编译下载, 可以看到板子上蓝灯1s闪烁一次.

关闭Keil, 打开STM32CubeMX, 配置TIM4为 1ms周期(1KHz), 50%占空比:
STM32CubeMX_定时器中断_PWM_第5张图片
重新生成代码, 编译下载, 灯常亮, 亮度弱了些.

事实上, 占空比不变, 频率的改变叫PFM(Pulse Frequency Modulation, 脉冲频率调制)更合适一点, 常用于步进电机的调速或者无源蜂鸣器的音调调节.

而频率不变, 占空比的改变叫PWM(Pulse Width Modulation, 脉冲宽度调制), 常用于直流电机的调速.

在电源设计中, PWM或者PFM都是很常用的. 在MCU的实现上就差不太多了, 两个数字的调整而已.

下面main.c写函数设置pwm的占空比:

/* USER CODE BEGIN 0 */
void pwm_set_value(uint16_t pwm_value) {
	TIM_OC_InitTypeDef sConfigOC = {0};
	
	HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_2);
	sConfigOC.OCMode = TIM_OCMODE_PWM1;
  	sConfigOC.Pulse = pwm_value;
  	sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  	sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  	if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  	{
    	Error_Handler();
	}
  	HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2);
}

void pwm_set_value2(uint16_t pwm_value) {
	TIM4->CCR2 = pwm_value;
}
/* USER CODE END 0 */

pwm_value的值在[0, 1000]之间, pwm_set_valuepwm_set_value2 两个函数都可以设置占空比, main函数中补充:

  /* USER CODE BEGIN 2 */
  		//HAL_TIM_Base_Start_IT(&htim3);
		HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2);	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		static uint16_t value = 0;
		value = (value == 1000) ? 0 : (value+10);	//++value, not value++
		pwm_set_value2(value);
		HAL_Delay(10);
  }
  /* USER CODE END 3 */

编译下载, 可以看到板子上蓝灯1s内由暗到亮. 当然我们也可以在定时器3的中断函数中实现:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {	//10ms
	static uint16_t value = 0;
	value = (value == 1000) ? 0 : (value+10);	//++value, don't value++
	pwm_set_value2(value);
}

效果是一样的.

工程代码

https://download.csdn.net/download/weifengdq/11959640

微信公众号

欢迎扫描二维码关注本人微信公众号, 及时获取或者发送给我最新消息:
在这里插入图片描述

你可能感兴趣的:(STM32)