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.

[参考译文] MSP430FR6989:计时器延迟功能、用于进入 LMP3并等待一小时、然后退出

Guru**** 2782445 points

Other Parts Discussed in Thread: MSP430FR6989

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1030939/msp430fr6989-timer-delay-function-to-enter-lmp3-for-one-hour-then-exit

器件型号:MSP430FR6989

我正在尝试设置延迟功能、该功能将进入 LMP3 1小时、然后使用 TimerA1中断退出 LMP3。 在此期间不应执行其他操作、省电实用程序只会延迟1小时。 我已修改 msp430fr69xx_TA1_06.c 示例代码。 以下是我的当前代码:

#include <msp430.h>

void delay_hour(float hour)
{
        TA1CCR0 = (int)(16524 * hour); //Set count target, up to 65535, or 3.96 hours
        TA1CTL |= MC__UP; //Set count mode to up (Changed from TA1CTL = MC__UP;)
        __bis_SR_register(LPM3_bits | GIE); //Enter LPM3
        //while((TA1CTL & TAIFG) == 0) { __no_operation(); } //Wait until count target is reached and interrupt flag turns on
}

int main(void)
{
  WDTCTL = WDTPW | WDTHOLD;                 // Stop WDT

  // Configure GPIO
  P1DIR |= BIT0;                            // LED interrupt
  P1OUT |= BIT0;
  PJSEL0 |= BIT4 | BIT5;

  // Disable the GPIO power-on default high-impedance mode to activate
  // previously configured port settings
  PM5CTL0 &= ~LOCKLPM5;

  // Clock setup
  CSCTL0_H = CSKEY >> 8;                    // Unlock CS registers
  CSCTL1 = DCOFSEL_0;                       // Set DCO to 1MHz
  CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK; // Set ACLK = VLO; MCLK = DCO
  CSCTL3 = DIVA__32 | DIVS__1 | DIVM__1;     // Set S and M dividers to 1, ACLK to 239.75Hz
  CSCTL0_H = 0;                             // Lock CS registers

  TA1CCTL0 = CCIE;                          // TACCR0 interrupt enabled
  TA1CCR0 = 0;                              // Set count target to 0 by default
  // Set timer clock speed to 4.5898 ticks/s, or 16524 ticks/hour
  TA1CTL = TASSEL__ACLK | MC__UP | ID__8; //Set clock source to ACLK, the count mode to stop, and the clock divider to 8
  TA1EX0 = TAIDEX_7; //Set expansion clock divider to 8
  __bis_SR_register(LPM3_bits | GIE);       // Enter LPM3 w/ interrupt

  while(1)
  {
      delay_hour(0.000278); //Delay for one second (0.000278hr or 4.59 ticks) for fast toggling of LED (testing purposes)
      P1OUT ^= BIT0; //Toggle LED
  }
}

// Timer A1 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = TIMER1_A0_VECTOR
__interrupt void Timer1_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(TIMER1_A0_VECTOR))) Timer1_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
    TA1CTL |= MC__STOP; //  Stop timer to prevent repeat counting (Changed from TA1CTL = MC__STOP;)
    __bic_SR_register_on_exit(LPM3_bits);
}

我将在 MSP430FR6989 Launchpad 上运行此功能。   P1.0 LED 亮起、但不会熄灭。 我知道使用 VLOCLK 的 ACLK 设置工作正常。  我通过制作此脚本对其进行了测试、该脚本以大约每秒一次的速率打开和关闭 LED、如下所示:

#include <msp430.h>

int main(void)
{
  WDTCTL = WDTPW | WDTHOLD;                 // Stop WDT

  // Configure GPIO
  P1DIR |= BIT0;                            // LED interrupt
  P1OUT |= BIT0;
  PJSEL0 |= BIT4 | BIT5;

  // Disable the GPIO power-on default high-impedance mode to activate
  // previously configured port settings
  PM5CTL0 &= ~LOCKLPM5;

  // Clock system setup
  CSCTL0_H = CSKEY >> 8;                    // Unlock CS registers
  CSCTL1 = DCOFSEL_0;                       // Set DCO to 1MHz
  CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK; // Set ACLK = VLO; MCLK = DCO
  CSCTL3 = DIVA__32 | DIVS__1 | DIVM__1;     // Set all dividers to 1
  CSCTL0_H = 0;                             // Lock CS registers

  TA1CCTL0 = CCIE;                          // TACCR0 interrupt enabled
  TA1CCR0 = 2;                              // 2 ticks or 0.44s
  TA1CTL = TASSEL__ACLK | MC__UP | ID__8; //Set clock source to ACLK, the count mode to stop, and the clock divider to 8
  TA1EX0 = TAIDEX_7; //Set expansion clock divider to 8

  __bis_SR_register(LPM3_bits | GIE);       // Enter LPM3 w/ interrupt
}

// Timer A1 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = TIMER1_A0_VECTOR
__interrupt void Timer1_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(TIMER1_A0_VECTOR))) Timer1_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
  P1OUT ^= BIT0;
}

由于时钟设置和计时器设置正确、我假设我的错误位于延迟函数或中断中。 延迟函数设置计数并在进入 LPM3之前开始计时器计数。 一旦计数达到、中断应该将计数器设置为停止模式以避免计数重复。 然后、它应该退出 LPM3。  

我在主函数中使用 while 循环。 延迟函数应进入 LPM3、以1为单位达到定时器目标计数、然后退出 LPM3。 我假设由于 LPM3中的 CPU 关闭、主函数在退出 LPM3之前无法继续进行 LED 切换。 因此、一旦定时器中断退出 LPM3、LED 将切换、while 环路将返回到延迟功能。 这种假设是错误的吗? 如果是、则在退出 LPM3后、主函数从何处恢复? 如果每次离开 LPM3时它在主函数开始时重新启动、我可以理解它永远不会达到 LED 切换。 在这种情况下、如何修改延迟函数以获得所需的结果?

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

    拼写错误警报:

    > TA1CTL = MC__UP;//将计数模式设置为向上

    这会设置 TASSEL=0 (以及 ID=0)、以便有效地将其停止。 尝试:

     > TA1CTL |= MC__UP;//将计数模式设置为向上

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

    感谢您的发现。 我在我的代码中更改了它。 我还尝试将中断中的 TA1CTL = MC_STOP 更改为|=。 遗憾的是、LED 仍然无法切换。  

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

    我删除了此行(恰好在 while (1)之前):

    >_bis_SR_register (LPM3_bits | GIE);//通过中断输入 LPM3

    我得到1秒的切换(0.5Hz)。 自 TA1CCR0=0以来、这将永远不会结束。

    未经请求:  

    > TA1CTL |= MC_STOP;//停止计时器以防止重复计数

    这不会停止计时器、因为 MC__STOP=0。 尝试:

    > TA1CTL &=~MC_3;//停止计时器以防止重复计数

    [考古学家注意:原始帖子中的代码已更改。]

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

    这解决了所有问题! 非常感谢您的耐心和帮助。 我现在看到、while 环路之前的 LPM3入口和计数目标0停止了中断的触发和退出 LPM3、有效地将其锁定到 LPM3中。 MC_3的使用也很清楚。

    将来,我是否不应更改原来的帖子,使回覆中所提供的解决方案对日后的读者清晰可见? 我不知道在这种情况下什么被认为是良好做法。

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

    这是一个判断呼叫--有一个就地编辑的案例。 如果我编辑一个帖子(甚至是为了修复拼写错误)、我只需附加"[编辑:修复的拼写错误]"或某些这样的内容、至少会告诉人们他们不会被迷住。