打印
[STM8]

Stm8l152c6 IIC从机发数据正常,但不能收数据

[复制链接]
7005|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
jhj0124|  楼主 | 2011-10-19 08:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
最近使用stm8l152c6调试,利用它的IIC功能,把152c6当做从机,另外一块其它芯片当做主机,它们之间进行IIC通讯,其中152c6mast发送数据时,mast采用中断接收iic数据,mast通过串口打印接收数据、示波器观察,152c6从机向主机发送数据是正常的,当主机向152c6发送数据时,152c6却不能接收到数据。


                         正常波形数据
152c6mast发送数据波形:start+地址(0x4A|0x01+数据(0xcc+stop



                                   
152c6接收数据:地址(0X4A|0x00),波形上看地址是正确的,同时在152c6的从机接收中断里面也检测到了地址匹配,通过改变一盏灯的亮灭变化指示。但接下来的波形出现一个很窄的脉冲,正常情况是发送完地址后SDA应该被拉高的,但SDA被拉低了;为什么SDA会出现低电平呢,断开mastSDA连线,直接用示波器观察mast出来的波形,发现是正常的,那么SDA被拉低就是152C6接收到地址后被拉低了?接下来mast发送的数据:0x27,也能通过示波器观察到,数据发送结束后,SDA线再次被拉低。
   猜测数据来自mast,当传完地址后(152c6能够检测到地址匹配),SDA线与功能,被slave强制拉低(断开和152c6SDA连接脚,mast传输完地址后SDA是高电平)?所以出现SDA变低情况?如果按照猜测152C6接收到地址后,把SDA一直拉低,那么后面mast发送过来的0x27数据就不可能出现,线与后应该全为零才对。
Stm8l152c6IIc从机,中断进行收发数据。下面为152c6程序。
   初始化IIC
void Init_I2C (void)
{
/* Set I2C registers for 7Bits Address */


I2C1->CR1 |= 0x01;
// Enable I2C peripheral


I2C1->CR2 |= 0x04;
// Enable I2C acknowledgement


I2C1->FREQR = 16;
// Set I2C Freq value (16MHz)


I2C1->OARL |= (SLAVE_ADDRESS << 1) ;
// set slave address to 0xA5(put 0x4A for the register dues to7bit address)


I2C1->OARH |= 0x40;
// Set 7bit address mode

      

I2C1->ITR
|= 0x07;

// all I2C interrupt enable

}

中断处理
INTERRUPT_HANDLER(I2C1_IRQHandler,29)
{
if (I2C_ReadRegister(I2C1, I2C_Register_SR2))

{


I2C1->SR2 = 0; // Clears SR2 register


}


I2C_Event_TypeDef
Event = I2C_GetLastEvent(I2C1);


switch (Event)


{


//------ Slave transmitter ---------//


// check on EV1 //


case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:


MessageBegin = 1;


break;



// check on EV3 //


case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:


// Transmit data//


I2C1->DR =*(data);//
通过全局变量data发送数据,这个发送通讯正常


break;


//----- Slave receiver --------//


//check on EV1//


case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:


GPIOC->ODR^=1<<7;//
通过一盏led灯检测到,接收数据时地址是正确的



//
示波器观察结果也符合


break;



// Check on EV2//


case I2C_EVENT_SLAVE_BYTE_RECEIVED:




GPIOE->ODR^=1<<7;//
没能看到改LED的变化




i2cRcvBuffer[i2cRcvIndex++]
= I2C1->DR ;


break;



//Check on EV4 //


case (I2C_EVENT_SLAVE_STOP_DETECTED):


// write to CR2 to clear STOPF flag //


I2C1->CR2 |= I2C_CR2_ACK;



Tr_enable=1;


break;


default:


break;


}

}



Stm8l从机接收时序,事件1EV1)为:addr=1,然后SCL拉低,直到完成相应的时序,但我这里根据波形得到的结果是addr=1SDA却被拉低?

不知道问题出在哪了,寻求指点。
图片不能正常显示,上传一个pdf,麻烦有心人帮忙指点一二,不胜感激。

积分可能不够,努力赚积分,一定补上。

stm8l152c6 iic通讯不正常.pdf

248.65 KB

沙发
yinyangdianzi| | 2011-10-19 16:39 | 只看该作者
等答案

使用特权

评论回复
板凳
guanggaoren| | 2011-10-20 07:34 | 只看该作者
MARK.

使用特权

评论回复
地板
jhj0124|  楼主 | 2011-10-20 10:02 | 只看该作者
中断处理里面执行下面这个if判断函数后,能发送数据了。
  void I2C_rx_tx(void)
  {   
static u8 sr1,sr2,sr3;;                                       
// save the I2C registers configuration
sr1 = I2C1->SR1;
sr2 = I2C1->SR2;
sr3 = I2C1->SR3;
//Communication error? //

if (sr2 & (I2C_SR2_WUFH | I2C_SR2_OVR |I2C_SR2_ARLO |I2C_SR2_BERR))
  {               
//   I2C1->CR2|= I2C_CR2_STOP;  // stop communication - release the lines
    I2C1->SR2= 0;                 // clear all error flags
       
  }

// More bytes received ?
if ((sr1 & (I2C_SR1_RXNE | I2C_SR1_BTF)) == (I2C_SR1_RXNE | I2C_SR1_BTF))
  {
//   I2C_byte_received(I2C1->DR);
  }

// Byte received ? //
  if( (sr1 & I2C_SR1_RXNE)&&(sr3 &I2C_SR3_BUSY))
  {
      GPIOE->ODR^=0X80;
      I2C_byte_received(I2C1->DR);   

   }

//NAK? (=end of slave transmit comm)//
if (sr2 & I2C_SR2_AF)
    {       
       I2C1->SR2 &= ~I2C_SR2_AF;          // clear AF
    }

// Stop bit from Master  (= end of slave receive comm) //
if (sr1 & I2C_SR1_STOPF)
  {
    I2C1->CR2 |= I2C_CR2_ACK;          // CR2 write to clear STOPF

  }
// Slave address matched (= Start Comm) //
if( (sr1 & I2C_SR1_ADDR)&&(sr3 &I2C_SR3_BUSY))
    {       
    GPIOC->ODR^=0X80;
    }
// More bytes to transmit ? //
if ((sr1 & (I2C_SR1_TXE | I2C_SR1_BTF)) == (I2C_SR1_TXE | I2C_SR1_BTF))
  {      
  }
// Byte to transmit ? //
if (sr1 & I2C_SR1_TXE)
  {
   I2C1->DR =*(data);
  }       
  
}

使用特权

评论回复
5
jhj0124|  楼主 | 2011-10-20 10:05 | 只看该作者
上面提到的两个中断函数,判断条件一样,只是一个用case语句,一个用if条件判断来实现,但用case语句的中断接收数据时,出现i2c被锁死情况。应该是判断标志位的时候出的问题。


接收中断发生
//check on EV1//
    case    I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
       GPIOC->ODR^=1<<7;
      break;

// Slave address matched (= Start Comm) //
if( (sr1 & I2C_SR1_ADDR)&&(sr3 &I2C_SR3_BUSY))
    {       
    GPIOC->ODR^=0X80;
}
单字节接收时,采用case语句的中断,能检测到EV1事件的发生,但不能接收数据(说明没有检测到rxne=1)EV2 :case I2C_EVENT_SLAVE_BYTE_RECEIVED: 没被执行,SDA为低电平,通过观察sr1寄存器窗口,发现只有stopf被置1,rxne=1根本没有被检测到,原因不明,中断没法单步调试。。。但此时I2C总线没有锁死,继续发送第二个字节,由于stopf还没被清除,i2c总线继续被占用,所以第二字节没触发地址匹配中断,此时怪事出现了,调试窗口观察到了RXNE被置1,但I2C总线挂了。直到重新复位stm8l152c6。
   观察case的判断条件,
EV1:  I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED = (uint16_t)0x0202,  /*!< BUSY and ADDR flags */
EV2: I2C_EVENT_SLAVE_BYTE_RECEIVED = (uint16_t)0x0240,  /*!< BUSY and RXNE flags */
EV4:I2C_EVENT_SLAVE_STOP_DETECTED = (uint16_t)0x0010,  /*!< STOPF flag */

再看下函数:I2C_GetLastEvent(),看下这个函数到底做了些什么事情:
I2C_Event_TypeDef I2C_GetLastEvent(I2C_TypeDef* I2Cx)
{
  __IO uint16_t lastevent = 0;
  uint16_t flag1 = 0;
  uint16_t flag2 = 0;

  if ((I2Cx->SR2 & I2C_SR2_AF) != 0x00)
  {
    lastevent = I2C_EVENT_SLAVE_ACK_FAILURE;
  }
  else
  {
    /* Read the I2C status register */
    flag1 = I2Cx->SR1;
    flag2 = I2Cx->SR3;

    /* Get the last event value from I2C status register */
    lastevent = ((uint16_t)((uint16_t)flag2 << 8) | (uint16_t)flag1);
  }
  /* Return status */
  return (I2C_Event_TypeDef)lastevent;
}

可以发现该函数返回值为一个16bit 数据,高八位为sr3的状态值,低八位为sr1的状态值,并把返回值和I2C_Event_TypeDef匹配,这就很好的说明了为什么发送第二个字节导致iic总线挂起:查找不到和I2C_Event_TypeDef匹配的数据,从而导致I2C挂起;而采用if循环,判断状态位,条件不满足,继续顺序向下执行,不会导致I2C锁死。

以上仅限个人理解,或有差错,望高手指点。

感慨下:只能说ST IIC的状态位太搞了,实在搞不清楚它的标志位的作用时间,并且还有那么多的标志位,如果程序判断出点差错,就会被搞死,还不知道怎么死的。

使用特权

评论回复
6
yangganglone| | 2013-12-3 18:45 | 只看该作者
你好,我现在也是在做2个单片机进行iic通讯,但是我从机接收中断里面好像不能接收数据,不知道为什么,还望您给指点一下

使用特权

评论回复
7
sy971586331| | 2014-1-27 11:07 | 只看该作者
yangganglone 发表于 2013-12-3 18:45
你好,我现在也是在做2个单片机进行iic通讯,但是我从机接收中断里面好像不能接收数据,不知道为什么,还望 ...

你的从机接收数据搞定了吗,我也是从机不能接收数据,主机发完地址后从机无应答,你是怎么解决的呢

使用特权

评论回复
8
yangganglone| | 2014-2-3 20:06 | 只看该作者
sy971586331 发表于 2014-1-27 11:07
你的从机接收数据搞定了吗,我也是从机不能接收数据,主机发完地址后从机无应答,你是怎么解决的呢 ...

我现在已经解决了,我是这么做的,在接收中断里面处理的!

使用特权

评论回复
9
sy971586331| | 2014-2-7 16:50 | 只看该作者
yangganglone 发表于 2014-2-3 20:06
我现在已经解决了,我是这么做的,在接收中断里面处理的!

我的接收也是用的中断,但你具体是怎么处理的呢,能加QQ请教你吗

使用特权

评论回复
10
yangganglone| | 2014-3-31 09:08 | 只看该作者
sy971586331 发表于 2014-2-7 16:50
我的接收也是用的中断,但你具体是怎么处理的呢,能加QQ请教你吗
/***********************************************************
//iic中断函数
**********************************************************/
[url=home.php?mod=space&uid=1095855]@far[/url] [url=home.php?mod=space&uid=422518]@interrupt[/url] void iic_irq(void)
{
       
               
                if(I2C_SR2==0xFF)
                        {
                                        //testiic=1;
                                        I2C_SR2=0x00;
                                        send_string("发送错误",8);
                        }
                               
                        if((I2C_SR1&(1<<1))==(1<<1))         // 地址匹配
                        {
                                        DataAmount=0;             //   数据数量清零
                                        temp1=I2C_SR1;                                //假读 清除标志位
                                        temp2=I2C_SR3;                                         //地址匹配清除标志位       
                        }       
                //        send_string("电压是:",7);
                        if((I2C_SR1&(1<<6))==(1<<6))         //接收到数据
                        {       
                                        v1=I2C_DR;   //保存所接收的数据
                                        //v2=I2C_DR;                       
                                        I2C_CR2|=(1<<2);
                                        I2C_CR2|=(1<<3);                                                                               
                                        send_char(v1%10+48);       
                                        //send_char(0x0a);

                        }
                        if(I2C_SR1&(1<<4)==(1<<4))                                //停止位侦测
                        {                                               
                                        temp1=I2C_SR1;
                                        I2C_CR2|=(1<<1);
                        }
                                                                                  
}

使用特权

评论回复
11
yangganglone| | 2014-3-31 17:21 | 只看该作者
请问。从机中断里面可以发数据给主机么?

使用特权

评论回复
12
sy971586331| | 2014-4-18 18:49 | 只看该作者
yangganglone 发表于 2014-3-31 17:21
请问。从机中断里面可以发数据给主机么?

IIC从机是被动的,从机要发数据给主机要主机主动读

使用特权

评论回复
13
看我吴钩| | 2015-1-22 10:17 | 只看该作者
请教LZ,最后怎么解决的呢?我用一款单片机的硬件IIC口和NXP的时钟芯片PCF8563(带IIC接口)同样出现一样的问题,单片机主收发器发送STOP信号后,SDA却一直保持为低,使得接下来的读写出现错误。STOP信号明明发出了,为什么SDA还是低电平,从器件PCF8563钳住拉低SDA的话,怎么解决?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

16

帖子

0

粉丝