本帖最后由 南来之风 于 2023-7-31 22:24 编辑
ST的官方库有非常丰富的外设使用例程,本文体验的就是:STM32Cube_FW_WBA_V1.1.0\Projects\NUCLEO-WBA52CG\Examples\TIM\TIM_TimeBase
该例程配置使用TIM模块产生一个1s的中断,然后再中断服务函数中翻转LED。
初始化外设,Flash和Systick:
SystemClock_Config() 函数用于配置STM32WBA52CGUx 设备系统时钟为100 MHz /* Configure the system clock */
SystemClock_Config();
根据官方ReadMe,TIM模块的时钟频率,TIM2模块的计数器时钟频率,以及周期都有相应的公式:
In this example TIM2 input clock (TIM2CLK) is set to APB1 clock (PCLK1),since APB1 prescaler is equal to 1. TIM2CLK = PCLK1 PCLK1 = HCLK => TIM2CLK = HCLK = SystemCoreClockTo get TIM2 counter clock at 10 KHz, the Prescaler is computed as following:Prescaler = (TIM2CLK / TIM2 counter clock) - 1Prescaler = (SystemCoreClock /10 KHz) - 1SystemCoreClock is set to 100 MHz for STM32WBAxx Devices. The TIM2 ARR register value is equal to 10000 - 1 Update rate = TIM2 counter clock / (Period + 1) = 1 Hz So the TIM2 generates an interrupt each 1 s When the counter value reaches the auto-reload register value, the TIM update interrupt is generated and, in the handler routine, pin PB.4 (connected to LD1 on board NUCLEO-WBA52CG) is toggled. So led blinks at the following frequency: 0.5Hz. In case of error, LD3 is turned ON.
在main.h中,有相应的参数定义: /* Compute the prescaler value to have TIMx counter clock equal to 10000 Hz */
#define PRESCALER_VALUE (uint32_t)(((SystemCoreClock) / (10000)) - 1)
/* Initialize TIMx peripheral as follows:
+ Period = 10000 - 1
+ Prescaler = (SystemCoreClock/10000) - 1
+ ClockDivision = 0
+ Counter direction = Up
*/
#define PERIOD_VALUE (10000 - 1);
在main.c中,调用如下函数进行TIM模块初始化: /**
* [url=home.php?mod=space&uid=247401]@brief[/url] TIM2 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = PRESCALER_VALUE;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = PERIOD_VALUE;
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();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
}
如下定义了TIM2模块的中断服务子程序:/**
* [url=home.php?mod=space&uid=247401]@brief[/url] This function handles TIM2 global interrupt.
*/
void TIM2_IRQHandler(void)
{
/* USER CODE BEGIN TIM2_IRQn 0 */
/* USER CODE END TIM2_IRQn 0 */
HAL_TIM_IRQHandler(&htim2);
/* USER CODE BEGIN TIM2_IRQn 1 */
/* USER CODE END TIM2_IRQn 1 */
}
接着调用HAL库中的中断服务子程序:
void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim)
{
uint32_t itsource = htim->Instance->DIER;
uint32_t itflag = htim->Instance->SR;
/* Capture compare 1 event */
if ((itflag & (TIM_FLAG_CC1)) == (TIM_FLAG_CC1))
{
if ((itsource & (TIM_IT_CC1)) == (TIM_IT_CC1))
{
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1);
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_1;
/* Input capture event */
if ((htim->Instance->CCMR1 & TIM_CCMR1_CC1S) != 0x00U)
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->IC_CaptureCallback(htim);
#else
HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
/* Output compare event */
else
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->OC_DelayElapsedCallback(htim);
htim->PWM_PulseFinishedCallback(htim);
#else
HAL_TIM_OC_DelayElapsedCallback(htim);
HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
}
}
}
/* Capture compare 2 event */
if ((itflag & (TIM_FLAG_CC2)) == (TIM_FLAG_CC2))
{
if ((itsource & (TIM_IT_CC2)) == (TIM_IT_CC2))
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC2);
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_2;
/* Input capture event */
if ((htim->Instance->CCMR1 & TIM_CCMR1_CC2S) != 0x00U)
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->IC_CaptureCallback(htim);
#else
HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
/* Output compare event */
else
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->OC_DelayElapsedCallback(htim);
htim->PWM_PulseFinishedCallback(htim);
#else
HAL_TIM_OC_DelayElapsedCallback(htim);
HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
}
}
/* Capture compare 3 event */
if ((itflag & (TIM_FLAG_CC3)) == (TIM_FLAG_CC3))
{
if ((itsource & (TIM_IT_CC3)) == (TIM_IT_CC3))
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC3);
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_3;
/* Input capture event */
if ((htim->Instance->CCMR2 & TIM_CCMR2_CC3S) != 0x00U)
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->IC_CaptureCallback(htim);
#else
HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
/* Output compare event */
else
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->OC_DelayElapsedCallback(htim);
htim->PWM_PulseFinishedCallback(htim);
#else
HAL_TIM_OC_DelayElapsedCallback(htim);
HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
}
}
/* Capture compare 4 event */
if ((itflag & (TIM_FLAG_CC4)) == (TIM_FLAG_CC4))
{
if ((itsource & (TIM_IT_CC4)) == (TIM_IT_CC4))
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC4);
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_4;
/* Input capture event */
if ((htim->Instance->CCMR2 & TIM_CCMR2_CC4S) != 0x00U)
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->IC_CaptureCallback(htim);
#else
HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
/* Output compare event */
else
{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->OC_DelayElapsedCallback(htim);
htim->PWM_PulseFinishedCallback(htim);
#else
HAL_TIM_OC_DelayElapsedCallback(htim);
HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
}
}
/* TIM Update event */
if ((itflag & (TIM_FLAG_UPDATE)) == (TIM_FLAG_UPDATE))
{
if ((itsource & (TIM_IT_UPDATE)) == (TIM_IT_UPDATE))
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->PeriodElapsedCallback(htim);
#else
HAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
}
/* TIM Break input event */
if ((itflag & (TIM_FLAG_BREAK)) == (TIM_FLAG_BREAK))
{
if ((itsource & (TIM_IT_BREAK)) == (TIM_IT_BREAK))
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_BREAK);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->BreakCallback(htim);
#else
HAL_TIMEx_BreakCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
}
/* TIM Break2 input event */
if ((itflag & (TIM_FLAG_BREAK2)) == (TIM_FLAG_BREAK2))
{
if ((itsource & (TIM_IT_BREAK)) == (TIM_IT_BREAK))
{
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_BREAK2);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->Break2Callback(htim);
#else
HAL_TIMEx_Break2Callback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
}
/* TIM Trigger detection event */
if ((itflag & (TIM_FLAG_TRIGGER)) == (TIM_FLAG_TRIGGER))
{
if ((itsource & (TIM_IT_TRIGGER)) == (TIM_IT_TRIGGER))
{
__HAL_TIM_CLEAR_IT(htim, TIM_IT_TRIGGER);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->TriggerCallback(htim);
#else
HAL_TIM_TriggerCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
}
/* TIM commutation event */
if ((itflag & (TIM_FLAG_COM)) == (TIM_FLAG_COM))
{
if ((itsource & (TIM_IT_COM)) == (TIM_IT_COM))
{
__HAL_TIM_CLEAR_IT(htim, TIM_FLAG_COM);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->CommutationCallback(htim);
#else
HAL_TIMEx_CommutCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
}
/* TIM Encoder index event */
if ((itflag & (TIM_FLAG_IDX)) == (TIM_FLAG_IDX))
{
if ((itsource & (TIM_IT_IDX)) == (TIM_IT_IDX))
{
__HAL_TIM_CLEAR_IT(htim, TIM_FLAG_IDX);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->EncoderIndexCallback(htim);
#else
HAL_TIMEx_EncoderIndexCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
}
/* TIM Direction change event */
if ((itflag & (TIM_FLAG_DIR)) == (TIM_FLAG_DIR))
{
if ((itsource & (TIM_IT_DIR)) == (TIM_IT_DIR))
{
__HAL_TIM_CLEAR_IT(htim, TIM_FLAG_DIR);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->DirectionChangeCallback(htim);
#else
HAL_TIMEx_DirectionChangeCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
}
/* TIM Index error event */
if ((itflag & (TIM_FLAG_IERR)) == (TIM_FLAG_IERR))
{
if ((itsource & (TIM_IT_IERR)) == (TIM_IT_IERR))
{
__HAL_TIM_CLEAR_IT(htim, TIM_FLAG_IERR);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->IndexErrorCallback(htim);
#else
HAL_TIMEx_IndexErrorCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
}
/* TIM Transition error event */
if ((itflag & (TIM_FLAG_TERR)) == (TIM_FLAG_TERR))
{
if ((itsource & (TIM_IT_TERR)) == (TIM_IT_TERR))
{
__HAL_TIM_CLEAR_IT(htim, TIM_FLAG_TERR);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->TransitionErrorCallback(htim);
#else
HAL_TIMEx_TransitionErrorCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
}
}
注意其中有个函数调用:
HAL_TIM_PeriodElapsedCallback(htim);
这个回调函数的定义如下:
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] Period elapsed callback in non blocking mode
* @param htim : TIM handle
* @retval None
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
BSP_LED_Toggle(LD1);
}
烧录后,可以看到LD1以1s频率闪烁。
|