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.

430g2553 IIC

Other Parts Discussed in Thread: MSP430G2553

你好:

    我的问题如下:

        用2553通过I2C写一个数字功放,

#ifndef SIMPLE_I2C_H
#define SIMPLE_I2C_H
#endif
#define uchar unsigned char

uchar TRFlag;
uchar DataFlag=0;
uchar TxData[2];
uchar *PTxData;
//uchar Rxdata;
uchar Txctr;
uchar I2C_buf1;

void init_i2c(void);
void I2Cm_Tx(uchar valueReg,uchar RegAddress,uchar DeviceAddress);
void I2Cm_Rx(uchar valueReg,uchar RegAddress,uchar DeviceAddress);

#pragma vector=USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void){
  if(TRFlag==1){
    if(Txctr){
      Txctr--;
      UCB0TXBUF=*PTxData++;       //no data transmit
      __bic_SR_register_on_exit(CPUOFF);   // get out of interrupt
    }
    else{
      UCB0CTL1|=UCTXSTP;
      IFG2&=~UCB0TXIFG;
      __bic_SR_register_on_exit(CPUOFF);
    }
  }
  else{
    I2C_buf1=UCB0RXBUF;
    UCB0CTL1|=UCTXSTP;
    IFG2&=~UCB0RXIFG;
    __bic_SR_register_on_exit(CPUOFF);
  }
}

void I2Cm_Tx(uchar valueReg,uchar RegAddress,uchar DeviceAddress){
  _DINT();
  TRFlag=1;
  if(DataFlag==1){
    Txctr=1;
    DataFlag=0;
  }
  else{
    Txctr=2;
  }
  IE2&=~UCB0RXIE;
  while(UCB0CTL1&UCTXSTP);
  UCB0CTL1|=UCSWRST;
  UCB0CTL0=UCMST+UCMODE_3+UCSYNC;
  UCB0CTL1=UCSSEL_2+UCSWRST;
  UCB0BR0=12;
  UCB0BR1=0;
  UCB0I2CSA=DeviceAddress;
  UCB0CTL1&=~UCSWRST;
  IE2|=UCB0TXIE;
  TxData[0]=RegAddress;
  TxData[1]=valueReg;
  PTxData=TxData;
  while(UCB0CTL1&UCTXSTP);
  UCB0CTL1|=UCTR+UCTXSTT;
  __bis_SR_register(CPUOFF+GIE);      //enter interrupt
  while(UCB0CTL1&UCTXSTP);            //return to this
}

void I2Cm_Rx(uchar valueReg,uchar RegAddress,uchar DeviceAddress){
  _DINT();
  uchar temp_dev,temp_reg;
  temp_dev=DeviceAddress;
  temp_reg=RegAddress;
  TRFlag=0;
  DataFlag=1;
  I2Cm_Tx(0x00,temp_reg,temp_dev);
  IE2&=~UCB0TXIE;
  while(UCB0CTL1&UCTXSTP);
  UCB0CTL1|=UCSWRST;
  UCB0CTL0=UCMST+UCMODE_3+UCSYNC;
  UCB0CTL1=UCSSEL_2+UCSWRST;
  UCB0BR0=12;
  UCB0BR1=0;
  UCB0I2CSA=temp_dev;
  UCB0CTL1&=~UCSWRST;
  IE2|=UCB0RXIE;
  while(UCB0CTL1&UCTXSTP);
  UCB0CTL1|=UCTXSTT;
  __bis_SR_register(CPUOFF+GIE);
  while(UCB0CTL1&UCTXSTP);
}

void init_i2c(void){
  P1SEL|=BIT6+BIT7;
  P1SEL2|=BIT6+BIT7;
}

 调用I2Cm_TX()后,只执行完if(Txctr){}一遍后跳出中断,捕捉到下面的波形:

I2C_SA是0X38,上面的数据不对吧?请帮忙分析,谢谢!

  • 先用TI官方的程序调试一下,排除硬件问题,再去调试修改软件~

  • 波形是错的,波形发出来的数据时0XE1.

  • 那我改的这个对不对?这个对你们来说不是很简单的吗?

  • 这能称为数据吗?I2C数据十几毫秒,别乱忽悠

  • 你用那个眼睛看到的I2C数据不能是几十毫秒? I2C的速率是从直流到100K(高速400K).

    从波形图上看数据就是0XE1,如果不会看的话,回去翻书去,别再这里随意下结论。如果你有自己的分析,欢迎贴上来。

    至于说到这个波形的问题,那是很多的,但不是说就没数据。

    1. 按照I2C的标准,SCL和SDA在不使用的时候都应该是高电平,这个图中的SCL是低电平。

    2. START的位置不是很明显,但可能是示波器没展开造成的。

    3. 第5个CLK宽度太大,什么原因造成的不清楚,但还是一个合格I2C CLK波形

    4. 第6,7,8个CLK被遮住了,但还是能看出是CLK,

    5. 8个数据位之后没有STOP

    这是波形分析,至于程序有什么问题,没时间去细究。

     

  • 我是不懂,所以才问,你们回复个看官方例程算什么,我是看了才改的,硬件没问题,之前用别的MCU写I2C也OK,你没时间就别回复啊,那些代码需要你们很多时间细究吗?以前有帖子质疑你们的官方例程咋不回复,没那耐心干嘛开在线支持?说你们忽悠就急了

  • 你好:

    主函数那一段能发给大家看看吗?

    还有就是注意看START和STOP信号,分析程序的执行结果。

    Regards,

    Hardy

  • 首先回你例程的不是我,从你的代码中我看到了无数例程的影子。但是,我也没觉得回你例程有什么不妥。 你有没有认真地去读下例程呢?有没有去挨个看例程中的语句操作寄存器的含义呢? 你在编写代码之前,有没有实际的画一下流程图,然后去检查下里面的逻辑错误呢? 如果你要人家帮忙看代码,至少要把你代码贴完整,代码中的注释写清楚。你的代码中的各个变量的含义是什么?如果可能,最好贴上你的流程分析。否者人家要来猜你的意图,如果程序里面有逻辑错误,看起来就更吃力,你觉得这个不花时间行吗? 即使是一个很小的代码,不同的程序员思路就不一样,写出来的流程和代码都不一样,你不要只站在你的角度看代码,觉得人家花不了时间。

    这里就以你的代码为例子,把我浏览你代码的大致想法简单分析一下,你可以看到一个逻辑混乱的代码给看的人带来多大的困难。真的不如自己去推翻重新写一遍。 1. 代码里没有MAIN函数,程序的入口进行了什么初始化看不到。 2. 主频设置的多大,SMCLK,ACLK是用的什么时钟源都不清楚,这关系到如何判断I2C的波特率。    没有这些信息,不要说你的I2C的波形是20多个毫秒,就算是1S都是可能的.这就是为什么你觉得10几毫秒的I2C数据不能,因为你从例程直接抄过来的,认为就是100K的速率,而看代码的人根本没得到这些信息。 3. I2C的初始化就只初始化了下管脚,你把I2C的初始化放在了I2C的发送和接收的代码中,实在是不知道咋有这样的想法。唯一的解释就是你从TI的发射例程中拷贝了一段,然后又从接收例程中拷贝了一段。 3. 从代码来猜TRFlag标志是用来标志I2C发送还是接受状态的,这个标志在USCIAB0TX_ISR的中断出来函数中用来判断是接收还是发射状态。这个标志在你I2Cm_RX的函数入口被初始化成0,按照流程走到调用I2Cm_TX()中又被置1,调用返回后    这个标志就一直保留成1了.换句话说在I2Cm_RX()函数的头半部分TRFlag =0, 后半部分TRFlag =1. 这么混乱的逻辑,你让谁能一眼看出来你想干什么? 4. 回到开始的话题,按照一般的理解,I2Cm_RX(),I2Cm_TX()这样命名的函数应该是对等的平行关系函数,而在你的代码中I2Cm_RX()又在调用I2Cm_TX,真不晓得你在编程前是否真正的去分析过系统和流程没有.另外推荐程序员在编程之前学习下程序命令规则,这个一定会给你带来好处的. 5. 继续谈问题,在中断函数中,你通过TRFlag标志来判断是接收中断还是发射中断,问题是MSP430G2553的I2C中断向量有2个,一个发射,一个接收,你在发射中断里去判断接收的数据中断,如何能有结果?    这说明你看例程都没仔细看,更不用说看数据手册了。 6. 继续,DataFlag标志,从你I2Cm_Tx的函数中来猜,你是想用这个来区分只传送设备地址和设备地址+寄存器地址。在你的I2Cm_RX()函数中设置了这个标志然后调用I2Cm_TX去发送设备地址+寄存器地址.问题是之后你连发送地址+读操作都没有, 就直接切换到接收模式。你看到那个I2C的协议可以这样做的? 这说明你连I2C的协议都没去认真阅读。 7. 在处理I2C的中断事件中,把第一次进TX中断当做是START信号的中断事件,这样做风险很大而且也很让人不好理解。    你要去实际判断是否有START信号的中断,这个状态在UCBxSTAT的UCSTTIFG来表示。MSP430G系列的I2C寄存器总共就只有12个, 你在编程前花不了一个小时就浏览完了,比你出了问题,盲人摸象地去找问题花的时间少多了. D8. 纵观全部代码,基本上就是把TI的例程按照你的思路去揉在一起,这样的代码风险非常大。既没有防冲突能力又没有异常处理机制,很多地方都存在死循环的可能性。

    我不是说一定要挑剔你代码的毛病,你想一下,如果一眼能看到这么多问题,逻辑思路一点都不清晰的代码,你还有兴趣去挨个检查问题么?这不是说给你找一两个问题就能解决的聊的. 根本问题在于你在设计代码的时候,没有花时间去了解相关知识,没有去分析协议,没有去读数据手册,没有认真分析流程画出流程及逻辑关系。这些都不是能力问题,是你做事的方式的问题。 任何人都是从无知到有知的,如果你总想让人家来帮你找问题,而自己不去反省自己的问题,怎么能成为一个合格的软件工程师呢?

  • 首先感谢你的精彩分析和中肯建议,虽然我不是软件工程师,但这代码确实太烂,并对自己的无理表示道歉。

    1.这个程序用于2553做主控的蓝牙音箱中,用TI的数字功放,main函数功能主要有四个:a.硬件的初始化(不包括功放);b.功放初始化;c.按键操作;d.显示控制。

    用I2C来实现对功放的初始化,我把功能分布调试,所以没有贴main(),初始化数据在另一个文件中,这段代码是从官方的例程12抄过来的,所以没加注释。

    2.功放初始化:a.对功放指定寄存器写数据;b.读出指定寄存器值计算后重新写入该寄存器

                           (读操作先写入被读寄存器地址,再进行当前地址寄存器读取,所以在RX内先调用了TX)(TX\RX每次只完成单个字节数据(不包括地址)的读写)

    3.RX、TX内每次进行调用都初始化I2C,这是对应例程i2c_12中的tx、rx set_up,按照我对UCSWRST的理解,I2C初始化应该和IO一起,初始化一遍即可,把SA放到TX、RX函数中。不是一定要照抄例程,只是觉得刚开始还是尽量接近官方例程。

    4.在DS中,如果没理解错,T\RX flag共用一个向量(Status flag共用一个向量),参照例程,我还是把他们放一起。

    5.注释一下我贴的代码

    #ifndef SIMPLE_I2C_H
    #define SIMPLE_I2C_H
    #endif
    #define uchar unsigned char

    uchar TRFlag;     //判断是发送还是接收中断,1->tx
    uchar DataFlag=0;   //判断是只发送功放寄存器地址还是需发数据,0->需加数据
    uchar TxData[2];       //装寄存器地址或者+数据
    uchar *PTxData;     //指向上面的数组
    //uchar Rxdata;
    uchar Txctr;            //发送计数
    uchar I2C_buf1;      //存储要发送的或者接收的I2C数据

    void init_i2c(void);
    void I2Cm_Tx(uchar valueReg,uchar RegAddress,uchar DeviceAddress);      //变量:数据I2C_buf1、寄存器地址、功放地址
    void I2Cm_Rx(uchar valueReg,uchar RegAddress,uchar DeviceAddress);

    #pragma vector=USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void){
      if(TRFlag==1){                                                  //TRFlag、Txctr在TX建立过程中赋值
        if(Txctr){
          Txctr--;
          UCB0TXBUF=*PTxData++;      
          __bic_SR_register_on_exit(CPUOFF);   // 按照对例程的理解,这句应该不要,STP不发,不断中断才会进行完Txctr-到0,再到下面给STP,按照例程中  

                                                                               recieve()\transmit(), 我在每次调用TX RX中断返回后都while 已STP发送,这样这里需要加这一句跳出低功耗,不加不会循环不

                                                                                 会发STP,加了更不会循环
        }
        else{                                                                 //实际这里没有执行到
          UCB0CTL1|=UCTXSTP;
          IFG2&=~UCB0TXIFG;
          __bic_SR_register_on_exit(CPUOFF);
        }
      }
      else{
        I2C_buf1=UCB0RXBUF;
        UCB0CTL1|=UCTXSTP;
        IFG2&=~UCB0RXIFG;
        __bic_SR_register_on_exit(CPUOFF);
      }
    }

    void I2Cm_Tx(uchar valueReg,uchar RegAddress,uchar DeviceAddress){
      _DINT();
      TRFlag=1;                           //发送标志
      if(DataFlag==1){                //RX函数内部DataFlag置1后紧接着调用TX,如通过RX间接调用TX,DataFlag马上清0,避免影响TX后续的直接调用
        Txctr=1;
        DataFlag=0;
      }
      else{
        Txctr=2;
      }
      IE2&=~UCB0RXIE;                                        //初始化
      while(UCB0CTL1&UCTXSTP);
      UCB0CTL1|=UCSWRST;
      UCB0CTL0=UCMST+UCMODE_3+UCSYNC;
      UCB0CTL1=UCSSEL_2+UCSWRST;                               //选择SMCLK12分频为时钟,例程中未初始化主时钟,默认S/MCLK为800K,实际不超过SCL不超过67K

                                                                                                               ,我写的main中也为800K
      UCB0BR0=12;
      UCB0BR1=0;
      UCB0I2CSA=DeviceAddress;
      UCB0CTL1&=~UCSWRST;
      IE2|=UCB0TXIE;
      TxData[0]=RegAddress;
      TxData[1]=valueReg;                            //通过RX间接调用TX时,此值为I2C_buf1,但不发送
      PTxData=TxData;                                  //指针赋值
      while(UCB0CTL1&UCTXSTP);
      UCB0CTL1|=UCTR+UCTXSTT;
      __bis_SR_register(CPUOFF+GIE);      //enter interrupt
      while(UCB0CTL1&UCTXSTP);            //return to this
    }

    void I2Cm_Rx(uchar valueReg,uchar RegAddress,uchar DeviceAddress){
      _DINT();
      uchar temp_dev,temp_reg;                        //RX TX参数传递
      temp_dev=DeviceAddress;
      temp_reg=RegAddress;
      TRFlag=0;                                            //接收标志,这个应该放在调用TX后
      DataFlag=1;
      I2Cm_Tx(0x00,temp_reg,temp_dev);
      IE2&=~UCB0TXIE;                                           //初始化
      while(UCB0CTL1&UCTXSTP);
      UCB0CTL1|=UCSWRST;
      UCB0CTL0=UCMST+UCMODE_3+UCSYNC;
      UCB0CTL1=UCSSEL_2+UCSWRST;
      UCB0BR0=12;
      UCB0BR1=0;
      UCB0I2CSA=temp_dev;
      UCB0CTL1&=~UCSWRST;
      IE2|=UCB0RXIE;
      while(UCB0CTL1&UCTXSTP);
      UCB0CTL1|=UCTXSTT;
      __bis_SR_register(CPUOFF+GIE);
      while(UCB0CTL1&UCTXSTP);
    }

    void init_i2c(void){
      P1SEL|=BIT6+BIT7;
      P1SEL2|=BIT6+BIT7;
    }

    6.参考的官方例程

    //******************************************************************************
    //  MSP430G2xx3 Demo - USCI_B0 I2C Master TX/RX multiple bytes from MSP430 Slave
    //                     with a repeated start in between TX and RX operations.
    //
    //  Description: This demo connects two MSP430's via the I2C bus. The master
    //  transmits to the slave, then a repeated start is generated followed by a
    //  receive operation. This is the master code. This code demonstrates how to
    //  implement an I2C repeated start with the USCI module using the USCI_B0 TX
    //  interrupt.
    //  ACLK = n/a, MCLK = SMCLK = BRCLK = default DCO = ~1.2MHz
    //
    //    ***to be used with msp430x22x4_uscib0_i2c_13.c***
    //
    //                                /|\  /|\
    //               MSP430F24x      10k  10k     MSP430G2xx3
    //                   slave         |    |        master
    //             -----------------   |    |  -----------------
    //           -|XIN  P3.1/UCB0SDA|<-|---+->|P3.1/UCB0SDA  XIN|-
    //            |                 |  |      |                 |
    //           -|XOUT             |  |      |             XOUT|-
    //            |     P3.2/UCB0SCL|<-+----->|P3.2/UCB0SCL     |
    //            |                 |         |                 |
    //
    //  D. Dang
    //  Texas Instruments Inc.
    //  February 2011
    //  Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
    //******************************************************************************
    #include "msp430g2553.h"

    #define NUM_BYTES_TX 3                         // How many bytes?
    #define NUM_BYTES_RX 2

    int RXByteCtr, RPT_Flag = 0;                // enables repeated start when 1
    volatile unsigned char RxBuffer[128];       // Allocate 128 byte of RAM
    unsigned char *PTxData;                     // Pointer to TX data
    unsigned char *PRxData;                     // Pointer to RX data
    unsigned char TXByteCtr, RX = 0;
    unsigned char MSData = 0x55;

    void Setup_TX(void);
    void Setup_RX(void);
    void Transmit(void);
    void Receive(void);

    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
      P1SEL |= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
      P1SEL2|= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
     
      while(1){
       
      //Transmit process
      Setup_TX();
      RPT_Flag = 1;
      Transmit();
      while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
     
      //Receive process
      Setup_RX();
      Receive();
      while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
      }
    }

    //-------------------------------------------------------------------------------
    // The USCI_B0 data ISR is used to move received data from the I2C slave
    // to the MSP430 memory. It 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)
    {
      if(RX == 1){                              // Master Recieve?
      RXByteCtr--;                              // Decrement RX byte counter
      if (RXByteCtr)
      {
        *PRxData++ = UCB0RXBUF;                 // Move RX data to address PRxData
      }
      else
      {
        if(RPT_Flag == 0)
            UCB0CTL1 |= UCTXSTP;                // No Repeated Start: stop condition
          if(RPT_Flag == 1){                    // if Repeated Start: do nothing
            RPT_Flag = 0;
          }
        *PRxData = UCB0RXBUF;                   // Move final RX data to PRxData
        __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
      }}
     
      else{                                     // Master Transmit
          if (TXByteCtr)                        // Check TX byte counter
      {
        UCB0TXBUF = MSData++;                   // Load TX buffer
        TXByteCtr--;                            // Decrement TX byte counter
      }
      else
      {
        if(RPT_Flag == 1){
        RPT_Flag = 0;
        PTxData = &MSData;                      // TX array start address
        TXByteCtr = NUM_BYTES_TX;                  // Load TX byte counter
        __bic_SR_register_on_exit(CPUOFF);
        }
        else{
        UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
        IFG2 &= ~UCB0TXIFG;                     // Clear USCI_B0 TX int flag
        __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
        }
      }
     }
     
    }

    void Setup_TX(void){
      _DINT();
      RX = 0;
      IE2 &= ~UCB0RXIE; 
      while (UCB0CTL1 & UCTXSTP);               // Ensure stop condition got sent// Disable RX interrupt
      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 = 0x48;                         // Slave Address is 048h
      UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
      IE2 |= UCB0TXIE;                          // Enable TX interrupt
    }
    void Setup_RX(void){
      _DINT();
      RX = 1;
      IE2 &= ~UCB0TXIE; 
      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 = 0x48;                         // Slave Address is 048h
      UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
      IE2 |= UCB0RXIE;                          // Enable RX interrupt
    }
    void Transmit(void){
        PTxData = &MSData;                      // TX array start address
        TXByteCtr = NUM_BYTES_TX;                  // Load TX byte counter
        while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
        UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
        __bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts
    }
    void Receive(void){
        PRxData = (unsigned char *)RxBuffer;    // Start of RX buffer
        RXByteCtr = NUM_BYTES_RX-1;              // Load RX byte counter
        while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
        UCB0CTL1 |= UCTXSTT;                    // I2C start condition
        __bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts
    }


  • 感谢你的精彩分析和中肯建议,虽然不是软件工程师,但这代码确实很烂,并对自己的无理表示道歉。

    回复.doc
  •  qi yun yuan ,

                         你好,请问你的msp430g2553的硬件I2C调试好了吗?可以用了吗?我使用的430WARE里的历程,但是不好用,能不能教我一下?

  • 请问IIC可不可以实现在一个时序里面,发送和接收的切换?

    我用的是mup6050,需要先发送寄存器地址,然后接收传感器发回来的信号。但是看数据手册没有提到发送和接收的切换,都是采用RESTART的方式,但是采用RESTART的方式的话,传感器就不能发回数据了,求指教。

  • 按照I2C协议规定是不行的,I2C只能工作在发送或接收状态,切换I2C的状态只能依靠START+DEVICEADD+W/R命令

    我线看下MUP6050的手册,我不太肯定是否有这样的I2C设备会这样设计。

  • 我想可能是你理解错误,我刚查看了MUP6050的数据手册,你要从MUP6050的寄存器读数据也是要按照标准规I2C规定操作的,

    红线部分是MUP6050的读操作时序。

  • 你看,首先需要发送一个AD+R,这个是Transmitter模式吧?然后需要收到一个DATA数据,这个是Receiver模式是吧?这中间不是需要转换的吗?

  • 你发送了AD+R其中的R就是告诉从机切换到发送模式,主机主动切换到接收模式。

    你需要看下I2C的协议。