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.

[参考译文] MSP430FR2311:可编程改变功率模式

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/820313/msp430fr2311-programatically-changing-power-modes

器件型号:MSP430FR2311

我有两个项目正确地使用了 MSP430低功耗模式。  我了解需要将器件置于睡眠状态、但不了解在中断后需要清除该位。  

到目前为止、我注意到了一些问题。  由于低频振荡器太慢、因此如果我想在115200处接收 UART 消息、我只能使用 LPM0。  我还必须特意退出/清除 I2C 中断例程中的 LPM0位、以便在 main 中处理它们。

因此、我不确定我的所有代码是否正确。  我希望有人可以进行审核并提出任何建议。

项目1.

//唤醒以处理在进入时通过 UART 接收的数据。
// I2C 从设备命令进入并做出适当响应时唤醒。
//还注意到我必须清除 lpm 位才能从 I2C 事务

int main (void)
{中唤醒
//停止 WDT
WDT_A_HOLD (WDT_A_base);

initClockTo16MHz ();
inituart(0);
initGPIO();
initi2C();

while (1)
{

if (rxFlag = 1)
{
processorUART ();
}

__bis_SR_register (LPM0_Bits + GIE);
}



// UART 中断
#if defined (__TI_Compiler_version__)|| defined (__IAR_systems_icc_)
#pragma = USCI_A0 (


void _if)(_COMPIAR _VERSION_IFIE_IFIE_IFIE_IFIE_IFIE_IFIE_IFIE_IFIE_COMPI_ IE_COMPI_

)#_COMPIACT_VERSION_ERSION_IFIE_IFIE_ERSION_A0 (#US_AULT_ERSION_ERSION_ERSION_IF
#endif
{
switch (__evo_in_range (UCA0IV、USCI_UART_UCTXCPTIFG))
{
USCI_NONE 案例:中断;
USCI_UART_UCRXIFG 案例:

UCA0IFG &=~ UCRXIFG; //清除中断
rxData = UCA0RXBUF;
rxFlag = 1;
_BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//在 TI 上退出 LPM0
中断;
案例 USCI_UART_UCTXIFG:中断;
案例 USCI_UART_UCSTTIFG:中断;
案例 USCI_UART_UCTXCPTIFG:break;
}
}


//*********
// I2C 中断
//

#if defined (__TI_Compiler_version__)|| defined (__IAR_systems_icc_)
#pragma vector = USCI_B0_vector
__interrupt void USCI_B0_ISR (void)
#Elif defined (__GNU__)
void __attribute__(interrupt (USCI_B0_vector)#USCI_ISR vector (void

)(void)#USCI_ISR vector 0!
#endif
{
//必须从 UCB0RXBUF
uint8_t Rx_val 读取;
switch (_even_in_range (UCB0IV、USCI_I2C_UCBIT9IFG)
){
USCI_NONE 案例: 中断; //向量0:无中断
USCI_I2C_UCALIFG 案例:中断; //向量2:ALIFG
USCI_I2C_UCNACKIFG 案例: //向量4:NACKIFG
中断;
案例 USCI_I2C_UCSTTIFG:中断; //向量6:STTIFG
USCI_I2C_UCSTPIFG 案例:
UCB0IFG &=~(UCTXIFG0);
中断; //向量8:STPIFG
USCI_I2C_UCRXIFG3案例:中断; //向量10:RXIFG3
USCI_I2C_UCTXIFG3案例:中断; //向量12:TXIFG3
USCI_I2C_UCRXIFG2案例:中断; //向量14:RXIFG2
USCI_I2C_UCTXIFG2案例:中断; //向量16:TXIFG2
USCI_I2C_UCRXIFG1案例:中断; //向量18:RXIFG1
USCI_I2C_UCTXIFG1案例:中断; //向量20:TXIFG1
USCI_I2C_UCRXIFG0案例: //向量22:RXIFG0
RX_val = UCB0RXBUF;
切换(SlaveMode)
{
情况(RX_REG_ADDRESS_MODE):
ReceiveRegAddr = Rx_val;
I2C_Slave_ProcessCMD (ReceiveRegAddr);
中断;
情况(RX_DATA_MODE):
ReceiveBuffer[ReceiveIndex++]= Rx_val;
RXByteCtr---;

IF (RXByteCtr = 0)
{
//完成接收 MSG
SlaveMode = RX_REG_ADDRESS_MODE;
UCB0IE &=~(UCTXIE);
UCB0IE |= UCRXIE; //启用 RX 中断
I2C_Slave_TransactionDone (ReceiveRegAddr);


__BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//在 RETI 上退出 LPM0
}
中断;
默认值:
__no_operation();
中断;
}
中断;
USCI_I2C_UCTXIFG0案例: //向量24:TXIFG0
UCB0TXBUF =传输缓冲器[TransmitIndex++];
TXByteCtr --;
IF (TXByteCtr = 0)
{
//完成发送 MSG
SlaveMode = TX_REG_ADDRESS_MODE;
UCB0IE &=~(UCTXIE);
UCB0IE |= UCRXIE; //启用 RX 中断
I2C_Slave_TransactionDone (ReceiveRegAddr);
}
中断; //中断矢量:I2C 模式:UCTXIFG
默认值:中断;
}
}

项目2.

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

initClockTo16MHz();
inituart();

/*初始化外设*/
initGPIO();
initPWM();
initi2C();
initrtc();

while (1)
{
currentSample();
LED_CURRENT_READING = ADC_Conversion_Result;

tempSample ();
CURRENT_TEMP_READING = ADC_Conversion_Result;

doOtherStudioff ();


//LPM3、RTC 或 I2C 将强制退出
_bis_SR_register (LPM3_bits + GIE);
}





void currentSample (void)
{
ENABLE_ADC10 (ADCINCH_0);
_DELAY_CYCLES (15);

//启用并开始转换
//在单通道、单次转换模式中
ADC_startConversion (ADC_base、ADC_SINGLECHANNEL);

//LPM3、ADC 转换完成将强制退出
_bis_SR_register (LPM0_bits + GIE);

disable_ADC10 ();
}

void tempSample (void)
{
ENABLE_ADC10 (ADCINCH_12);

_DELAY_CYCLES (15);

//启用并开始转换
//在单通道、单次转换模式中
ADC_startConversion (ADC_base、ADC_SINGLECHANNEL);

//LPM3、ADC 转换完成将强制退出
_bis_SR_register (LPM0_bits + GIE);

disable_ADC10 ();
}


void disable_ADC10 (void){
adc_disableConversions (adc_base、0);
adc_disable (adc_base);
}

void enable_adc10 (uint8_t adc_channel){
//初始化 ADC 模块

adc_init (adc_base、adc_SAMPLEHOLDCOSC_base);}void adc_oc_oc_oc_enable、adc_oc_oc_occe_enc (uint1、adce_oc_oc_oc_oc_base);



ADC_setupSamplingTimer (ADC_base、ADC_CYCLEHOLD_1024_cycles、ADC_MULTIPLESAMPLESDISABLE);

IF (ADC_CHANNEL = ADCINCH_12)
{
ADC_configureMemory (ADC_base、ADC_channel、ADC_VREFPS_INT、ADC_VREFNEG_AVSS);
}
否则
{
ADC_configureMemory (ADC_base、ADC_channel、ADC_VREFPOS_AVCC、ADC_VREFNEG_AVSS);// driverlib 中 A1的通道错误映射?
}

ADC_clearInterrupt (ADC_base、ADC_completed_interrupt);

//启用存储器缓冲器中断
ADC_enableInterrupt (ADC_base、ADC_completed_interrupt);
}



// ADC 中断服务例程
#if defined (__TI_Compiler_version__)|| defined (__IAR_systems_icc_)
#pragma vector=ADC_complete_interrupt




(_ void)(_adc)(nvoid _interrupt)(_inc)(nvoid _inc)(void _interrupt (n_inc)(void _interrupt)(_inc)(_ vector (_inc)_ vo
#endif
{
ADC_Conversion_Result = ADCMEM0;

__BIC_SR_register_ON_EXIT (LPM3_BITS); //睡眠定时器退出 LPM3
}


// RTC 中断服务例程
#if defined (__TI_Compiler_version__)|| Defined (__IAR_systems_ICC__)
#pragma vector=RTC_vector
__interrupt void RTC_ISR (void)
#Elif defined (__GCOMPILE__)
void __attribute__(interrupt (interrupt (rtc_vector)#rTC

!#pru_ISR (void)#rc!#rc!错误!
#endif
{
_BIC_SR_REGISTER_ON_EXIT (LPM3_BITS); //计时器退出 LPM3

开关(__evo_in_range (RTCIV、RTCIV_RTCIF)

{

案例 RTCIV_NONE:中断; //无中断

案例 RTCIV_RTCIF: // RTC 溢出
P2OUT ^= BIT3;
中断;

默认值:中断

;}

//


*********
// I2C 中断
//

#if defined (__TI_Compiler_version__)|| defined (__IAR_systems_icc_)
#pragma vector = USCI_B0_vector
__interrupt void USCI_B0_ISR (void)
#Elif defined (__GNU__)
void __attribute__(interrupt (USCI_B0_vector)#USCI_ISR vector (void

)(void)#USCI_ISR vector 0!
#endif
{
//必须从 UCB0RXBUF
uint8_t Rx_val 读取;
switch (_even_in_range (UCB0IV、USCI_I2C_UCBIT9IFG)
){
USCI_NONE 案例: 中断; //向量0:无中断
USCI_I2C_UCALIFG 案例:中断; //向量2:ALIFG
USCI_I2C_UCNACKIFG 案例: //向量4:NACKIFG
中断;
案例 USCI_I2C_UCSTTIFG:中断; //向量6:STTIFG
USCI_I2C_UCSTPIFG 案例:
UCB0IFG &=~(UCTXIFG0);
中断; //向量8:STPIFG
USCI_I2C_UCRXIFG3案例:中断; //向量10:RXIFG3
USCI_I2C_UCTXIFG3案例:中断; //向量12:TXIFG3
USCI_I2C_UCRXIFG2案例:中断; //向量14:RXIFG2
USCI_I2C_UCTXIFG2案例:中断; //向量16:TXIFG2
USCI_I2C_UCRXIFG1案例:中断; //向量18:RXIFG1
USCI_I2C_UCTXIFG1案例:中断; //向量20:TXIFG1
USCI_I2C_UCRXIFG0案例: //向量22:RXIFG0
RX_val = UCB0RXBUF;
切换(SlaveMode)
{
情况(RX_REG_ADDRESS_MODE):
ReceiveRegAddr = Rx_val;
I2C_Slave_ProcessCMD (ReceiveRegAddr); /
中断;
情况(RX_DATA_MODE):
ReceiveBuffer[ReceiveIndex++]= Rx_val;
RXByteCtr---;

IF (RXByteCtr = 0)
{
//完成接收 MSG
SlaveMode = RX_REG_ADDRESS_MODE;
UCB0IE &=~(UCTXIE);
UCB0IE |= UCRXIE; //启用 RX 中断
I2C_Slave_TransactionDone (ReceiveRegAddr);

//我们应该在这里这么做吗?
__BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//在 RETI 上退出 LPM0
}
中断;
默认值:
__no_operation();
中断;
}
中断;
USCI_I2C_UCTXIFG0案例: //向量24:TXIFG0
UCB0TXBUF =传输缓冲器[TransmitIndex++];
TXByteCtr --;
IF (TXByteCtr = 0)
{
//完成发送 MSG
SlaveMode = TX_REG_ADDRESS_MODE;
UCB0IE &=~(UCTXIE);
UCB0IE |= UCRXIE; //启用 RX 中断
I2C_Slave_TransactionDone (ReceiveRegAddr);
}
中断; //中断矢量:I2C 模式:UCTXIFG
默认值:中断;
}
}

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

    您似乎有基本的想法。 在某些 CPU 中,任何中断都会唤醒 main(),在 MSP430中,ISR 会决定是否发生这种情况。

    您现在要进入下一个步骤--系统设计。

    1) 1)一旦有多个唤醒源(在 ADC+RTC+I2C 情况下)、就需要小心处理错误的唤醒。 如果 RTC 或 I2C 在等待 ADC 时发出唤醒信号、则此代码将假定 ADC 已完成。 一个简单的第一近似值可能是:

    ADC_DONE = 0;
    ADC_startConversion();
    while (!ADC_DONE) LPM0;// ADC_DONE 在 ISR 中设置为1 

    2)使用 LPM 会有竞争:如果事件(从 ISR 唤醒)发生在 main ()不在 LPM 中时、则不会保留任何记录。 例如、如果事件发生在进入 LPM 之前的最后一条语句中、则不会有唤醒。 这会导致[未经测试、但我认为是对的]:

    while (1){ //反转循环
    __disable_interrupt ();//检查标志
    是否(RTC_DONE || I2C_DONE)中断;//必须发生在更早
    的__bis_SR_register (LPM0_bits | GIE);//重新启用和睡眠
    }//结束 while (1)
    __ENABLE_INTERRUPT (); //恢复正常
    
    

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

    Bruce、

    感谢您提供信息。  我理解你在1中的意思、但我看不到你在2中的意思。  您能进一步说明吗?

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

    假设在 DoOtherStudio()执行时发生 I2C 中断/唤醒、会发生什么情况。 然后、该代码将进入 LPM、但唤醒将会很长时间、因此它将在 LPM 中停止。

    在此代码中、我们期望 RTC 中断最终会发出另一个唤醒信号、但在处理 I2C 主机请求的任何内容时都会有延迟。 在没有定期唤醒(即 RTC)的情况下、它将永久停止。

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

    只要我开始在 main()中执行,是否最好立即重新启用中断?

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

    目标应该是尽可能使中断被启用(GIE)。 通常,这是在所有"init()调用之后(while 循环之前)的"_enable_interrupt();"形式。 在这个代码中,GIE 将在第一次调用 currentSample()后被置位(永远),尽管这对读取器来说有点不明显。

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

    好的、我想我看到您正在获得什么。  如果我的中断需要在 main()中的 ISR 外部完成一些额外的工作并且我已经唤醒、那么在下一个中断出现之前、我可能不会运行 ISR 的 main()代码、这可能是一个问题。

    因此、关于 GIE 被永久启用、我没有意识到这一点、但我想这是可以的。  那么、我对    ISR 内部的__BIC_SR_REGISTER_ON_EXIT (LPM3_BITS);或__BIC_SR_REGISTER_ON_EXIT (LPM0_BITS)执行了什么操作?  我只是告诉它跳到 main()是可以的。  否则、如果我不这么做、CPU 会返回到 LPM?

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

    "_ON_EXIT"公式在状态寄存器中设置 CPUOFF=0、如 main 所见(假设它已设置 CPUOFF=1)、因此 main 再次启动。 如果您不执行此操作、main 仍将看到 CPUOFF=1、并且不执行任何操作。

    [我必须回到我的日常工作中,所以:]这可能是重新阅读用户指南(SLAU445I)第1.3.4.1-2节和第1.4节的前几段的好时机--现在你已经知道了一般的想法,知道这些机制将会更有用。

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

    您好、Bruce、

    再次感谢您的所有帮助。  我最终这样做了、我解决了项目1的问题。  这对您是否正确?  基本上、当 有一个 UART 字节要被接收时、我将 RxFlag 设置为1、当有一个 i2c 消息改变了一个寄存器时、I2Cflag 设置为1。

    while (1){
    
    if (i2cFlag!= 0)
    {
    i2cFlag = 0;
    }
    
    if (cntl = 0x00)// i2c 更改了功率控制寄存器
    {
    PowerControl(0);
    }
    否则、如果(cntl = 0x01)// i2c 更改了功率控制寄存器
    {
    PowerControl(1);
    }
    
    if (rxFlag!= 0)
    {
    rxFlag = 0;
    processUART();
    }
    
    //如果没有标志,则睡眠
    _disable_interrupt ();
    if (rxFlag =0 && i2cFlag =0)
    {
    _bis_SR_register (LPM0_Bits + GIE);
    }
    其他
    {
    __ENABLE_INTERRUPT();
    }
    } 

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

    对我来说没关系。  

    确保将所有"Flag"变量声明为"volatile"、以便在打开优化器时它们不会消失。

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

    大家好、Bruce、感谢您支持这个主题!

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

    如果问题已得到解决、我将关闭此主题。 谢谢