TI中文支持网
TI专业的中文技术问题搜集分享网站

MSp430G2553在I2C通信中CPU的工作模式选择

/  Description: I2C interface to TMP100 temperature sensor in 9-bit mode.
//  Timer_A CCR0 interrupt is used to wake up and read the two bytes of
//  the TMP100 temperature register every 62ms. If the temperature is greater
//  than 28C, P1.0 is set, else reset. CPU is operated in LPM0. I2C speed
//  is ~100kHz.
//  ACLK = n/a, MCLK = SMCLK = TACLK = BRCLK = default DCO = ~1.2MHz
//
//         /|\           /|\ /|\
//          |   TMP100   10k 10k     MSP430G2xx3
//          |   ——-   |   |   ——————-
//          +–|Vcc SDA|<-|—+->|P1.7/UCB0SDA    XIN|-
//          |  |       |  |      |                   |
//          +–|A1,A0  |  |      |               XOUT|-
//             |       |  |      |                   |
//          +–|Vss SCL|<-+——|P1.6/UCB0SCL   P1.0|—> LED
//         \|/  ——-          |                   |
//
//  D. Dang
//  Texas Instruments Inc.
//  February 2011
//   Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
//******************************************************************************
#include "msp430g2553.h"
unsigned int RxByteCtr;
unsigned int RxWord;
void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
  P1DIR |= BIT0;                            // P1.0 output
  P1SEL |= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
  P1SEL2|= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
  UCB0CTL1 |= UCSWRST;                      // Enable SW reset
  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode
  UCB0CTL1 = UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset
  UCB0BR0 = 12;                             // fSCL = SMCLK/12 = ~100kHz
  UCB0BR1 = 0;
  UCB0I2CSA = 0x4e;                         // Set slave address
  UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
  IE2 |= UCB0RXIE;                          // Enable RX interrupt
  TACTL = TASSEL_2 + MC_2;                  // SMCLK, contmode
  while (1)
  {
    RxByteCtr = 2;                          // Load RX byte counter
    UCB0CTL1 |= UCTXSTT;                    // I2C start condition
    __bis_SR_register(CPUOFF + GIE);        // Enter LPM0, enable interrupts
                                            // Remain in LPM0 until all data
                                            // is RX'd
    if (RxWord < 0x1d00)                    // >28C?
      P1OUT &= ~0x01;                       // No, P1.0 = 0
    else
      P1OUT |= 0x01;                        // Yes, P1.0 = 1
    __disable_interrupt();
    TACCTL0 |= CCIE;                        // TACCR0 interrupt enabled
    __bis_SR_register(CPUOFF + GIE);        // Enter LPM0, enable interrupts
                                            // Remain in LPM0 until TACCR0
                                            // interrupt occurs
    TACCTL0 &= ~CCIE;                       // TACCR0 interrupt disabled
  }
}
#pragma vector = TIMER0_A0_VECTOR
__interrupt void TA0_ISR(void)
{
  __bic_SR_register_on_exit(CPUOFF);        // Exit LPM0
}
// The USCIAB0TX_ISR is structured such that it can be used to receive any
// 2+ number of bytes by pre-loading RxByteCtr with the byte count.
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
  RxByteCtr–;                              // Decrement RX byte counter
  if (RxByteCtr)
  {
    RxWord = (unsigned int)UCB0RXBUF << 8;  // Get received byte
    if (RxByteCtr == 1)                     // Only one byte left?
      UCB0CTL1 |= UCTXSTP;                  // Generate I2C stop condition
  }
  else
  {
    RxWord |= UCB0RXBUF;                    // Get final received byte,
                                            // Combine MSB and LSB
    __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
  }
}
结合上面的例程,我的问题是:为什么一旦进入数据的接收或者发送状态,CPU就进入休眠状态呢,而在不执行I2C通信的任务时,CPU就被唤醒了?
希望能获得解答,谢谢!
wan zeng:

回复 Jarvan Song:

谢谢您的回答!

对于延迟中断,在进入该中断前,_bis_SR_register(CPUOFF)使得430处于低功耗模式,进入延迟中断后,_bis_SR_register_on_exit(CPUOFF);使得CPU被唤醒;对于I2C数据收发中断,在进入该中断之前,同样_bis_SR_register(CPUOFF)使得430处于低功耗模式,进入中断后,在接收数据的过程中,仍然为低功耗模式,

只有当数据全部接收完之后,才唤醒CPU并返回主循环程序对该数据进行比较处理。这样理解对吧?

但我的疑问也出现了,延迟中断唤醒了CPU,但之后CPU并没有事情可做,为什么要在此做延迟中断呢?不做延迟中断,不是更省功耗吗?

 

Jarvan Song:

回复 wan zeng:

你还是没理解,首先你得看看题目程序说明,此程序是每隔62ms对温度计进行一次数据读取然后判断温度是否满足条件,然后进行相应操作,延时中断唤醒CPU后往下执行进入到下一个循环,重新执行该程序,因为在第一次循环中收发中断服务子程序中, UCB0CTL1 |= UCTXSTP语句已经结束了此次I2C数据传输,并且只有UCB0CTL1 |= UCTXSTT这条语句才可以产生I2C通信开始条件,如果这时延时中断之后不唤醒,那么I2C通讯条件永远停留在_bis_SR_register(CPUOFF)产生I2C通讯开始条件,除非延时中断后唤醒cpu进入到下一个循环,才可以重新执行这条语句UCB0CTL1 |= UCTXSTT产生I2C通讯的必要条件。

Jarvan Song:

回复 wan zeng:

        还有就是只要进入中断服务子程序msp430就会自己,自主唤醒进入到AM状态,执行完_bis_SR_register(CPUOFF)之前的语句后又会重新返回到低功耗模式,这个过程是不需要自己设置的,当执行_bis_SR_register(CPUOFF)此时这个是人为的唤醒了。

wan zeng:

回复 Jarvan Song:

我刚刚看到资料上有这么一句“在使用低功耗模式下的USCI模块提供了自动时钟激活。如果因为设备处于低功耗状态而导致USCI模块的时钟源关断时,如果需要,无论时钟源控制位设置如何,USCI模块都可自动激活”

“在I2C从模式下由于时钟是由外部设备提供的,所以内部时钟源并不是必须的。在设备处于LPM4状态下的 并且所有内部时钟源被禁止时,USCI可以工作在I2C从模式下。接收或者发送中断都可以将CPU从任何一种低功耗状态下唤醒。”

您说的很对!

在主循环中,UCB0CTL1|=UCTASTT;产生起始条件,当主机接收到第一个数据并发送应答信号之后,UCRXIFG=1;  并在使能接收中断和总中断的条件下,CPU自主从CPUOFF状态中唤醒,进入中断服务程序,当数据接收完毕,退出中断,又将恢复至低功耗状态,但我们需要进行数据比较,不能让CPU低功耗,于是在接收中断程序末尾添上 _bis_SR_register(CPUOFF)让CPU继续处于唤醒状态。数据处理完之后,TACCTL0|=CCIE;_bis_SR_register(CPUOFF+GIE);CPU又将进入低功耗模式,但是我们需要进入下一个循环,需要通过UCB0CTL1|=UCTXSTT产生下一轮的起始条件,所以需要延迟中断重新唤醒CPU。呃。。这样理解还有错吗?

wan zeng:

回复 wan zeng:

当主程序执行到_bis_SR_register(CPUOFF);时,第一次进入低功耗模式,程序就停在这儿了,就不再往下执行了。当进入接收中断时,CPU自主唤醒,执行中断服务程序,并在退出中断返回主函数前退出低功耗模式,使得主程序的语句得以执行,然后路遇第二次低功耗,程序又停在那儿了,不再往下执行,幸亏有了延迟中断,将CPU唤醒,程序最后得以执行到TACCTL0&=~CCIE;关闭延迟中断,最后程序进入下一次循环。谢谢TI员工您的耐心回答,超级感谢!

wan zeng:

回复 Jarvan Song:

超级感谢TI员工Jarvan song的耐心回答!

赞(0)
未经允许不得转载:TI中文支持网 » MSp430G2553在I2C通信中CPU的工作模式选择
分享到: 更多 (0)