打印

G2Launchpad 硬件IIC 调试问题啊!两天了,卡在循环里面

[复制链接]
2539|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 hkhkdyx 于 2014-5-5 23:24 编辑

/*
* I2C_Init(I2C_MODE i2c_mode, UCSSELx ucsselx)
* 初始化I2C
*
* 参数:
*         i2c_mode --I2C主从模式设置
*      |__        Slave
*      |__        Master
*      |
*         ucsselx --I2C时钟信号选择
*      |__        UCLKI
*      |__        ACLK
*      |__        SMCLK
* 输出:
*    无
*
*/
void I2C_Init(I2C_MODE i2c_mode, UCSSELx ucsselx)
{
        _disable_interrupts();

        P1SEL |= BIT6 + BIT7;                 // GPIO 配置为USCI_B0功能
        P1SEL2|= BIT6 + BIT7;                 // GPIO 配置为USCI_B0功能
        // Own address is a 7-bit address | Address slave with 7-bit address | Single master environment
        switch(i2c_mode)
        {
                case Slave:
                        UCB0CTL0 = UCMODE_3 + UCSYNC;                         //同步通信I2C从机状态
                        break;
                case Master:
                        UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;         //同步通信I2C主机状态
                        break;
        }
        switch(ucsselx)
        {
                case UCLKI:
                        UCB0CTL1 = UCSSEL_0 + UCSWRST;                         // Use UCLKI,USCI Software Reset
                        break;
                case ACLK:
                        UCB0CTL1 = UCSSEL_1 + UCSWRST;                         // Use ACLK,USCI Software Reset
                        break;
                case SMCLK:
                        UCB0CTL1 = UCSSEL_2 + UCSWRST;                         // Use SMCLK,USCI Software Reset
                        break;
        }
        UCB0BR0 =I2C_BAUDRATE_DIV ;        // 除了分频系数,实际波特率还与时钟有关
        UCB0BR1 = 0;                                 // 这一级别的分频一般不启用
        UCB0I2CSA = SLAVE_ADDR;         // I2C从机地址,可在宏定义中修改
        UCB0CTL1 &= ~UCSWRST;                 // 开启I2C

        _enable_interrupts();
}


void I2C_WriteData(uint8 data)
{
        I2C_Init(Master,SMCLK);
        i2c_delay_ms(1);
        while((UCB0CTL1 & UCTXSTP));         // 确保总线空闲
        UCB0CTL1 |= UCTR + UCTXSTT;     // I2C TX, start condition
        while((IFG2 & UCB0TXIFG)==0);         // UCB0TXIFG is set when UCB0TXBUF is empty.
        UCB0TXBUF = SlaveAddress;                // Load TX buffer
        while((IFG2 & UCB0TXIFG)==0);        // UCB0TXIFG is set when UCB0TXBUF is empty.
        UCB0TXBUF = data;
        while((IFG2 & UCB0TXIFG)==0);         // UCB0TXIFG is set when UCB0TXBUF is empty.
        UCB0CTL1 |= UCTXSTP;                  // I2C stop condition
        i2c_delay_ms(1);
}
以上我只上传了我的 iic初始化和 iic写函数。用CCSV5编译器进行调试的时候,程序总是卡在图中红线位置。不知道为啥啊?真心给跪了。都调试了两天,搞不懂原因,求大神们指点指点小弟!另外还有个问题是,如何收到从机发来的应答信号(ACK)?

相关帖子

沙发
hkhkdyx|  楼主 | 2014-5-6 09:13 | 只看该作者
求大神指导啊!!!!!

使用特权

评论回复
板凳
dirtwillfly| | 2014-5-6 11:00 | 只看该作者
UCB0TXBUF = SlaveAddress;  
UCB0TXBUF赋值后肯定不是空的了,为啥还要来回判断它?
建议在第一次while((IFG2 & UCB0TXIFG)==0)时放个大循环,若不没空等待一下。

使用特权

评论回复
地板
hkhkdyx|  楼主 | 2014-5-7 00:00 | 只看该作者
dirtwillfly 发表于 2014-5-6 11:00
UCB0TXBUF = SlaveAddress;  
UCB0TXBUF赋值后肯定不是空的了,为啥还要来回判断它?
建议在第一次while(( ...

版主,第一次在这里发帖,您耐心回复我,非常非常感谢你!你的回复给了我重新调试的勇气我能不能加下您的扣扣或者电话,当面像您请教啊。我的扣扣是34555162,希望您能指教啊~~期盼您的消息
我调试的模块是光照强度模块BH1750  里面还有几个疑点:1.在写时序中G2553的硬件I2C如何判断是否收到从机来的应答信号ACK; 2.在读时序中,主机读完第一组数据时候如何给从机发送应答信号ACK?(PS:在主机读完第二组数据时候发送非应答信号NCK我知道如何去写UCB0CTL1 |= UCTXNACK)

使用特权

评论回复
5
dirtwillfly| | 2014-5-7 08:24 | 只看该作者
hkhkdyx 发表于 2014-5-7 00:00
版主,第一次在这里发帖,您耐心回复我,非常非常感谢你!你的回复给了我重新调试的勇气我能不能加下您的 ...

我最近在线时间比较少,你可以加群:61549143
问题优先发在论坛,然后把链接发到群里。群是对论坛的补充~~
有时间我会尽量回答大家的问题的

使用特权

评论回复
6
dirtwillfly| | 2014-5-7 08:26 | 只看该作者
hkhkdyx 发表于 2014-5-7 00:00
版主,第一次在这里发帖,您耐心回复我,非常非常感谢你!你的回复给了我重新调试的勇气我能不能加下您的 ...

调试这类问题,最好手边有一台示波器或者逻辑分析仪。
看下时序波形,和手册对比一下。
当然,更要多一些耐心

使用特权

评论回复
7
hkhkdyx|  楼主 | 2014-5-7 09:09 | 只看该作者
dirtwillfly 发表于 2014-5-7 08:26
调试这类问题,最好手边有一台示波器或者逻辑分析仪。
看下时序波形,和手册对比一下。
当然,更要多一些 ...

谢谢版主的耐心回复。我以前加过一次群,说实话群确实很冷清啊,遇到问题发群里就没人回复我。。。呜呜。另外,我现在手头也没有示波器  看来是要回学校实验室调试了。话说最近非常忙,边调试程序,边要写论文, 老师要求我后天就见他,我最近在赶论文,调I2C可能要缓几天了,唉

使用特权

评论回复
8
hkhkdyx|  楼主 | 2014-5-7 09:10 | 只看该作者
dirtwillfly 发表于 2014-5-6 11:00
UCB0TXBUF = SlaveAddress;  
UCB0TXBUF赋值后肯定不是空的了,为啥还要来回判断它?
建议在第一次while(( ...

是为了判断是否把数据发送完毕啊,若发送完毕了我好进行下一步操作

使用特权

评论回复
9
Unshining| | 2014-5-7 11:52 | 只看该作者
考虑这样一个问题:发出SlaveAddress后,主机接收到的是一个NAK,因而UCB0TXIFG不置位,而是与NAK有关的中断项置位。因此那个循环就出不去了。
你可以试试降低通讯频率,并确认Slave已经连接好了,可以正常工作。

使用特权

评论回复
10
yirongfu| | 2014-5-7 13:14 | 只看该作者
同意楼上的思路,应该分析一下I2C的通讯速率是否合适

UCB0BR0 =I2C_BAUDRATE_DIV ;        // 除了分频系数,实际波特率还与时钟有关
楼主可以算算自己的MCU主频,以及给I2C配置的波特率。

时序方面,除了看从器件的手册,建议也多琢磨琢磨430 2系列的用户手册中的时序图。

多试试,多看看,不需要示波器之类的仪器也能调通的。

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
hkhkdyx + 1 很给力!
11
hkhkdyx|  楼主 | 2014-5-7 15:54 | 只看该作者
Unshining 发表于 2014-5-7 11:52
考虑这样一个问题:发出SlaveAddress后,主机接收到的是一个NAK,因而UCB0TXIFG不置位,而是与NAK有关的中 ...

谢谢你,我能不能留下您的联系方式,或者您加我企鹅:34555162。我最近2天在做文档,先加着,文档弄完了我再继续调试~~

使用特权

评论回复
12
hkhkdyx|  楼主 | 2014-5-7 15:54 | 只看该作者
yirongfu 发表于 2014-5-7 13:14
同意楼上的思路,应该分析一下I2C的通讯速率是否合适

UCB0BR0 =I2C_BAUDRATE_DIV ;        // 除了分频系 ...

谢谢你,我能不能留下您的联系方式,或者您加我企鹅:34555162。文档要的比较急我最近2天在做文档,先加着,文档弄完了我再继续调试~~

使用特权

评论回复
13
hkhkdyx|  楼主 | 2014-5-17 12:07 | 只看该作者
//==============================软件硬件I2C模式分割线===============================
#ifdef HARD_IIC                // Begin of Hard I2C


/*
* IIC_Init(IIC_MODE iic_mode, UCSSELx ucsselx)
* 初始化I2C
*
* 参数:
*         iic_mode --IIC主从模式设置
*      |__        Slave
*      |__        Master
*      |
*         ucsselx --IIC时钟信号选择
*      |__        UCLKI
*      |__        ACLK
*      |__        SMCLK
* 输出:
*    无
*
*/
void IIC_Init(IIC_MODE iic_mode, UCSSELx ucsselx)
{
        _disable_interrupts();

        P1SEL |= BIT6 + BIT7;                 // GPIO 配置为USCI_B0功能
        P1SEL2|= BIT6 + BIT7;                 // GPIO 配置为USCI_B0功能
        // Own address is a 7-bit address | Address slave with 7-bit address | Single master environment
        switch(iic_mode)
        {
                case Slave:
                        UCB0CTL0 = UCMODE_3 + UCSYNC;                         //同步通信I2C从机状态
                        break;
                case Master:
                        UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;         //同步通信I2C主机状态
                        break;
        }
        switch(ucsselx)
        {
                case UCLKI:
                        UCB0CTL1 = UCSSEL_0 + UCSWRST;                         // Use UCLKI,USCI Software Reset
                        break;
                case ACLK:
                        UCB0CTL1 = UCSSEL_1 + UCSWRST;                         // Use ACLK,USCI Software Reset
                        break;
                case SMCLK:
                        UCB0CTL1 = UCSSEL_2 + UCSWRST;                         // Use SMCLK,USCI Software Reset
                        break;
        }
        UCB0BR0 =IIC_BAUDRATE_DIV ;        // 除了分频系数,实际波特率还与时钟有关
        UCB0BR1 = 0;                                 // 这一级别的分频一般不启用
        //UCB0I2CSA = SLAVE_ADDR;         // I2C从机地址,可在宏定义中修改
        UCB0CTL1 &= ~UCSWRST;                 // 开启I2C

        _enable_interrupts();
}


/*
* uint8 IIC_Read_Bytes(uint8 Addr, uint8 *Data, uint8 Num)
* 硬件IIC主机读多个字节
*
* 参数:
*           Addr --硬件IIC从机地址
*      |
*            Data --数组首地址
*      |
*            Num  --读出数组的长度
* 输出:
*    无
*
*/
uint8 IIC_Read_Bytes(uint8 Addr, uint8 *Data, uint8 Num)
{
    uint8 TimeOut = 0;
    uint8 i = 0;

    UCB0CTL1 |= UCSWRST;
    UCB0CTL1 &= ~UCSWRST;                 // 开启I2C

    TimeOut = IIC_TIME_OUT;
    while((UCB0STAT & UCBBUSY) && (TimeOut--));                        // 确保总线不忙
    TimeOut = IIC_TIME_OUT;
    while((UCB0CTL1 & UCTXSTP) && (TimeOut--));                 // 确保STOP
    // 设置IIC从设备地址,
    UCB0I2CSA = Addr;
    UCB0CTL1 &= ~UCTR;           // IIC RX Module
    UCB0CTL1 |= UCTXSTT;         // IIC模块为接收模式,启动START信号
    TimeOut = IIC_TIME_OUT;
    while((UCB0CTL1 & UCTXSTT) && (TimeOut--));                         // 判断UCTXSTT是否自动硬件置0
    for(i=0;i<Num;i++)
    {
            while((!(IFG2 & UCB0RXIFG)) && (TimeOut--));        // 判断UCB0RXIFG是否自动硬件置0
            Data[i] = UCB0RXBUF;
    }
    // 发送IIC STOP 信号
    UCB0CTL1 |= UCTXSTP;
    TimeOut = IIC_TIME_OUT;
    while((UCB0CTL1 & UCTXSTP) && (TimeOut--)); // 确保STOP
    return 1;
}


/*
* uint8 IIC_Write_OneByte(uint8 Addr, uint8 Val)
* 硬件IIC主机写一个字节
*
* 参数:
*           Addr --硬件IIC从机地址
*      |
*            Val --待写入的值
* 输出:
*    无
*
*/
uint8 IIC_Write_OneByte(uint8 Addr, uint8 Val)
{
      uint8 TimeOut = 0;

      UCB0CTL1 |= UCSWRST;
      UCB0CTL1 &= ~UCSWRST;                 // 开启I2C

      TimeOut = IIC_TIME_OUT;
      while((UCB0STAT & UCBBUSY) && (TimeOut--));                // 确保总线不忙
      TimeOut = IIC_TIME_OUT;
      while((UCB0CTL1 & UCTXSTP) && (TimeOut--));                 // 确保STOP
      // 设置I2C从设备地址,
      UCB0I2CSA = Addr;
      UCB0CTL1 |= UCTR + UCTXSTT;                                         // IIC模块为发送模式,启动START信号
      TimeOut = IIC_TIME_OUT;
      while((!(IFG2 & UCB0TXIFG)) && (TimeOut--));
      UCB0TXBUF = Val;
      TimeOut = IIC_TIME_OUT;
      while((!(IFG2 & UCB0TXIFG)) && (TimeOut--));
      // 清除IIC发送缓冲空的中断标志,发送IIC STOP信号
      IFG2 &= ~UCB0TXIFG;
      UCB0CTL1 |= UCTXSTP;                                                     // 发送IIC STOP 信号
      TimeOut = IIC_TIME_OUT;
      while((UCB0CTL1 & UCTXSTP) && (TimeOut--));                 // 确保STOP
      return 1;
}


/*
* uint8 IIC_Write_Bytes(uint8 Addr, const uint8 *Data, uint8 Num)
* 硬件IIC主机写多个字节
*
* 参数:
*           Addr --硬件IIC从机地址
*      |
*            Data --数组首地址
*      |
*            Num  --写入数组的长度
* 输出:
*    无
*
*/
uint8 IIC_Write_Bytes(uint8 Addr, const uint8 *Data, uint8 Num)
{
      uint8 TimeOut = 0;
      uint8 i = 0;

      UCB0CTL1 |= UCSWRST;
      UCB0CTL1 &= ~UCSWRST;                 // 开启I2C

      TimeOut = IIC_TIME_OUT;
      while((UCB0STAT & UCBBUSY) && (TimeOut--));                // 确保总线不忙
      TimeOut = IIC_TIME_OUT;
      while((UCB0CTL1 & UCTXSTP) && (TimeOut--));                 // 确保STOP
      // 设置IIC从设备地址
      UCB0I2CSA = Addr;
      UCB0CTL1 |= UCTR + UCTXSTT;                                        // IIC模块为发送模式,启动START信号
      TimeOut = IIC_TIME_OUT;
      while((!(IFG2 & UCB0TXIFG)) && (TimeOut--));
      for(i=0;i<Num;i++)
      {
          UCB0TXBUF = Data[i];
          TimeOut = IIC_TIME_OUT;
          while((!(IFG2 & UCB0TXIFG)) && (TimeOut--));
      }
      // 清除IIC发送缓冲空的中断标志,发送 IIC STOP 信号
      IFG2 &= ~UCB0TXIFG;
      UCB0CTL1 |= UCTXSTP;                                                     // 发送IIC STOP 信号
      TimeOut = IIC_TIME_OUT;
      while((UCB0CTL1 & UCTXSTP) && (TimeOut--));                 // 确保STOP
      return 1;
}


#endif                                // End of Hard IIC

使用特权

评论回复
评分
参与人数 1威望 +6 收起 理由
dirtwillfly + 6 很给力!
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

20

帖子

0

粉丝