STM32 TIM1中心对齐模式3下更新事件仅在ARR触发的求助
STM32 TIM1中心对齐模式3下仅在ARR触发更新事件的解决方案
针对TIM1中心对齐模式3下更新事件在ARR和0处均触发的问题,本质是该模式下硬件默认会在计数器向上溢出(到达ARR)和向下下溢(到达0)时都产生更新事件(UEV)。要实现仅在ARR处触发ADC采样,可通过以下三种方案解决:
方案1:改用CC事件/TRGO硬件触发ADC(推荐纯硬件实现)
放弃使用更新事件触发ADC,改用计数器到达ARR时的捕获/compare(CC)事件作为触发源,完全通过硬件配置实现需求:
- 配置空闲CC通道:选择一个未用于PWM输出的TIM1通道(如CC3/CC4),将其CCR值设为ARR,配置为定时模式(仅触发事件,不输出PWM)。
- 设置TRGO触发源:将TIM1的TRGO输出绑定为该CC事件,再配置ADC以TIM1_TRGO为触发源。
HAL库代码示例
// 配置TIM1的CC3通道,CCR3 = ARR值 TIM_OC_InitTypeDef sConfigOC = {0}; sConfigOC.OCMode = TIM_OCMODE_TIMING; sConfigOC.Pulse = TIM1->ARR; // 绑定CCR值到ARR sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3); // 配置TRGO输出为CC3事件 TIM_MasterConfigTypeDef sMasterConfig = {0}; sMasterConfig.MasterOutputTrigger = TIM_TRGO_CC3; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig); // 配置ADC触发源为TIM1_TRGO ADC_HandleTypeDef hadc1; hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_TRGO; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; HAL_ADC_Init(&hadc1);
方案2:软件过滤更新事件(适合允许少量软件干预场景)
保留更新事件触发ADC,但在DMA/中断回调中通过计数方向判断,仅处理ARR处的触发:
- 读取TIM1_CR1寄存器的
DIR位:DIR=0表示向上计数到ARR触发的更新,DIR=1表示向下计数到0触发的更新。 - 仅在
DIR=0时处理ADC采样数据,忽略DIR=1的触发。
代码示例(DMA完成回调)
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { if (hadc->Instance == ADC1) { // 判断TIM1当前计数方向 if (!(__HAL_TIM_GET_COUNTERMODE(&htim1) == TIM_COUNTERMODE_DOWN)) { // 仅处理向上计数到ARR时的采样数据 process_adc_data(adc_buffer); } // 重新启动ADC DMA循环采样 HAL_ADC_Start_DMA(&hadc1, adc_buffer, BUFFER_SIZE); } }
方案3:模拟中心对齐模式(软件控制计数方向)
放弃硬件中心对齐模式,改用向上/向下计数模式手动切换,仅在ARR处触发更新事件:
- 初始配置TIM1为向上计数模式,开启更新中断。
- 当计数器到达ARR触发中断时,切换为向下计数模式;当计数器到达0时,再切换回向上计数模式。此时更新事件仅在ARR处产生。
HAL库代码示例
// 初始配置为向上计数模式 TIM_Base_InitTypeDef sTimBaseInit = {0}; sTimBaseInit.Prescaler = YOUR_PRESCALER; sTimBaseInit.CounterMode = TIM_COUNTERMODE_UP; sTimBaseInit.Period = YOUR_ARR_VALUE; sTimBaseInit.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(&htim1); // 开启TIM更新中断 HAL_TIM_Base_Start_IT(&htim1); // 更新中断回调函数 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM1) { if (__HAL_TIM_IS_TIM_COUNTING_DOWN(htim)) { // 向下计数到0,切换为向上计数 __HAL_TIM_SET_COUNTERMODE(htim, TIM_COUNTERMODE_UP); __HAL_TIM_SET_COUNTER(htim, 0); } else { // 向上计数到ARR,切换为向下计数并触发ADC采样 __HAL_TIM_SET_COUNTERMODE(htim, TIM_COUNTERMODE_DOWN); HAL_ADC_Start_DMA(&hadc1, adc_buffer, BUFFER_SIZE); } } }
注意事项
- 方案1中需确保所选CC通道未被PWM占用,若所有通道都在使用,可考虑复用通道的事件触发功能(不影响PWM输出)。
- 方案3需保证中断响应及时,避免计数方向切换延迟影响PWM输出精度。
内容的提问来源于stack exchange,提问作者Electrone
相关产品推荐
相关产品推荐

