Keil MDK STM32系列(七) STM32F4基于HAL的PWM和定时器
Keil MDK STM32系列
- Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发
- Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401开发
- Keil MDK STM32系列(三) 基于标准外设库SPL的STM32F407开发
- Keil MDK STM32系列(四) 基于抽象外设库HAL的STM32F401开发
- Keil MDK STM32系列(五) 使用STM32CubeMX创建项目基础结构
- Keil MDK STM32系列(六) 基于HAL的ADC模数转换
- Keil MDK STM32系列(七) STM32F4基于HAL的PWM和定时器
- Keil MDK STM32系列(八) STM32F4基于HAL的PWM和定时器输出音频
- Keil MDK STM32系列(九) 基于HAL和FatFs的FAT格式SD卡TF卡读写
配置 PWM 输出
- 选择芯片
- System Core -> SYS-> Debug: Serial Wire 防止下次无法烧录
- System Core -> RCC-> High Speed Clock (HSE): Crystal/Ceramic Resonator 启用外接高速晶振
- Clock Configuration: (配置为最高84MHz)选择外部晶振, 把HSE和PLLCLK连上, 在HCLK上输入84回车, 软件会自动调节各节点倍数
- Timers -> TIM2
- Clock Source: Internel Clock, 使用系统的时钟源
- Channelx: PWM Generation CHx PWM输出
- Counter Settings PWM频率 = 84MHz / (Perscaler + 1) / (Counter Period + 1)
- Perscaler: 0
- Counter Mode: Up
- Counter Period: 256
- Internal Clock Division(CKD): No Division
- auto-reload preload: Enable - 如果启用, 在修改占空比时会等当前周期执行完再变化
- Trigger Output
- Master/Slave Mode (MSM bit): Disable
- Trigger Event Selection: Reset (UG bit from TIMx_EGR)
- PWM Generation Channel 1
- Mode: PWM mode1
- Pulse: 0
- Output compare perload: Enable
- Fast Mode: Disable
- CH Polarity: High
- PWM Generation Channel 2
- ...
PWM 配置, 体现在代码上的变化
- stm32f4xx_hal_conf.h 去掉了TIM的注释
#define HAL_TIM_MODULE_ENABLED
- stm32f4xx_hal_msp.c 增加了初始化方法HAL_TIM_Base_MspInit(), HAL_TIM_MspPostInit(), HAL_TIM_Base_MspDeInit()
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspInit 0 */
/* USER CODE END TIM2_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_TIM2_CLK_ENABLE();
/* USER CODE BEGIN TIM2_MspInit 1 */
/* USER CODE END TIM2_MspInit 1 */
}
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(htim->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspPostInit 0 */
/* USER CODE END TIM2_MspPostInit 0 */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**TIM2 GPIO Configuration
PA15 ------> TIM2_CH1
PB3 ------> TIM2_CH2
*/
GPIO_InitStruct.Pin = GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN TIM2_MspPostInit 1 */
/* USER CODE END TIM2_MspPostInit 1 */
}
}
/**
* @brief TIM_Base MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param htim_base: TIM_Base handle pointer
* @retval None
*/
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspDeInit 0 */
/* USER CODE END TIM2_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM2_CLK_DISABLE();
/* USER CODE BEGIN TIM2_MspDeInit 1 */
/* USER CODE END TIM2_MspDeInit 1 */
}
}
- main.c 对TIM2增加初始化方法, TIM的初始化过程与其它外设是不一样的
这里Prescaler=0
,Period=255
, 对应84MHz的SYSCLK, 输出的PWM频率为84MHz/256 = 32.8125KHz, 用于输出音频
TIM_HandleTypeDef htim2;
/**
* @brief TIM2 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 255;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
HAL_TIM_MspPostInit(&htim2);
}
配置定时器
通过TIMx配置
- 勾选 Internal Clock
- 配置下方参数
- Counter Settings
- Prescaler: 0
- Counter Mode: Up
- Counter Period: 1999 这里和Perscaler组合, 实现(0+1)(1999+1)个时钟的周期
- Internal Clock Division (CKD): No division
- auto-reload preload: Disable
- Trigger Output (TRGO) Parameters
- Master/Slave Mode (MSM bit): Disable
- Trigger Envent Selection: Reset
- NVIC Settings
- TIM3 global interrupt: Enable
对应代码变化
stm32f4xx_hal_conf.h 启用TIM模块
#define HAL_TIM_MODULE_ENABLED
main.c 除了初始化方法, 还需要添加中断处理方法
static void MX_TIM3_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 1999;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
//...
}
stm32f4xx_hal_msp.c 这里会一起处理其他的TIM实例
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM2)
{
// ...
}
else if(htim_base->Instance==TIM3)
{
__HAL_RCC_TIM3_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
}
}
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM2)
{
//...
}
else if(htim_base->Instance==TIM3)
{
__HAL_RCC_TIM3_CLK_DISABLE();
HAL_NVIC_DisableIRQ(TIM3_IRQn);
}
}
stm32f4xx_it.h 增加对应的定时中断处理
void TIM3_IRQHandler(void);
stm32f4xx_it.c
/**
* @brief This function handles TIM3 global interrupt.
*/
void TIM3_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim3);
}