当前位置:   article > 正文

STM32F4 TIM更新中断与PWM输出(HAL库)_stm32f4 hal tim

stm32f4 hal tim

概述

STM32F4的定时器分配:
通用定时器:TIM2~TIM5 & TIM9~TIM14;
高级定时器:TIM1 & TIM8;
基本定时器:TIM6 & TIM7.

TIM基本初始化

TIM时钟初始化

/* TIMx RCC时钟使能 */
__HAL_RCC_TIMx_CLK_ENABLE();
/* TIMx RCC时钟失能 */
__HAL_RCC_TIMx_CLK_DISABLE();
  • 1
  • 2
  • 3
  • 4

TIM参数初始化

TIM初始化函数

/* TIM初始化
   参数:
   (TIM_HandleTypeDef*)htim - TIM 句柄
   返回:
   HAL_OK - 初始化成功
   HAL_ERROR - 当 htim = NULL,将返回HAL_ERROR. */
HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim);

/* TIM复位 */
HAL_StatusTypeDef HAL_TIM_Base_DeInit(TIM_HandleTypeDef *htim);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

TIM句柄

typedef struct { 
    
    /* TIM实例引用(TIM2,TIM3...) */
    TIM_TypeDef *Instance;
    
    /* TIM初始化结构体 */
    TIM_Base_InitTypeDef Init;
    
    /* 活跃通道(PWM相关),取值有:
       HAL_TIM_ACTIVE_CHANNEL_1
       HAL_TIM_ACTIVE_CHANNEL_2
       HAL_TIM_ACTIVE_CHANNEL_3
       HAL_TIM_ACTIVE_CHANNEL_4 */
    HAL_TIM_ActiveChannel Channel; 
    
    /* DMA相关 */
    DMA_HandleTypeDef *hdma[7]; 
    
    /* 状态标识 */
    HAL_LockTypeDef Lock; 
    __IO HAL_TIM_StateTypeDef State;
    
} TIM_HandleTypeDef;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

TIM初始化结构体

typedef struct {
    
    /* 预分频系数(将写入TIMx->PSC寄存器) */
    uint32_t Prescaler;
    
    /* 计数模式,取值有:
       TIM_COUNTERMODE_UP - 向上计数(计数递增,从 0 递增至 Period值) 
       TIM_COUNTERMODE_DOWN - 向下计数(计数递减,从 Period值 递减至 0) 
       TIM_COUNTERMODE_CENTERALIGNED1 - 中心对齐模式1
       TIM_COUNTERMODE_CENTERALIGNED2 - 中心对齐模式2
       TIM_COUNTERMODE_CENTERALIGNED3 - 中心对齐模式3 */
    uint32_t CounterMode;
    
    /* 计数器重装载值(将写入TIMx->ARR寄存器) */
    uint32_t Period;
    
    /* 时钟分频因子,取值有:
       TIM_CLOCKDIVISION_DIV1 - 1分频
       TIM_CLOCKDIVISION_DIV2 - 2分频
       TIM_CLOCKDIVISION_DIV3 - 3分频 */
    uint32_t ClockDivision;
    
    /* 重复计数寄存器值,用于高级定时器 */
    uint32_t RepetitionCounter;
    
    /* 计数器自动重载预装载使能,取值有:
       TIM_AUTORELOAD_PRELOAD_ENABLE - 自动重载预装载使能
       TIM_AUTORELOAD_PRELOAD_DISABLE - 自动重载预装载失能 */
    uint32_t AutoReloadPreload;
    
} TIM_Base_InitTypeDef;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

注意:
计数器自动重载预装载使能/失能(TIM_AUTORELOAD_PRELOAD_ENABLE/DISABLE)并非指开启/关闭定时器的循环定时,而是指开启/关闭自动重载预装载缓冲寄存器自动重载预装载缓冲寄存器又称影子寄存器,可作为自动重装载寄存器TIMx->ARR与计数器TIMx->CNT之间的进一步计数值缓存。
AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE时,定时器定时一个周期后,计数器TIMx->CNT直接读取自动重装载寄存器TIMx->ARR的值作为下一次的计数值。此时修改TIMx->ARR的值将在计数器下一次重装载计数值时生效
AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE时,自动重载预装载寄存器(影子寄存器)将作为TIMx->ARRTIMx->CNT之间的缓存。定时器定时一个周期后,TIMx->CNT首先读取影子寄存器的值作为下一次的计数值,影子寄存器再读取TIMx->ARR的值(注意先后,TIMx->CNT先于影子寄存器读取)。此时修改TIMx->ARR的值将在计数器下下次重装载计数值时生效

只要处于使能状态,定时器总会循环定时

定时器溢出时间的计算:

/* Period - 计数器自动重装载值
   Prescaler - 预分频系数 
   Ft - 定时器的时钟频率(MHz). 例如TIM3挂载在APB1时钟桥上,Ft = HCLK/2 . */
Tout = ((Period + 1)*(Prescaler + 1))/Ft (us)
  • 1
  • 2
  • 3
  • 4

Msp初始化回调函数

 调用HAL_TIM_Base_Init()初始化TIM时,会调用Msp初始化回调函数。一般在Msp初始化回调函数中实现 时钟使能、NVIC配置、中断配置 等。

/* TIM初始化回调函数 */
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim) {
    ...
    // 时钟使能;
    // NVIC配置;
    // 中断配置;
    ...
}

/* TIM复位回调函数 */
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim) {
    ...
    // 时钟复位;
    // NVIC复位;
    // 中断配置复位;
    ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

TIM使能

/* 使能htim句柄对应的TIM (直接写入寄存器)
   注意:调用 __HAL_TIM_ENABLE() 之后对应的定时器将开启计数 */
__HAL_TIM_ENABLE(htim);

/* 失能htim句柄对应的TIM (直接写入寄存器)
   注意:调用 __HAL_TIM_DISABLE() 之后对应的定时器将关闭计数 */
__HAL_TIM_DISABLE(htim);

/* 定时器开始定时(对 __HAL_TIM_ENABLE(htim) 的复杂封装) */
HAL_TIM_Base_Start(TIM_HandleTypeDef* htim);

/* 定时器停止定时(对 __HAL_TIM_DISABLE(htim) 的复杂封装) */
HAL_TIM_Base_Stop(TIM_HandleTypeDef* htim);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

TIM计数器操作

TIM定时参数设置

/* 直接设置TIM的预分频值(直接写入寄存器) */
__HAL_TIM_SET_PRESCALER(TIM_HandleTypeDef* htim,uint32_t psc);

/* 动态设置TIM的自动重装载值(直接写入寄存器) */
__HAL_TIM_SET_AUTORELOAD(TIM_HandleTypeDef* htim,uint32_t arr);
/* 动态获取TIM的自动重装载值(直接读取寄存器) */
__HAL_TIM_GET_AUTORELOAD(TIM_HandleTypeDef* htim);

/* 直接设置TIM计数器的当前计数值(直接写入寄存器),计数器下次从设置值开始计数。
   计数器计数到达 0(向下计数) 或 自动重装载值(向上计数) 后,
   除非再次直接设置计数器当前计数值,自动装载为 自动重装载值(向下计数) 或 0(向上计数) */
__HAL_TIM_SET_COUNTER(TIM_HandleTypeDef* htim,uint32_t cnt);

/* 直接获取TIM计数器的当前计数值(直接读取寄存器) */
__HAL_TIM_GET_COUNTER(TIM_HandleTypeDef* htim);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

TIM实现微秒级延时

向上计数

/* 选择TIM2,预分频设置为 84-1 */
void delayUs(uint32_t xus) {
    /* 设置自动装载值 */
    __HAL_TIM_SET_AUTORELOAD(&htim2,xus);
    /* 计数器设置初始值。计数器计完一轮后才重装数值,若初始值不正确,将导致计时错误 */
	__HAL_TIM_SET_COUNTER(&htim2,0);
    /* 开始计时 */
	__HAL_TIM_ENABLE(&htim2);
    /* 等待计时到达 */
	while(__HAL_TIM_GET_COUNTER(&htim2) < xus);
    /* 停止计时 */
	__HAL_TIM_DISABLE(&htim2);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

向下计数

/* 选择TIM2,预分频设置为 84-1 */
void delayUs(uint32_t xus) {
    /* 设置自动装载值 */
    __HAL_TIM_SET_AUTORELOAD(&htim2,xus);
    /* 计数器设置初始值。计数器计完一轮后才重装数值,若初始值不正确,将导致计时错误 */
	__HAL_TIM_SET_COUNTER(&htim2,xus);
    /* 开始计时 */
	__HAL_TIM_ENABLE(&htim2);
    /* 等待计时到达 */
	while(__HAL_TIM_GET_COUNTER(&htim2) > 0);
    /* 停止计时 */
	__HAL_TIM_DISABLE(&htim2);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

注意:

使用定时器实现微秒级延时时,必须确保计数器初始值正确设置。
 向上计数:计数器从0开始递增计数,计数到arr后重新装载为0。计数器初始值 小于或大于 arr 都将导致计时偏差。而当 计数器初始值 大于arr时,将导致以上函数一直阻塞在while()循环。
 向下计数:计数器从arr开始递减计数,计数到0后重新装载为arr。计数器初始值 小于或大于 arr 都将导致计时偏差。

TIM更新中断

TIM更新中断(TIM_IT_UPDATE)指TIM计数器更新中断。在向上计数模式中,当计数器计满指定值后,重装新值时将产生更新中断;在向下计数模式中,当计数器递减为0后,重装新值时将产生更新中断。

NVIC配置

/* 全局NVIC分组 */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);

/* NVIC优先级配置 
   参数:
   (IRQn_Type)TIM3_IRQn - TIM中断名 */
HAL_NVIC_SetPriority(TIM3_IRQn,0,0);

/* NVIC中断使能 */
HAL_NVIC_EnableIRQ(TIM3_IRQn);
/* NVIC中断失能 */
HAL_NVIC_DisableIRQ(TIM3_IRQn);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

TIM中断使能

/* TIM更新中断使能 */
__HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);
/* TIM更新中断失能 */
__HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE);

/* 使能更新中断之后开启定时器(先调用__HAL_TIM_ENABLE_IT(),再调用__HAL_TIM_ENABLE()) */
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim);

/* 失能更新中断之后关闭定时器(先调用__HAL_TIM_DISABLE_IT(),再调用__HAL_TIM_DISABLE()) */
HAL_StatusTypeDef HAL_TIM_Base_Stop_IT(TIM_HandleTypeDef *htim);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

 注意:调用HAL_TIM_Base_Start_IT()后定时器将一直重复计数,直到关闭定时器或关闭中断。定时器更新中断发生后,更新中断不被禁止,如果需要更新中断发生后被禁止,需要手动调用HAL_TIM_Base_Stop_IT()禁止更新中断

中断服务函数

void TIMx_IRQHandler(void);
  • 1

通用入口函数

/* 通用入口函数在中断服务函数中调用。中断回调函数中包含中断标志的判断和清除,
   以及调用中断回调函数。 */
void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim);
  • 1
  • 2
  • 3

中断回调函数

/* 更新中断回调函数 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
/* 输出比较中断回调函数 */
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim);
/* 输入捕获中断回调函数 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);
/* 触发中断回调函数 */
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

TIM更新中断示例

#include "stm32f4xx.h"
#include "sys_init.h"

void LED_Init(void);
void TIM_ParamInit(TIM_HandleTypeDef* htim,uint32_t psc,uint32_t prd);
void Start_Count(TIM_HandleTypeDef* htim);
void Stop_Count(TIM_HandleTypeDef* htim);

/* TIM句柄 */
static TIM_HandleTypeDef TIM_Handler;

int main(void) {
    // HAL_init(),NVIC全局分组,系统时钟配置
	SYS_INIT();
	LED_Init();
	TIM_ParamInit(&TIM_Handler,8400-1,5000-1);
	Start_Count(&TIM_Handler);	
	while(1);	
}

void LED_Init() {
    
    #ifndef LED_Port 
    #define LED_Port GPIOC
    #endif
    #ifndef LED_Pin
    #define LED_Pin GPIO_PIN_0
    #endif
    #ifndef LED_CLK_ENABLE
    #define LED_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
    #endif
    
    GPIO_InitTypeDef LED_InitStruct;
    
    LED_CLK_ENABLE();
	
	LED_InitStruct.Pin = LED_Pin;
	LED_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
	LED_InitStruct.Pull = GPIO_NOPULL;
	LED_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	
	HAL_GPIO_Init(LED_Port,&LED_InitStruct);
}

/* 调用HAL_TIM_Base_Init(),并将参数写入全局变量 */
void TIM_ParamInit(TIM_HandleTypeDef* htim,uint32_t psc,uint32_t prd) {
	
	htim->Instance = TIM3;
	htim->Init.Prescaler = psc;
	htim->Init.Period = prd;
	htim->Init.CounterMode = TIM_COUNTERMODE_UP;
	htim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
	
	HAL_TIM_Base_Init(htim);
}

/* Msp初始化回调函数 */
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim) {
    /* TIM时钟使能 */
	__HAL_RCC_TIM3_CLK_ENABLE();
    /* TIM中断优先级配置 */
	HAL_NVIC_SetPriority(TIM3_IRQn,0,0);
    /* NVIC中断使能 */
	HAL_NVIC_EnableIRQ(TIM3_IRQn);
}

void Start_Count(TIM_HandleTypeDef* htim) {
    /* 开启中断并开始计时 */
	HAL_TIM_Base_Start_IT(htim);
}

void Stop_Count(TIM_HandleTypeDef* htim) {
    /* 关闭中断并停止计时 */
	HAL_TIM_Base_Stop_IT(htim);
}

/* TIM中断服务函数 */
void TIM3_IRQHandler(void) {
    /* TIM中断处理通用入口函数 */
	HAL_TIM_IRQHandler(&TIM_Handler);
}

/* TIM更新中断回调函数 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    #ifndef LED_Toggle
    #define LED_Toggle() HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0)
    #endif
	LED_Toggle();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90

PWM输出

概述

STM32F4的通用定时器除了TIM6TIM7之外,都可以用作PWM输出,每个通用定时器可同时输出4PWM波形。

PWM输出初始化

PWM输出时钟使能

/* TIMx时钟使能 */
__HAL_RCC_TIMx_CLK_ENABLE();
/* PWM输出通道对应的GPIO时钟使能 */
__HAL_RCC_GPIOx_CLK_ENABLE();
  • 1
  • 2
  • 3
  • 4

GPIO初始化

GPIO_InitTypeDef GPIO_InitStruct;
/* GPIOF_PIN_9 对应 TIM14_CH1 */
GPIO_Initure.Pin = GPIO_PIN_9;
/* 复用推挽输出 */
GPIO_Initure.Mode = GPIO_MODE_AF_PP;
/* 上拉 */
GPIO_Initure.Pull = GPIO_PULLUP;
/* 高速 */
GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;
/* 配置复用功能 */
GPIO_Initure.Alternate= GPIO_AF9_TIM14;

HAL_GPIO_Init(GPIOF,&GPIO_InitStruct);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

PWM参数初始化

 对于TIMPWM输出功能,使用专用PWM参数初始化函数HAL_TIM_PWM_Init(),它与HAL_TIM_Base_Init()的作用一致,但PWM输出也有专门的初始化回调函数,在HAL_TIM_PWM_Init()中调用。因此使用HAL_TIM_PWM_Init()而不用HAL_TIM_Base_Init()

/* PWM参数初始化
   参数:
   (TIM_HandleTypeDef*)htim - TIM句柄
   返回:
   HAL_OK - 初始化成功
   HAL_ERROR - 当 htim = NULL 时将返回 HAL_ERROR */
HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim);

/* PWM初始化回调函数 */
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) {
    ...
    // 时钟初始化;
    // GPIO初始化;
    // 中断配置;
    // 通道初始化;
    ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

PWM通道初始化

/* TIM通道初始化函数
   参数:
   (TIM_HandleTypeDef*)htim - TIM句柄
   (TIM_OC_InitTypeDef*)sConfig - TIM输出比较初始化结构体指针
   (uint32_t)Channel - TIM通道,取值有:
       TIM_CHANNEL_1/TIM_CHANNEL_2/TIM_CHANNEL_3/TIM_CHANNEL_4 */
HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef* htim, 
                                            TIM_OC_InitTypeDef* sConfig, 
                                            uint32_t Channel);
typedef struct {
    
    /* PWM模式,取值有:
       TIM_OCMODE_PWM1 - TIMx_CNT < TIMx_CCRn,通道 n 便为 有效电平,否则为 无效电平,
           计数器的 递增 或 递减 模式都是如此。
       TIM_OCMODE_PWM2 - TIMx_CNT < TIMx_CCRn,通道 n 便为 无效电平,否则为 有效电平,
           计数器的 递增 或 递减 模式都是如此。*/
    uint32_t OCMode;
    
    /* PWM捕获比较值(将写入TIMx->CCRn) */
    uint32_t Pulse;
    
    /* PWM极性,设置通道PWM波形的有效电平,取值有:
       TIM_OCPOLARITY_HIGH - 有效电平为高电平 
       TIM_OCPOLARITY_LOW - 有效电平为低电平 */
    uint32_t OCPolarity;
    
    /* 高级定时器相关 */
    uint32_t OCNPolarity; 
    uint32_t OCFastMode;
    uint32_t OCIdleState; 
    uint32_t OCNIdleState;
    
} TIM_OC_InitTypeDef;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

PWM通道的开启/关闭

/* 开启PWM输出:
   1.调用TIM_CCxChannelCmd()开启PWM通道;
   2.调用__HAL_TIM_ENABLE()使能定时器
   参数:
   (TIM_HandleTypeDef*)htim - TIM句柄
   (uint32_t)Channel - PWM输出通道,取值有
       TIM_CHANNEL_1/TIM_CHANNEL_2/TIM_CHANNEL_3/TIM_CHANNEL_4 */
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef* htim, uint32_t Channel);

/* 关闭PWM输出:
   1.调用TIM_CCxChannelCmd()关闭PWM通道;
   2.调用__HAL_TIM_DISABLE()失能定时器 */
HAL_StatusTypeDef HAL_TIM_PWM_Stop(TIM_HandleTypeDef* htim, uint32_t Channel);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

PWM输出波形参数计算

PWM基频

PWM输出基频由定时器中计数器的溢出频率控制,因此修改 自动重装载寄存器TIMx->ARR, 预分频寄存器TIMx->PSC 或 计数器TIMx->CNT 的值可修改PWM输出基频。

/* 动态设置TIM的预分频值 TIM->psc */
__HAL_TIM_SET_PRESCALER(TIM_HandleTypeDef* htim,uint32_t psc);

/* 动态设置TIM的自动重装载值 TIM->ARR */
__HAL_TIM_SET_AUTORELOAD(TIM_HandleTypeDef* htim,uint32_t arr);

/* 动态设置TIM计数器的当前计数值 TIM->CNT */
__HAL_TIM_SET_COUNTER(TIM_HandleTypeDef* htim,uint32_t cnt);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

PWM占空比

PWM输出占空比由 捕获比较寄存器TIMx->CCRn(n=1~4) 与 自动重装载寄存器TIMx->ARR 的值之比控制。

设 TIMx->CCRn/TIMx->ARR = dc
    
PWM模式1(TIM_OCMODE_PWM1)
    定时器计数递增模式(TIM_COUNTERMODE_UP) :   占空比 = dc   有效电平相位 先于 无效电平
    定时器计数递减模式(TIM_COUNTERMODE_DOWN) : 占空比 = dc   有效电平相位 后于 无效电平   
    
PWM模式2(TIM_OCMODE_PWM2)
    定时器计数递增模式(TIM_COUNTERMODE_UP) :   占空比 = 1-dc 有效电平相位 后于 无效电平
    定时器计数递减模式(TIM_COUNTERMODE_DOWN) : 占空比 = 1-dc 有效电平相位 先于 无效电平
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

 可以通过HAL_TIM_PWM_ConfigChanne()设置占空比参数,但由于调用该函数会重设其它函数,可能出现不必要的混乱。HAL库中提供了相关的宏函数:

/* 设置PWM捕获比较值,TIMx->CCRn 
   __HANDLE__ - TIM句柄 
   __CHANNEL__ - PWM输出通道,取值有:
       TIM_CHANNEL_1/TIM_CHANNEL_2/TIM_CHANNEL_3/TIM_CHANNEL_4 
   __COMPARE__ - 比较值    */
__HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__);
/* 获取PWM捕获比较值,TIMx->CCRn */
__HAL_TIM_GET_COMPARE(__HANDLE__, __CHANNEL__);

/* 设置PWM捕获比较值,TIMx->CCRn 
   __HANDLE__ - TIM句柄 
   __CHANNEL__ - PWM输出通道,取值有:
       TIM_CHANNEL_1/TIM_CHANNEL_2/TIM_CHANNEL_3/TIM_CHANNEL_4 
   __POLARITY__ - PWM有效电平极性,取值有:
       TIM_OCPOLARITY_HIGH - 有效电平为高电平
       TIM_OCPOLARITY_LOW - 有效电平为低电平*/
__HAL_TIM_SET_CAPTUREPOLARITY(__HANDLE__, __CHANNEL__, __POLARITY__);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

PWM输出示例

#include "stm32f4xx.h"
#include "sys_init.h"

/* 定时器预分频值,选取原则是方便计算 */
#ifndef SYS_PSC
#define SYS_PSC 84
#endif

void PWM_ParamInit(void);
void PWM_SetParam(uint32_t freq,double dc);

// TIM句柄
static TIM_HandleTypeDef TIM_Handler = {0};

int main(void) {
    
    // HAL_Init(),系统时钟初始化,NVIC全局分组配置...
    SYS_INIT();
    
    PWM_ParamInit();
    
    // 设置基频 1000Hz, 占空比 0.5
    PWM_SetParam(1000,0.5);
    
    // 开启PWM输出
    HAL_TIM_PWM_Start(&TIM_Handler,TIM_CHANNEL_1);
    
    // 关闭PWM输出
    // HAL_TIM_PWM_Stop(&TIM_Handler,TIM_CHANNEL_1);
    
    while(1);
}

// PWM参数初始化
void PWM_ParamInit(void) {
    
    TIM_Handler.Instance = TIM14;
    
    // TIM时钟预分频值,#define SYS_PSC 84
    TIM_Handler.Init.Prescaler = SYS_PSC-1;
    
    //在动态设置PWM基频时设置
    // TIM_Handler.Init.Period = prd;
    
    // 向上计数模式,计数器递增
    TIM_Handler.Init.CounterMode = TIM_COUNTERMODE_UP;
    TIM_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    
    // 不开启自动重装预装载缓冲
    TIM_Handler.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
	
	HAL_TIM_PWM_Init(&TIM_Handler);   
}

// 设置PWM基频和占空比
void PWM_SetParam(uint32_t freq,double dc) {
    // 设置自动装载值(写入TIMx->ARR)以设置PWM基频
    __HAL_TIM_SET_AUTORELOAD(&TIM_Handler,1000000/freq-1);
    // 设置比较值(写入TIMx->CCRn(n=1~4))以设置PWM占空比
    __HAL_TIM_SET_COMPARE(&TIM_Handler,TIM_CHANNEL_1,1000000/freq*dc);
}

// PWM Msp初始化回调函数
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* htim) {
    
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    TIM_OC_InitTypeDef TIM_OCInitStruct = {0};
    
    // PWM通道对应的GPIO使能
    __HAL_RCC_GPIOA_CLK_ENABLE();
    // 定时器使能
    __HAL_RCC_TIM14_CLK_ENABLE();
    
    // GPIOA_PIN_7 - TIM14_CH1
    GPIO_InitStruct.Pin = GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    // 配置复用功能
    GPIO_InitStruct.Alternate= GPIO_AF9_TIM14;
    HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
    
    // PWM模式1,占空比 = TIMx->CCRn/TIMx->ARR
    TIM_OCInitStruct.OCMode = TIM_OCMODE_PWM1;
    
    // 在动态设置PWM占空比时设置
    // TIM_OCInitStruct.Pulse = pulse;
    
    // PWM有效电平为高电平
    TIM_OCInitStruct.OCPolarity = TIM_OCPOLARITY_HIGH;
    
    // 配置PWM通道
    HAL_TIM_PWM_ConfigChannel(htim,&TIM_OCInitStruct,TIM_CHANNEL_1);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/281083
推荐阅读
相关标签
  

闽ICP备14008679号