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/MSP430G2553:使用中断的定时器脉宽调制示例

Guru**** 2543090 points
Other Parts Discussed in Thread: MSP430G2553

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/589296/ccs-msp430g2553-timer-pulse-width-modulation-using-interrupts-example

器件型号:MSP430G2553

工具/软件:Code Composer Studio

大家好、有人能给我一个使用 TimerA 通过中断生成 PWM 的示例吗?

我的代码继续标记 CCR0中断。  

// MSP430G2553
//----------
//|            |
//|            |
//|   P1.3/TA1|--> PWM
//

int main (空)

WDTCTL = WDTPW + WDTHOLD;//停止 WDT

P1DIR |= BIT3;//计时器的 PWM 输出

TA1CCR0 = 100;//frequency
TA1CCR1 = 50;//占空比
TA1CCTL0 |= CCIE + OUTMOD_7;//启用 TBCCR0中断
TA1CCTL1 |= CCIE + OUTMOD_7;//启用 TBCCR0中断
_bis_SR_register (GIE);//输入 LPM0、启用中断

 while (1){}

#pragma vector=Timer1_A0_vector
_interrupt void Timer1_A0_ISR (void)

    P1OUT |= BIT3;  

#pragma vector=Timer1_A1_vector
_interrupt void Timer1_A1_ISR (void)

/*任何对 TBIV 寄存器的访问、读取或写入都会自动复位
最高"挂起"中断标志。 *
switch (__even_in_range (TA1IV、14))

情况0:中断;//无中断
案例2:

    P1OUT &=~BIT3;//结束 PWM

中断;  
案例4:
中断;  
案例6:中断;//未使用 CCR3
案例8:中断;//未使用 CCR4
案例10:中断;//未使用 CCR5
情况12:中断;//未使用 CCR6
案例14://溢出
中断;
默认值:break;

抱歉、未格式化的代码。 希望有道理。

谢谢、

Scott

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

    要获取格式化代码、请使用"插入代码"按钮。

    "持续标记 CCR0中断"到底意味着什么? 据我所见、您永远不会启动计时器、因此不会发生任何情况。

    请确保注释正确;此代码不会进入 LPM0。

    TI 的示例代码并非总是完美的;请使用 TA1IV_TACCR1之类的符号、而不是像2这样的魔术数字。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    MSP430G2553
    //---
    //| |
    //| |
    //| P1.3/TA1|->PWM
    //
    
    int main (void)
    { 
    WDTCTL = WDTPW + WDTHOLD;//停止 WDT P1DIR |= BIT3;//计时器的 PWM 输出 TA1CCR0 = 100;//frequency TA1CCR1 = 50;//占空比 TA1CCTL0 |= CCIE + OUTMOD_7;//启用 TBCCR0中断 TA1CCTL1 |= CCIE + OUTMOD_7;//启用 TBCCR0中断 _bis_SR_register (GIE);//启用中断

             __no_operation();//用于调试器
             TA1CTL = ID_0 + TASSEL_2 + MC_1 + TACLR;//向上计数模式、SMCLK、清零  

    while (1){#pragma
    
    vector=Timer1_A0_vector
    __interrupt void Timer1_A0_ISR (void)
    {
    P1OUT |= BIT3;
    }
    
    #pragma vector=Timer1_A1_vector
    __interrupt void Timer1_A1_ISR (void)
    {
    //对 TBIV 寄存
    器的任何访问、读取或写入都会自动复位最高的"挂起"中断标志。 */
    switch (__even_in_range (TA1IV、14))
    {
    案例0:中断;//无中断
    案例2:
    
    P1OUT &=~BIT3;//结束 PWM
    
    中断;
    案例4:
    中断;
    案例6:中断;// CCR3未使用
    案例8:中断;// CCR4未使用
    案例10:中断;// CCR5未使用
    案例12:中断;// CCR6未使用
    案例14://溢出
    中断;
    默认:中断;
    }
    

     我不确定我是否正确使用了"插入代码"。 我认为我仍然做得不对、因为它看起来仍然很不正式。 我在 Windows 环境中直接从 CCS 复制。 也许有一种更好的方法来插入 CCS 代码(并且仍然能够擦除我不想要的东西)。

    否则、我重新发布了我的代码、这次将 TA1CTL 寄存器设置为启动计时器。  

    此外、我还有 TA1CCR0和 TA1CCR0的魔法数字、但用频率和 PWM 注释。 抱歉。

    他们还有其他的魔法数字出现在 ISR 中、我也将其留在那里、因为这是我从 TI 资源管理器复制的代码。

    谢谢您、我希望这一点更清晰。 请告诉我它是否不是标准/不清楚。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我的意思是"持续标记 CCR0中断":我单步执行我的代码、然后 Tair 计数到 TA1CCR1、这会设置 CCR1中断标志 CCIFG。 然后它调用 Timer1_A1 ISR。 该部分似乎正常工作(实际上我在 Timer1_A1中设置了一个断点、因为您无法单步进入该断点、因为根据另一篇文章、调试器将损坏 TAIV)。 但是、否则、它看起来会按预期工作。

    然后、我单步执行并观察 Tair 计数到 TA1CCR1。 当 Tair 计数到 TA1CCR1时、它运行 Timer1_A0_ISR。 我可以看到它设置了 TA1CCR0 CCIFG。 然后、Timer1_A0_ISR 内的单步执行将复位 CCIFG。 但是、再次单步执行 CCIFG 已设置! 因此、我永远不会退出 Timer1_A0_ISR。

    此外、我的理解是、Tair 应该由 CCR0复位、但我看不到这种情况。
    谢谢、
    Scott
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    校正:
    我的意思是"持续标记 CCR0中断":我单步执行我的代码、然后 Tair 计数到 TA1CCR1、这会设置 CCR1中断标志 CCIFG。 然后它调用 Timer1_A1 ISR。 该部分似乎正常工作(实际上我在 Timer1_A1_ISR 中设置了断点、因为您无法单步进入该中断点、因为根据另一篇文章、调试器将损坏 TAIV)。 但是、否则、它看起来会按预期工作。

    然后、我单步执行并观察 Tair 计数到 TA1CCR0。 当 Tair 计数到 TA1CCR0时、它运行 Timer1_A0_ISR。 我可以看到它设置了 TA1CCR0 CCIFG。 然后、Timer1_A0_ISR 内的单步执行将复位 CCIFG。 但是、再次单步执行 CCIFG 已设置! 因此、我永远不会退出 Timer1_A0_ISR。

    此外、我的理解是、Tair 应该由 CCR0复位、但我看不到这种情况。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    仅仅是因为 TI 使用了魔法数字并不意味着您必须满腔关注;您可以做得更好:

    开关(TA1IV)
    {
    案例 TA1IV_TACCR1:
    P1OUT &=~BIT3;
    break;
    case TA1IV_TACCR2:
    中断;
    案例 TA1IV_TAIFG:
    中断;
    默认:
    中断;
    } 

    (由于使用了幻数、编写该代码的任何人都没有注意到 G2553计时器没有六个 CCR。)

    总之、您的时钟速度有多快? 我怀疑单步执行的速度是否足够快、可以注意到计时器运行了100个周期。 (要观察 PWM 输出、请使用示波器或逻辑分析仪。)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    // MSP430G2553
    //
    //说明:使用定时器 TA1。
    // TA1:PWM 输出
    //
    
    //// MSP430G2553
    // --------
    // | |
    // | |
    // | P1.3/TA1|->PWM
    //
    
    #include 
    #define TA1IV_TACCR12
    #define TA1IV_TACCR24
    #define PWM_FREQUENCY100
    #define PWM_Duty_cycle50
    
    int main (void)
    {
    WDTCTL = WDTPW + WDTHOLD; //停止 WDT
    P1DIR |= BIT3;//来自 TimerA
    
    TA1CCR0的 PWM 输出= PWM_FREQUENCY;//频率
    TA1CCR1 = PWM_Duty_cycle; //占空比
    TA1CCTL0 |= CCIE;// TBCCR0中断使能
    TA1CCTL1 |= CCIE;//启用 TBCCR1中断
    
    _bis_SR_register (GIE);//启用中断
    __no_operation(); //对于调试器
    TA1CTL = ID_0 + tassel_2 + MC_1 + TACLR;//向上计数模式、div 8
    
    while (1){
    //
    *一些代码
    */
    _ no_operation ();
    }
    
    }
    
    
    // PWM 输出
    //此 ISR 通过设置 TA1 CCR0来确定 PWM 信号的频率
    // Timer1_A0 =计时器 A1 CCR0
    #pragma vector=Timer1_A0_vector
    __interrupt void Timer1_A0_ISR (void)
    {
    P1OUT |= BIT0;//开始 PWM
    }
    
    
    
    // Timer_A3中断矢量(TBIV)处理程序
    // PWM 输出
    //此 ISR 通过设置 TA1 CCR1来确定 PWM 信号的脉冲宽度
    // Timer1_A1 =计时器 A1 CCR1-?
    #pragma vector=Timer1_A1_vector
    __interrupt void Timer1_A1_ISR (void)
    {
    //对 TBIV 寄存
    器的任何访问、读取或写入都会自动复位最高的"挂起"中断标志。 */
    switch (__even_in_range (TA1IV、14)))
    {
    情况0:中断; //无中断
    案例 TA1IV_TACCR1:
    P1OUT &=~BIT3; //结束 PWM
    中断; // CCR1脉冲宽度
    案例 TA1IV_TACCR2:
    中断; //未使用 CCR2
    默认值:中断;
    }
    }
    
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    好的、我清理了我的代码。 这看起来更好吗? 感谢您的提示、我看到您对魔术编号的理解。 如果您发现编码风格存在任何其他问题、请告诉我。

    现在死区时间卡在 Timer1_A0_ISR 中。 我尝试重置 ISR 内部的 CCIFG、但仍有一些问题正在解决、因此我永远不会退出 CCR0中断服务例程。
    谢谢、
    Scott
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    TA1IV_TACCRx 符号已在头文件中定义;请勿重新定义它们。

    用户指南第12.2.6.1节规定:

    当 TACCR0中断请求被服务时、TACCR0 CCIFG 标志会自动复位。

    因此 Timer1_A0_ISR 不可能卡滞。

    由于定时器继续运行、中断处理程序被重复执行。 如果您不希望它再次运行、请停止计时器。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    //
    // MSP430G2553
    // --------
    // | |
    // | |
    // | P1.3/TA1|->PWM
    //
    
    #include 
    #define PWM_FREQUENCY100
    #define PWM_Duty_cycle50
    
    int main (void)
    {
    WDTCTL = WDTPW + WDTHOLD; //停止 WDT
    P1DIR |= BIT3;//来自 TimerA
    
    TA1CCR0的 PWM 输出= PWM_FREQUENCY;//频率
    TA1CCR1 = PWM_Duty_cycle; //占空比
    TA1CCTL0 |= CCIE;// TBCCR0中断使能
    TA1CCTL1 |= CCIE;//启用 TBCCR1中断
    
    _bis_SR_register (GIE);//启用中断
    __no_operation(); //对于调试器
    TA1CTL = ID_0 + tassel_2 + MC_1 + TACLR;//向上计数模式、div 8
    
    while (1){
    //
    *一些代码
    */
    _ no_operation ();
    }
    
    }
    
    
    // PWM 输出
    //此 ISR 通过设置 TA1 CCR0来确定 PWM 信号的频率
    // Timer1_A0 =计时器 A1 CCR0
    #pragma vector=Timer1_A0_vector
    __interrupt void Timer1_A0_ISR (void)
    {
    P1OUT |= BIT3;//开始 PWM
    }
    
    
    
    // Timer_A3中断矢量(TBIV)处理程序
    // PWM 输出
    //此 ISR 通过设置 TA1 CCR1来确定 PWM 信号的脉冲宽度
    // Timer1_A1 =计时器 A1 CCR1-?
    #pragma vector=Timer1_A1_vector
    __interrupt void Timer1_A1_ISR (void)
    {
    //对 TBIV 寄存
    器的任何访问、读取或写入都会自动复位最高的"挂起"中断标志。 */
    switch (__even_in_range (TA1IV、14)))
    {
    情况0:中断; //无中断
    案例 TA1IV_TACCR1:
    P1OUT &=~BIT3; //结束 PWM
    中断; // CCR1脉冲宽度
    案例 TA1IV_TACCR2:
    中断; //未使用 CCR2
    默认值:中断;
    }
    }
    
    

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

    好的、我删除了 TA1IV_TACCRx 的重新定义(编译器对此发出警告)。

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

    我理解您对用户指南的引用、即 CCIFG 会自动复位。 我观察到它在 CCS 调试会话中、它在进入 ISR 时被复位。 但是、在退出 ISR 之前、它会再次被置位。 该图像显示、即使计数器 TA1R < TA1CCR0、比较寄存器、CCIFG 也会被置位。 为什么要设置它?

    谢谢、

    Scott