如何使用两个定时器(TIM4)通道正确读取 PWM 占空比?

问题描述 投票:0回答:1

使用的库:串行外设库

硬件:

  • 可产生两个pwm信号(A和B)的测试台
  • 将测试台连接到另一块板的电缆
  • 另一块板应读取由电缆传送的信号,并检测 PWM 占空比和频率(一个用于 A,一个用于 B)。

端口 D 引脚 12 Tim4 通道 1 端口 D 引脚 13 Tim4 通道 2

测试台频率/PWM 生成工作正常,因此无需调试。

硬件和电缆连接正确(我们已经三重检查)

问题出现在另一块板上:计算的占空比似乎只指向一个信号,所以如果我断开另一个信号的电缆,我仍然可以计算出两个占空比,同时应该为零

引脚 12 端口 D 定时器 4 通道 1 配置:

void myPWM4_Config_1(tmyPWMInput *me)
{
    RCC_ClocksTypeDef __RCC_CLOCK;

    myPWMInputCtor(me);

    RCC_GetClocksFreq(&__RCC_CLOCK);
    me->clock = __RCC_CLOCK.PCLK1_Frequency * 2; //APB1

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

    me->GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    me->GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    me->GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    me->GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    me->GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

    GPIO_Init(GPIOD, &me->GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);

    TIM4_IRQHandler_ptf = TIM4_IRQ_PWM;
    me->NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
    me->NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    me->NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    me->NVIC_InitStructure.NVIC_IRQChannelCmd = 1;
    NVIC_Init(&me->NVIC_InitStructure);

    me->TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
    me->TIM_TimeBaseStructure.TIM_Prescaler = 840 - 1;
    me->TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
    me->TIM_TimeBaseStructure.TIM_ClockDivision= TIM_CKD_DIV1;
    me->TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

    TIM_TimeBaseInit(TIM4, &me->TIM_TimeBaseStructure);

    me->TIM_CH1_ICInitStructure.TIM_Channel         = TIM_Channel_1;
    me->TIM_CH1_ICInitStructure.TIM_ICPolarity      = TIM_ICPolarity_Rising;
    me->TIM_CH1_ICInitStructure.TIM_ICSelection     = TIM_ICSelection_DirectTI;
    me->TIM_CH1_ICInitStructure.TIM_ICPrescaler     = TIM_ICPSC_DIV1;
    me->TIM_CH1_ICInitStructure.TIM_ICFilter        = 0x0;

    TIM_PWMIConfig(TIM4, &me->TIM_CH1_ICInitStructure);
                                      // Select the TIM8 Input Trigger: TI1FP1
    TIM_SelectInputTrigger(TIM4, TIM_TS_TI1FP1);
                                          // Select the slave Mode: Reset Mode
    TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset);

    TIM_SelectMasterSlaveMode(TIM4, TIM_MasterSlaveMode_Enable);
                           // Enables TIM8 peripheral Preload register on ARR.
    TIM_ARRPreloadConfig(TIM4, ENABLE);
    // Configures the TIM8 Update Request Interrupt source (SETS the CR1->URS bit)
    TIM_UpdateRequestConfig(TIM4, TIM_UpdateSource_Regular);

                            // Enable the CC1 and the update Interrupt Request
    TIM_ITConfig(TIM4, TIM_IT_CC1, ENABLE);

    TIM_ClearFlag(TIM4, TIM_FLAG_Update);
    TIM_Cmd(TIM4, ENABLE);
}

引脚 13 端口 D Tim4 通道 2 配置:

void myPWM4_Config_2(tmyPWMInput *me)
{
    RCC_ClocksTypeDef __RCC_CLOCK;

    myPWMInputCtor(me);

    RCC_GetClocksFreq(&__RCC_CLOCK);
    me->clock = __RCC_CLOCK.PCLK1_Frequency * 2; //APB1

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

    me->GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    me->GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    me->GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    me->GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    me->GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

    GPIO_Init(GPIOD, &me->GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_TIM4);

    TIM4_IRQHandler_ptf = TIM4_IRQ_PWM;
    me->NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
    me->NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    me->NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    me->NVIC_InitStructure.NVIC_IRQChannelCmd = 1;
    NVIC_Init(&me->NVIC_InitStructure);

    me->TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
    me->TIM_TimeBaseStructure.TIM_Prescaler = 840 - 1;
    me->TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
    me->TIM_TimeBaseStructure.TIM_ClockDivision= TIM_CKD_DIV1;
    me->TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

    TIM_TimeBaseInit(TIM4, &me->TIM_TimeBaseStructure);

    me->TIM_CH2_ICInitStructure.TIM_Channel         = TIM_Channel_2;
    me->TIM_CH2_ICInitStructure.TIM_ICPolarity      = TIM_ICPolarity_Rising;
    me->TIM_CH2_ICInitStructure.TIM_ICSelection     = TIM_ICSelection_DirectTI;
    me->TIM_CH2_ICInitStructure.TIM_ICPrescaler     = TIM_ICPSC_DIV1;
    me->TIM_CH2_ICInitStructure.TIM_ICFilter        = 0x0;

    TIM_PWMIConfig(TIM4, &me->TIM_CH2_ICInitStructure);
                                      // Select the TIM8 Input Trigger: TI1FP1
    TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2);
                                          // Select the slave Mode: Reset Mode
    TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset);

    TIM_SelectMasterSlaveMode(TIM4, TIM_MasterSlaveMode_Enable);
                           // Enables TIM8 peripheral Preload register on ARR.
    TIM_ARRPreloadConfig(TIM4, ENABLE);
    // Configures the TIM8 Update Request Interrupt source (SETS the CR1->URS bit)
    TIM_UpdateRequestConfig(TIM4, TIM_UpdateSource_Regular);

                            // Enable the CC1 and the update Interrupt Request
    TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE);

    TIM_ClearFlag(TIM4, TIM_FLAG_Update);
    TIM_Cmd(TIM4, ENABLE);
}

捕获/比较中断代码:

void TIM4_IRQHandler( void )
{
    if (TIM_GetITStatus(TIM4, TIM_IT_CC1) != RESET) {
        tmyPWMInput *pPWM4_1 = &myCTRL.myHW.myPortDCfg.myPWM4_1; //PIN12
                          // Clear TIM8 Capture Compare1 interrupt pending bit
        TIM_ClearITPendingBit(TIM4, TIM_IT_CC1);

        pPWM4_1->HighPeriod = TIM_GetCapture1(TIM4);       // length of high-portion
        pPWM4_1->FullPeriod = TIM_GetCapture2(TIM4);                 // total period
        myPWMCalc(pPWM4_1); //Calculate the frequency and duty cycle
    }

    if (TIM_GetITStatus(TIM4, TIM_IT_CC2) != RESET) {
        tmyPWMInput *pPWM4_2 = &myCTRL.myHW.myPortDCfg.myPWM4_2; //PIN13
                          // Clear TIM8 Capture Compare1 interrupt pending bit
        TIM_ClearITPendingBit(TIM4, TIM_IT_CC2);

        pPWM4_2->HighPeriod = TIM_GetCapture1(TIM4);       // length of high-portion
        pPWM4_2->FullPeriod = TIM_GetCapture2(TIM4);                 // total period
        myPWMCalc(pPWM4_2); //Calculate the frequency and duty cycle
    }
}

myPWMCalc 函数:

void myPWMCalc(tmyPWMInput *me)
{
    uint32_t myClk;
    uint32_t HighPeriod, FullPeriod;

    myClk = (me->clock / (me->TIM_TimeBaseStructure.TIM_Prescaler+1));

    // complete period of overflow
    FullPeriod = me->FullPeriod;
    HighPeriod = me->HighPeriod;

    if (FullPeriod < HighPeriod) // lost an overflow
    {
        FullPeriod += me->TIM_TimeBaseStructure.TIM_Period;
    }

    me->Frequency = (10 * myClk) / FullPeriod;
    me->DutyCycle = (10000 * HighPeriod) / FullPeriod;

    /* reset overflow */
    me->Overflow = 0;
}

如何读取从测试台收到的两个不同的 PWM 信号占空比? (频率测量正确)

我得到的输出:我计算的两个占空比相等,因为它们指向相同的频率信号,所以如果我断开另一个信号的电缆,我仍然读取两个 PWM 占空比。

我应该看到的是:占空比类似,当我断开一个信号时,断开信号的占空比应该为零。

c timer stm32
1个回答
0
投票

哪个STM32?

STM32参考手册(RM)TIM章节中描述的“PWM输入”“功能”需要一个定时器上的CH1CH2输入一个信号。这是合乎逻辑的 - 您希望硬件捕获两个参数(周期和高时间/占空比),为此,您需要两个硬件寄存器来捕获值。

该“功能”的工作原理是: 1. 在非直接连接的通道上使用“间接”捕获(在两个相对的边缘上捕获); 2. 使用定时器的从模式控制器的复位模式。因此,您无法将其用于两个信号,因为一个信号使用可用于此功能的两个通道,而且每个计时器只有一个从模式控制器。请阅读 RM 中“PWM 输入”的说明。

并且,您所做的是,第二个配置功能完全覆盖第一个配置功能的设置。

解决方案是 A. 使用两个计时器;或者,B. 如果边沿之间的距离保证始终足够远,则使用与同一定时器的两个通道上的两个信号的连接,并在两个通道的both边沿上使用捕获+中断,并计算周期/占空比每个通道独立于三个连续捕获的值。

我建议你选A。

PS.

使用的库:串行外设库

这里的 SPL 代表“标准外设库”,请注意,它可能已经被弃用了十年。

© www.soinside.com 2019 - 2024. All rights reserved.