问答

汇集网友智慧,解决技术难题

21ic问答首页 - 使用两个定时器输出PWM卡死

定时器 输出 使用 PWM 国产芯片 单片机

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

shilut2024-09-14
请教各位大牛一个问题,卡住我几天了。我使用如下定时器配置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_t  stcTIMPort;

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


回答 +关注 4
3327人浏览 8人回答问题 分享 举报
8 个回答

您需要登录后才可以回复 登录 | 注册