This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] CCS/MSP430F5529:使用中断驱动的定时器库生成具有特定规格的 PWM 波形。

Guru**** 2589245 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/746615/ccs-msp430f5529-generating-a-pwm-waveform-with-particular-specification-using-interrupt-driven-timer-library

器件型号:MSP430F5529
主题中讨论的其他器件:MSPWARE

工具/软件:Code Composer Studio

原始主题:-e2e.ti.com/.../737345

#include "driverlib.h"

#define TIMER_PERIOD 13105
#define DUTY 周期 CAPT82

void main (void)
{
//停止 WDT
WDT_A_HOLD (WDT_A_base);

// P2.0作为 PWM 输出
GPIO_setAsModuleFunctionOutputPin (
GPIO_port_param_param_param_timer




)



param.compareRegister;// param_param_param_param_param_param_param_param_param_param0 = gp0;// param_timer_param_param_param_param_param_param_param_param_param_param_param_param_param_param_param_param_timer = 1;// param_timer_timer_param_param_param_param_param_param_param_param_param_param_param_param_param_param_tim
param.compareOutputMode = TIMER_A_OUTPUTDE_RESET_SET;
param.dutyCycle = Duty_cycle;
Timer_A_outputPWM (TIMER_A1_base、&param);

//Enter LPM0
___ bis_SR_register (LPM0_BITS);

//对于调试器
__no_operation();
} 

我已经编写了这个 基于 OutputPWM 的 MSPware 代码、生成了我需要的波形。 我希望在切换输出时能够控制相同的事情、或许可以进行一些处理。 根据我所知、这只能使用 ISR 来完成、MSPware 计时器库提供了 Timer_up/down/updown 以及捕获和比较。 但是、我无法使其符合所需的规格[4S 总周期、~25ms 导通时间]。 可以有人帮助我吗?  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您为什么不配置或启用中断? 这很可能是您的代码无法正常工作的原因之一。 请查看我们的计时器 PWM DriverLib 代码示例、并将其与您正在执行的操作进行比较。

    Timer_A_Ex5_pwmMultipleUp.c

    /*-版权所有-、BSD
    *版权所有(c) 2017、德州仪器(TI)公司
    *保留所有权利。
    *
    *
    只要
    符合以下条件*、允许以源代码和二进制形式重新分发和使用:
    *
    *源代码的重新分发必须保留上述版权
    声明*、此条件列表和以下免责声明。
    *
    ***二进制形式的再发行必须在
    
    *随发行提供的文档和/或其他材料中复制上述版权声明、本条件列表和以下免责声明。
    *
    ***未经
    
    事先书面许可、不得使用德州仪器公司的名称或*其贡献者的名称认可或推广从本软件衍生的产品*。
    *
    *本软件由版权所有者和贡献者"按原样"提供
    *、
    
    不承担任何明示或暗示的保证、包括但不限于*适销性和特定用途适用性的暗示保证*。 在任何情况下、版权所有者或
    *贡献者都不对任何直接、间接、偶然、特殊、
    *模范、 或相应的损害(包括但不限于
    *采购替代产品或服务;丧失使用、数据或利润;
    *或业务中断)、但出于任何责任理论
    、*无论是在合同中、严格责任还是由于
    使用本软件而以任何方式产生的侵权行为(包括疏忽或*其他)
    、*即使已获悉可能会发生此类损坏。
    *--/版权--*//*********
    
    //! 该程序使用
    //!在 P2.0、P2.1上生成两个 PWM 输出 Timer1_A 已配置为向上计数模式。 CCR0中的值512-1定义了 PWM
    //! 以及 CCR1和 CCR2中 PWM 占空比的值。 使用~1.045MHz
    //! SMCLK 作为 TACLK、定时器周期为~500us、P2.2上的占空比为75%
    //! P2.3为25%。
    //! ACLK = n/a、SMCLK = MCLK = TACLK =默认 DCO ~1.045MHz。
    //!
    //! 测试对象:MSP430F5529
    //! ----------
    //! /|\| |
    //! || |
    //! -|RST |
    //! | |
    //! | P2.0/TA1.1|->CCR1 - 75% PWM
    //! | P2.1/TA1.2|->CCR2 - 25% PWM
    //!
    //! 此示例使用以下外设和 I/O 信号。 您必须
    //! 查看这些内容并根据您自己的董事会需要进行更改:
    //! -定时器外设
    //! - GPIO 端口外设
    //!
    //! 此示例使用以下中断处理程序。 要使用此示例
    //! 在您自己的应用程序中、您必须将这些中断处理程序添加到
    您的//! 矢量表。
    //! -无
    //!
    //
    
    #include "driverlib.h"
    
    #define TIMER_PERIOD 511
    #define Duty_Cycl1 384
    #define Duty_CYCLE2 128
    
    void main (void)
    {
    //停止 WDT
    WDT_A_HOLD (WDT_A_base);
    
    //P2.0和 P2.1输出
    //P2.0和 P2.1选项选择
    GPIO_setPeripheralModuleFunctionOutputPin (
    GPIO_PORT_P2、
    GPIO_PIN0 + GPIO_PIN1
    );
    
    //启动计时器
    Timer_A_initUpModeParam initUpParam ={0};
    initUpParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
    initUpParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_divider;
    initUpParam.timerPeriod = timer_period;
    initUpParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;
    initUpParam.captureCompareInterruptEnable_CCR0_CCIE =
    Timer_A_CCIE_CCR0_INTERRUPT_DISABLE;
    initUpParam.timerClear = timer_a_do _clear;
    initUpParam.startTimer = false;
    Timer_A_initUpMode (timer_A1_base、&initUpParam);
    
    Timer_A_startCounter (timer_A1_base、
    Timer_A_up_mode
    );
    
    //初始化比较模式以生成 PWM1
    Timer_A_initCompareModeParam initComp1Param ={0};
    initComp1Param.compareRegister = TIMER_A_CAPTURECMPARE 寄存器_1;
    initComp1Param.compareInterruptEnable = TIMER_A_CAPTURECMPARE INTERRUPT_DISABLE;
    initComp1Param.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;
    initComp1Param.compareValue = Duty_Cyclle1;
    Timer_A_initCompareMode (timer_A1_base、&initComp1Param);
    
    //初始化比较模式以生成 PWM2
    Timer_A_initCompareModeParam initComp2Param ={0};
    initComp2Param.compareRegister = TIMER_A_CAPTURECMPARE 寄存器_2;
    initComp2Param.compareInterruptEnable = TIMER_A_CAPTURECMPARE INTERRUPT_DISABLE;
    initComp2Param.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;
    initComp2Param.compareValue = Duty_CYCLE2;
    Timer_A_initCompareMode (timer_A1_base、&initComp2Param);
    
    //Enter LPM0
    _bis_SR_register (LPM0_bits);
    
    //用于调试器
    __no_operation();
    } 

    此致、

    James

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    大家好、James、是的、我已经看过这个示例、我也将在一段时间后发布我的代码。 但您发布的示例不使用 ISR。 我很想使用 ISR、因为我想在我的脉冲处于导通周期时设置一个标志、并在 ISR 完成后复位。 我不想我可以使用该代码执行该操作。 此外、我想知道、在 P2.0上的这个代码中有一个占空比为75%的脉冲、而在 P2.1上有另外一个脉冲?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    这里是我的代码、当控制进入 ISR 时、我不会获得所需的规格脉冲。 我不确定应该切换引脚的 ISR。 并且我无法触发 ISR

    #include "driverlib.h"

    #define TIMER_PERIOD 13105
    #define Duty_Cyclle1 82
    #define DUTY CYCLE2 128

    void main (void)

    //停止 WDT
    WDT_A_HOLD (WDT_A_base);

    //P2.0和 P2.1输出
    //P2.0和 P2.1选项选择
    GPIO_setPeripheralModuleFunctionOutputPin (
    GPIO_PORT_P2、
    GPIO_PIN0 + GPIO_PIN2
    );

    //启动计时器
    Timer_A_initUpModeParam initUpParam ={0};
    initUpParam.clockSource = TIMER_A_CLOCKSOURCE_ACLK;
    initUpParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_divider;
    initUpParam.timerPeriod = timer_period;
    initUpParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE;
    initUpParam.captureCompareInterruptEnable_CCR0_CCIE =
    Timer_A_CCIE_CCR0_INTERRUPT_ENABLE;
    initUpParam.timerClear = timer_a_do _clear;
    initUpParam.startTimer = false;
    Timer_A_initUpMode (timer_A1_base、&initUpParam);

    Timer_A_startCounter (timer_A1_base、
    Timer_A_up_mode
    );

    //初始化比较模式以生成 PWM1
    Timer_A_initCompareModeParam initComp1Param ={0};
    initComp1Param.compareRegister = TIMER_A_CAPTURECMPARE 寄存器_1;
    initComp1Param.compareInterruptEnable = TIMER_A_CAPTURECMPARE INTERRUPT_ENABLE;
    initComp1Param.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;
    initComp1Param.compareValue = Duty_Cyclle1;
    Timer_A_initCompareMode (timer_A1_base、&initComp1Param);

    //初始化比较模式以生成 PWM2
    Timer_A_initCompareModeParam initComp2Param ={0};
    initComp2Param.compareRegister = TIMER_A_CAPTURECMPARE 寄存器_2;
    initComp2Param.compareInterruptEnable = TIMER_A_CAPTURECMPARE INTERRUPT_ENABLE;
    initComp2Param.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;
    initComp2Param.compareValue = Duty_Cyclle1;
    Timer_A_initCompareMode (timer_A1_base、&initComp2Param);

    //Enter LPM0
    _bis_SR_register (LPM0_bits);

    //用于调试器
    __no_operation();

    #if defined (__TI_Compiler_version__)|| Defined (__IAR_systems_ICC__)
    #pragma vector=Timer1_A1_vector
    _interrupt
    #Elif defined (_GNU_)
    __attribute__((interrupt (Timer1_A1_vector))
    #endif
    空 Timer1_A0_ISR (空)

    uint16_t compVal = Timer_A_getCaptureCompareCount (timer_A1_base、
    Timer_A_CAPTURECOMPARE 寄存器0)
    + Duty_Cyclle1;

    //切换 P1.0
    GPIO_toggleOutputOnPin (
    GPIO_PORT_P2、
    GPIO_PIN0
    );

    //将偏移添加到 CCR0
    Timer_A_setCompareValue (timer_A1_base、
    Timer_A_CAPTURECMPARE 寄存器0、
    COMPVal
    );

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    > GPIO_setPeripheralModuleFunctionOutputPin (GPIO_PORT_P2、GPIO_PIN0 + GPIO_PIN2);
    拼写错误警报:我认为您是指:
    > GPIO_setPeripheralModuleFunctionOutputPin (GPIO_PORT_P2、GPIO_PIN0 + GPIO_PIN1);// TA1.1、TA1.2
    --------
    您没有收到中断、因为没有任何东西可以全局启用中断(GIE)。 替换:
    >_bis_SR_register (LPM0_bits);
    使用
    >_bis_SR_register (LPM0_bits | GIE);
    --------
    由于您是在向上计数模式下运行、因此不应执行以下操作:
    > Timer_A_setCompareValue (timer_A1_base、timer_A_CAPTURECOMPARE 寄存器_0、compVal);
    因为它会使周期变得越来越长、直到它换行并且变得非常短。 只需删除此行。
    --------
    如果您希望存储器内标志映射 PWM 的当前设置:您知道它何时在 Timer1_A0_vector 中变为低电平(复位/设置)。 要知道它何时变为高电平、需要定义 Timer1_A1_vector 以捕获(并复位) CCR1和 CCR2 CCIFG。

    或者:考虑直接检查 P2IN、因为在任何时候它都会反映引脚的状态。 [数据表中的参考引脚原理图(SLAS590N)图 6-3. 我认为用户指南也提到了这一点、但我忘记了在哪里。]
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我使用了引脚0和引脚2、因为这些引脚是电路板上可用的引脚、可用作分线引脚。

    2.是的、在不启用中断时出错。

    3、是的、对我的代码进行了更改、这里是我的新代码。 实质上、我需要类似于消息中附加的波形的东西。 在高电平期间、我想打开 ADC 通道 A0。 我的想法[根据新代码以正确的方向]:

    代码片段和相关部分:

    void configureTimerForSensorPulse ()

    Timer_A_initUpDownModeParam initUpDownParam ={0};
    initUpDownParam.clockSource = TIMER_A_CLOCKSOURCE_ACLK;
    initUpDownParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_divider;
    initUpDownParam.timerPeriod = timer_period;
    initUpDownParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;
    initUpDownParam.captureCompareInterruptEnable_CCR0_CCIE =
    Timer_A_CCIE_CCR0_INTERRUPT_DISABLE;
    initUpDownParam.timerClear = TIMER_A_DO _清除;
    initUpDownParam.startTimer = false;
    Timer_A_initUpDownMode (timer_A0_BASE、&initUpDownParam);

    //初始化比较寄存器以生成 PWM1
    Timer_A_initCompareModeParam initComp1Param ={0};
    initComp1Param.compareRegister = TIMER_A_CAPTURECMPARE 寄存器_1;
    initComp1Param.compareInterruptEnable =
    Timer_A_CAPTURECOMPARE 中断_ENABLE;
    initComp1Param.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;
    initComp1Param.compareValue = Duty_cycle;
    Timer_A_initCompareMode (timer_A0_BASE、&initComp1Param);

    //初始化比较寄存器以生成 PWM2
    Timer_A_initCompareModeParam initComp2Param ={0};
    initComp2Param.compareRegister = TIMER_A_CAPTURECMPARE 寄存器_2;
    initComp2Param.compareInterruptEnable =
    Timer_A_CAPTURECOMPARE 中断_ENABLE;
    initComp2Param.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;
    initComp2Param.compareValue = Duty_cycle;
    Timer_A_initCompareMode (timer_A0_BASE、&initComp2Param);

    Timer_A_initCompareModeParam initComp3Param ={0};
    initComp3Param.compareRegister = TIMER_A_CAPTURECMPARE 寄存器_3;
    initComp3Param.compareInterruptEnable =
    Timer_A_CAPTURECOMPARE 中断_ENABLE;
    initComp3Param.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;
    initComp3Param.compareValue = Duty_cycle;
    Timer_A_initCompareMode (timer_A0_BASE、&initComp3Param);

    #if defined (__TI_Compiler_version__)|| Defined (__IAR_systems_ICC__)
    #pragma vector=TIMER0_A1_vector
    _interrupt
    #Elif defined (_GNU_)
    __attribute__((interrupt (TIMER0_A1_vector))
    #endif
    空 Timer1_A1_ISR (空)

    开关(__evo_in_range (TA0IV、10))

    情况0x00:
    中断;
    情况0x02:
    adcSensor1Enable = 0;
    中断;
    情况0x04:
    adcSensor2Enable = 0;
    中断;
    情况0x06:
    adcSensor3Enable = 0;
    中断;// CCR3 IFG
    情况0x08:
    中断;// CCR4 IFG
    情况0x0A:
    中断;// CCR5 IFG
    情况0x0C:
    中断;// CCR6 IFG
    案例0x0E:// TA0IFG
    中断;
    默认值:
    中断;


    _BIC_SR_REGISTER_ON_EXIT (LPM4_BITS);
    //__no_operation();

    void main (void)

    //这些标志是全局变量:

    adcSensor1Enable = 1;
    adcSensor2Enable = 1;
    adcSensor3Enable = 1;

    //停止 WDT
    WDT_A_HOLD (WDT_A_base);

    configureTimerForSensorPulse ();

    configureADC();

    _enable_interrupt ();

    startadc ();

    while (1)

    //如果任何标志为低电平,则意味着 ADC 捕捉应该开始
    if (adcSensor1Enable = 0 || adcSensor2Enable = 0
    || adcSensor3Enable = 0)

    ADC12_A_startConversion (ADC12_A_base、
    ADC12_A_MEMORY_0、
    ADC12_A_SEQOFCHANNELS);

    //在所有值都为低电平时停止 ADC 捕捉
    if (adcSensor1Enable = 0 && adcSensor2Enable = 0
    && adcSensor3Enable = 0)

    adcSensor1Enable = 1;
    adcSensor2Enable = 1;
    adcSensor3Enable = 1;


    //Enter LPM4、启用中断
    _bis_SR_register (LPM4_bits + GIE);
    //用于调试器
    __no_operation();

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您是否了解了直接查看 PWM 值的相关内容? 即、将 PWM 输出视为输入并对其进行读取? 这将解决您的问题、无需中断。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    不是、我不理解该部分。 我该怎么做?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    要回答这个问题:我刚才提到过、任何时候(P1IN&BIT2)都会告诉您 TA0.1 (CCR1)输出是高电平还是低电平。 这提供了您之前询问的指示、但您无法清除它、因为您的新代码显然需要清除。

    更一般地说:您的问题已发生重大变化。 我无法想象使用单个计时器生成3种不同的非对称(或者:死区时间)波形的方法、即使在向上/向下计数模式下也是如此。 也许这里的一个向导知道得更好。 可能存在 DMA 技巧。

    此时、我将介绍软件 PWM。 在25ms 脉冲下、延迟/抖动的几微秒可能不会明显。 有一种软件 PWM 变体、它不是直接操纵 P1OUT 位、而是在运行时操纵 CCR、为下一个计时器事件做好准备; 这与简单的软件 PWM 大致相同、但由于硬件会生成边沿、因此可以避免延迟/抖动。

    它甚至可能是较少的代码:CCR1中断会关闭 TA0.1、打开 TA0.2 (并启动 ADC)、CCR2中断会关闭 TA0.2和 TA0.3、等等。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我的当前代码实际上会生成3个脉冲、每个脉冲具有4秒的周期和25毫秒的导通时间。 但是、我最希望在导通期间打开 ADC。 我在某种程度上找到了一种使下游 电路不需要生成非对称 波形的方法。 我认为我的当前代码在这方面无法正常工作。  

    假设我甚至不需要3个波形、如何在导通期间打开 ADC。 当 PWM 处于开启状态时、除了中断之外、我想不到任何其他东西。 我的想法是否正确?   

       

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    当我读取此代码时、它将生成三个同步脉冲、并在它们(同时)变为有效(低电平)时启动 ADC。 如果要在 ADC 变为高电平时启动、则需要设置/复位、而不是重置/设置。

    我假设您已正确配置了引脚和 ADC。

    您当时在想什么呢? 我想我逐渐不太清楚您的目标是什么。