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);
}