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

430g2553 IIC

你好:

    我的问题如下:

        用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,上面的数据不对吧?请帮忙分析,谢谢!

Xutong Han2:

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

Triton Zhang:

回复 Xutong Han2:

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

1231:

回复 Xutong Han2:

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

1231:

回复 Triton Zhang:

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

Triton Zhang:

回复 1231:

你用那个眼睛看到的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

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

 

1231:

回复 Triton Zhang:

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

Hardy Hu:

你好:

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

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

Regards,

Hardy

Triton Zhang:

回复 1231:

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

这里就以你的代码为例子,把我浏览你代码的大致想法简单分析一下,你可以看到一个逻辑混乱的代码给看的人带来多大的困难。真的不如自己去推翻重新写一遍。 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的例程按照你的思路去揉在一起,这样的代码风险非常大。既没有防冲突能力又没有异常处理机制,很多地方都存在死循环的可能性。

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

1231:

回复 Triton Zhang:

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

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->txuchar 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 2int RXByteCtr, RPT_Flag = 0;                // enables repeated start when 1volatile unsigned char RxBuffer[128];       // Allocate 128 byte of RAMunsigned char *PTxData;                     // Pointer to TX dataunsigned char *PRxData;                     // Pointer to RX dataunsigned 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}

1231:

回复 Triton Zhang:

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

赞(0)
未经允许不得转载:TI中文支持网 » 430g2553 IIC
分享到: 更多 (0)