shilut 发表于 2024-9-14 15:04

使用三个定时器输出PWM卡死

请教各位大牛一个问题,卡住我几天了。我使用如下定时器配置PWM,如下示:
PA6 -> PWM0    tim1_cha(4)
PA7 -> PWM1    tim2_cha(5)
PB0 -> PWM2    tim3_ch1b(2)
在应行如下初始化代码后,直接卡死了,请问是什么原因呢
void pwm_init()
{
    Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE); //端口外设时钟使能
    TimerPortCfg(PWM0);
    TimerPortCfg(PWM1);
    TimerPortCfg(PWM2);

    Timer1Cfg(100, PWM_DUTY);
    Bt_M23_EnPWM_Output(TIM1, TRUE, FALSE);   //端口输出使能

    Timer2Cfg(100, PWM_DUTY);
    Bt_M23_EnPWM_Output(TIM2, TRUE, FALSE);   //端口输出使能

    Timer3Cfg(100, PWM_DUTY);   
    Tim3_M23_EnPWM_Output(TRUE, FALSE);      //端口输出使能   

    Bt_M23_Run(TIM2);                        //运行。
    Bt_M23_Run(TIM1);                        //运行。
    Tim3_M23_Run();                            //运行。
}




完整模块代码发下:



#include "pwm.h"
#include "timer3.h"
#include "bt.h"
#include "gpio.h"
#include "motor.h"

volatile char pwm_duty = 95;

// PA6 -> PWM0    tim1_cha(4)
// PA7 -> PWM1    tim2_cha(5) 或 tim3_ch0b(4)
// PB0 -> PWM2    tim3_ch1b(2)

typedef enum
{
    PWM0= 0u,
    PWM1,   
    PWM2,   
}pwm_index_t;

/*******************************************************************************
* 中断服务函数
******************************************************************************/
void Tim1_IRQHandler(void)
{
    //Timer1 模式23 更新中断
    if(TRUE == Bt_GetIntFlag(TIM1,BtUevIrq)){
      Bt_M23_CCR_Set(TIM1, BtCCR0A, 100-pwm_duty); //设置通道A比较值
      Bt_ClearIntFlag(TIM1,BtUevIrq);//清中断标志
    }
}

void Tim2_IRQHandler(void)
{
    //Timer2 模式23 更新中断
    if(TRUE == Bt_GetIntFlag(TIM2,BtUevIrq))
    {
      Bt_M23_CCR_Set(TIM2, BtCCR0A, 100-pwm_duty); //设置通道A比较值
      Bt_ClearIntFlag(TIM2,BtUevIrq);//清中断标志
    }
}

void Tim3_IRQHandler(void)
{
    //Timer3 模式23 更新中断
    if(TRUE == Tim3_GetIntFlag(Tim3UevIrq)){
      Tim3_M23_CCR_Set(Tim3CCR1B, 100-pwm_duty); //设置CH1 通道B比较值         
      Tim3_ClearIntFlag(Tim3UevIrq);//清中断标志
    }
}

//Timer1 配置
void Timer1Cfg(uint16_t u16Period, uint16_t u16CHxACompare)
{
    uint16_t                     u16CntValue;
    uint8_t                      u8ValidPeriod;
    stc_bt_mode23_cfg_t          stcTim1BaseCfg;
    stc_bt_m23_compare_cfg_t   stcTim1PortCmpCfg;

    //结构体初始化清零
    DDL_ZERO_STRUCT(stcTim1BaseCfg);
    DDL_ZERO_STRUCT(stcTim1PortCmpCfg);

    Sysctrl_SetPeripheralGate(SysctrlPeripheralBTim, TRUE);   //Timer1外设时钟使能

    stcTim1BaseCfg.enWorkMode    = BtWorkMode2;             //锯齿波模式
    stcTim1BaseCfg.enCT          = BtTimer;               //定时器功能,计数时钟为内部PCLK
    stcTim1BaseCfg.enPRS         = BtPCLKDiv1;            //PCLK
    stcTim1BaseCfg.enCntDir      = BtCntUp;               //向上计数,在三角波模式时只读
    stcTim1BaseCfg.enPWMTypeSel= BtIndependentPWM;      //独立输出PWM
    stcTim1BaseCfg.enPWM2sSel    = BtSinglePointCmp;      //单点比较功能
    stcTim1BaseCfg.bOneShot      = FALSE;                     //循环计数
    stcTim1BaseCfg.bURSSel       = FALSE;                     //上下溢更新

    Bt_Mode23_Init(TIM1, &stcTim1BaseCfg);                        //TIM3 的模式23功能初始化

    Bt_M23_ARRSet(TIM1, u16Period, TRUE);                     //设置重载值,并使能缓存

    Bt_M23_CCR_Set(TIM1, BtCCR0A, u16CHxACompare);            //设置CH0比较值A


    stcTim1PortCmpCfg.enCH0ACmpCtrl   = BtPWMMode2;         //OCREFA输出控制OCMA:PWM模式2
    stcTim1PortCmpCfg.enCH0APolarity= BtPortPositive;   //正常输出
    stcTim1PortCmpCfg.bCh0ACmpBufEn   = TRUE;               //A通道缓存控制
    stcTim1PortCmpCfg.enCh0ACmpIntSel = BtCmpIntNone;       //A通道比较中断控制:无

    Bt_M23_PortOutput_Cfg(TIM1, &stcTim1PortCmpCfg);   //比较输出端口配置

    u8ValidPeriod = 0;                                        //事件更新周期设置,0表示锯齿波每个周期更新一次,每+1代表延迟1个周期
    Bt_M23_SetValidPeriod(TIM1, u8ValidPeriod);                   //间隔周期设置

    u16CntValue = 0;   
    Bt_M23_Cnt16Set(TIM1, u16CntValue);                           //设置计数初值

    Bt_ClearAllIntFlag(TIM1);                                 //清中断标志
    Bt_Mode23_EnableIrq(TIM1,BtUevIrq);                        //使能TIM1 UEV更新中断
    EnableNvic(TIM1_IRQn, IrqLevel0, TRUE);                   //TIM1中断使能
}

//Timer2 配置
void Timer2Cfg(uint16_t u16Period, uint16_t u16CHxACompare)
{
    uint16_t                     u16CntValue;
    uint8_t                      u8ValidPeriod;
    stc_bt_mode23_cfg_t          stcTim2BaseCfg;
    stc_bt_m23_compare_cfg_t   stcTim2PortCmpCfg;

    //结构体初始化清零
    DDL_ZERO_STRUCT(stcTim2BaseCfg);
    DDL_ZERO_STRUCT(stcTim2PortCmpCfg);

    Sysctrl_SetPeripheralGate(SysctrlPeripheralBTim, TRUE);   //Timer1外设时钟使能

    stcTim2BaseCfg.enWorkMode    = BtWorkMode2;             //锯齿波模式
    stcTim2BaseCfg.enCT          = BtTimer;               //定时器功能,计数时钟为内部PCLK
    stcTim2BaseCfg.enPRS         = BtPCLKDiv1;            //PCLK
    stcTim2BaseCfg.enCntDir      = BtCntUp;               //向上计数,在三角波模式时只读
    stcTim2BaseCfg.enPWMTypeSel= BtIndependentPWM;      //独立输出PWM
    stcTim2BaseCfg.enPWM2sSel    = BtSinglePointCmp;      //单点比较功能
    stcTim2BaseCfg.bOneShot      = FALSE;                     //循环计数
    stcTim2BaseCfg.bURSSel       = FALSE;                     //上下溢更新

    Bt_Mode23_Init(TIM2, &stcTim2BaseCfg);                        //TIM3 的模式23功能初始化

    Bt_M23_ARRSet(TIM2, u16Period, TRUE);                     //设置重载值,并使能缓存

    Bt_M23_CCR_Set(TIM2, BtCCR0A, u16CHxACompare);            //设置CH0比较值B


    stcTim2PortCmpCfg.enCH0ACmpCtrl   = BtPWMMode2;         //OCREFA输出控制OCMA:PWM模式2
    stcTim2PortCmpCfg.enCH0APolarity= BtPortPositive;   //正常输出
    stcTim2PortCmpCfg.bCh0ACmpBufEn   = TRUE;               //A通道缓存控制
    stcTim2PortCmpCfg.enCh0ACmpIntSel = BtCmpIntNone;       //A通道比较中断控制:无

    Bt_M23_PortOutput_Cfg(TIM2, &stcTim2PortCmpCfg);   //比较输出端口配置

    u8ValidPeriod = 0;                                        //事件更新周期设置,0表示锯齿波每个周期更新一次,每+1代表延迟1个周期
    Bt_M23_SetValidPeriod(TIM2, u8ValidPeriod);                   //间隔周期设置

    u16CntValue = 0;   
    Bt_M23_Cnt16Set(TIM2, u16CntValue);                           //设置计数初值

    Bt_ClearAllIntFlag(TIM2);                                 //清中断标志
    Bt_Mode23_EnableIrq(TIM2,BtUevIrq);                        //使能TIM3 UEV更新中断
    EnableNvic(TIM2_IRQn, IrqLevel0, TRUE);                   //TIM3中断使能
}


//Timer3 配置
void Timer3Cfg(uint16_t u16Period, uint16_t u16CHxBCompare)
{
    uint16_t                     u16CntValue;
    uint8_t                      u8ValidPeriod;
    stc_tim3_mode23_cfg_t      stcTim3BaseCfg;
    stc_tim3_m23_compare_cfg_t   stcTim3PortCmpCfg;

    //结构体初始化清零
    DDL_ZERO_STRUCT(stcTim3BaseCfg);
    DDL_ZERO_STRUCT(stcTim3PortCmpCfg);

    Sysctrl_SetPeripheralGate(SysctrlPeripheralTim3, TRUE);   //Timer3外设时钟使能

    stcTim3BaseCfg.enWorkMode    = Tim3WorkMode2;             //锯齿波模式
    stcTim3BaseCfg.enCT          = Tim3Timer;               //定时器功能,计数时钟为内部PCLK
    stcTim3BaseCfg.enPRS         = Tim3PCLKDiv1;            //PCLK
    stcTim3BaseCfg.enCntDir      = Tim3CntUp;               //向上计数,在三角波模式时只读
    stcTim3BaseCfg.enPWMTypeSel= Tim3IndependentPWM;      //独立输出PWM
    stcTim3BaseCfg.enPWM2sSel    = Tim3SinglePointCmp;      //单点比较功能
    stcTim3BaseCfg.bOneShot      = FALSE;                     //循环计数
    stcTim3BaseCfg.bURSSel       = FALSE;                     //上下溢更新

    Tim3_Mode23_Init(&stcTim3BaseCfg);                        //TIM3 的模式23功能初始化

    Tim3_M23_ARRSet(u16Period, TRUE);                     //设置重载值,并使能缓存

    Tim3_M23_CCR_Set(Tim3CCR1B, u16CHxBCompare);            //设置CH1比较值B

    stcTim3PortCmpCfg.enCHxBCmpCtrl   = Tim3PWMMode2;         //OCREFB输出控制OCMB:PWM模式2(PWM互补模式下也要设置,避免强制输出)
    stcTim3PortCmpCfg.enCHxBPolarity= Tim3PortPositive;   //正常输出
    stcTim3PortCmpCfg.bCHxBCmpBufEn   = TRUE;               //B通道缓存控制使能
    stcTim3PortCmpCfg.enCHxBCmpIntSel = Tim3CmpIntNone;       //B通道比较中断控制:无

    // Tim3_M23_PortOutput_Cfg(Tim3CH0, &stcTim3PortCmpCfg);   //比较输出端口配置
    Tim3_M23_PortOutput_Cfg(Tim3CH1, &stcTim3PortCmpCfg);   //比较输出端口配置

    u8ValidPeriod = 0;                                        //事件更新周期设置,0表示锯齿波每个周期更新一次,每+1代表延迟1个周期
    Tim3_M23_SetValidPeriod(u8ValidPeriod);                   //间隔周期设置

    u16CntValue = 0;

    Tim3_M23_Cnt16Set(u16CntValue);                           //设置计数初值

    Tim3_ClearAllIntFlag();                                 //清中断标志
    Tim3_Mode23_EnableIrq(Tim3UevIrq);                        //使能TIM3 UEV更新中断
    EnableNvic(TIM3_IRQn, IrqLevel0, TRUE);                   //TIM3中断使能
}

void TimerPortCfg(pwm_index_t pwm_index)
{
    stc_gpio_cfg_tstcTIMPort;

    DDL_ZERO_STRUCT(stcTIMPort);      
    stcTIMPort.enDir= GpioDirOut;

    switch (pwm_index){
    case PWM0:
      Gpio_Init(GpioPortA, GpioPin6, &stcTIMPort);
      Gpio_SetAfMode(GpioPortA,GpioPin6,GpioAf4);               //PA6 -> PWM0    tim1_cha(4)
      break;
    case PWM1:
      Gpio_Init(GpioPortA, GpioPin7, &stcTIMPort);
      Gpio_SetAfMode(GpioPortA,GpioPin7,GpioAf5);               //PA7 -> PWM1    tim2_cha(5)
      break;
    case PWM2:
      Gpio_Init(GpioPortB, GpioPin0, &stcTIMPort);
      Gpio_SetAfMode(GpioPortB,GpioPin0,GpioAf2);               //PB0 -> PWM2    tim3_ch1b(2)
      break;
    default:
      break;
    }

}

void TimerPortDeiniCfg(pwm_index_t pwm_index)
{
    stc_gpio_cfg_t stcTIMPort;

    DDL_ZERO_STRUCT(stcTIMPort);      
    stcTIMPort.enDir= GpioDirOut;

    switch (pwm_index){
    case PWM0:
      Gpio_Init(GpioPortA, GpioPin6, &stcTIMPort);
      Gpio_SetAfMode(GpioPortA,GpioPin6,GpioAf0);
      Gpio_ClrIO(GpioPortA, GpioPin6);
      break;
    case PWM1:
      Gpio_Init(GpioPortA, GpioPin7, &stcTIMPort);
      Gpio_SetAfMode(GpioPortA,GpioPin7,GpioAf0);               //PA7 -> PWM1    tim2_cha(5)
      Gpio_ClrIO(GpioPortA, GpioPin7);
      break;
    case PWM2:
      Gpio_Init(GpioPortB, GpioPin0, &stcTIMPort);
      Gpio_SetAfMode(GpioPortB,GpioPin0,GpioAf0);               //PB0 -> PWM2    tim3_ch1b(2)
      Gpio_ClrIO(GpioPortB, GpioPin0);
      break;   
    default:
      break;
    }
}


// -----------pwm enable
void pwm0_enable(uint8_t duty)
{
    TimerPortCfg(PWM0);
    if (duty > 100){
      duty = 100;
    }
    pwm_duty = duty;
    Bt_M23_Run(TIM1);   
}

void pwm1_enable(uint8_t duty)
{
    TimerPortCfg(PWM1);
    if (duty > 100){
      duty = 100;
    }
    pwm_duty = duty;
    Bt_M23_Run(TIM2);   
}

void pwm2_enable(uint8_t duty)
{
    TimerPortCfg(PWM2);
    if (duty > 100){
      duty = 100;
    }
    pwm_duty = duty;   
    Tim3_M23_Run();
}

// -----------pwm disable
void pwm0_disable(void)
{
    Bt_M23_Stop(TIM1);
    TimerPortDeiniCfg(PWM0);
}

void pwm1_disable(void)
{
    Bt_M23_Stop(TIM2);
    TimerPortDeiniCfg(PWM1);
}

void pwm2_disable(void)
{
    Tim3_M23_Stop();
    TimerPortDeiniCfg(PWM2);
}

shilut 发表于 2024-9-18 11:13

已解决

CJL906234 发表于 2024-9-18 18:29

使用三个定时器输出PWM卡死

谢谢

两只袜子 发表于 2024-9-19 15:59

什么原因导致的

shenxiaolin 发表于 2024-9-29 10:54

应该是不同的通道吧?

更多更合适ii 发表于 2024-9-30 17:25

在 pwm_init() 中调用 Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);,但确保所有必要的定时器外设时钟(SysctrlPeripheralBTim 和 SysctrlPeripheralTim3)也在初始化前已被使能。

肥肠虾头商迪 发表于 2025-7-24 17:55

怎么解决的呀?
页: [1]
查看完整版本: 使用三个定时器输出PWM卡死