打印
[STM8]

求助:STM8S I2C 接收不到停止位信号 困扰我半个月了;

[复制链接]
13429|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
计划模式|  楼主 | 2012-11-13 10:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
STM8S I2C  在从接收模式能正常接收到停止位信号,但在从发送模式始终接收不到停止位信号,

I2C主接收程序是这样写的:
在 I2C_SR1_BTF为1中断发生后执行下面程序;
I2C->CR2 &= ~I2C_CR2_ACK;   
*(pu8_DataBuffer_cpy++) = I2C->DR;
I2C->CR2 |= I2C_CR2_STOP;
*(pu8_DataBuffer_cpy++) = I2C->DR;
I2C->ITR |= I2C_ITR_ITBUFEN;
接下去I2C主机再接收一个字节后应该返回一个非应答;并且发送一个停止位;

但I2C从机发送完最后一个字节后,却接收不到停止位;并且还继续产生发送缓冲器空中断
各位大哥,帮忙指点下;万谢!
沙发
计划模式|  楼主 | 2012-11-13 21:24 | 只看该作者
米人回答:

使用特权

评论回复
板凳
IJK| | 2012-11-14 10:36 | 只看该作者
LZ用示波器看过吗?

使用特权

评论回复
地板
234918154| | 2012-11-15 16:22 | 只看该作者
使用库就很好解决,,
给你参考下,我使用通过的代码
###################################
/**
  * @brief I2C Interrupt routine.
  * @param  None
  * @retval None
  */
INTERRUPT_HANDLER(I2C_IRQHandler, 19)
{
    /* Read SR2 register to get I2C error */   //状态寄存器2(I2C_SR2)用来标记通信是否发生错误
    if ((I2C->SR2) != 0)
    {
        /* Clears SR2 register */
        I2C->SR2 = 0;

        /*
            添加发生I2C通信错误时候的警示代码
         */
    }
   
    switch (I2C_GetLastEvent())
    {

        /******* Slave transmitter ******/
        /* check on EV1 */
        case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:
            Tx_Idx = 0;
            break;

        /* check on EV3 */
        case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:
            /* Transmit data */
            I2C_SendData(Rec_Data[Tx_Idx++]);       //检测到一次EV3事件,就发送一次数据
            break;
            
        /******* Slave receiver **********/
        /* check on EV1*/
        case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
            break;

        /* Check on EV2*/
        case I2C_EVENT_SLAVE_BYTE_RECEIVED:
            Slave_Buffer_Rx[Rx_Idx++] = I2C_ReceiveData();    //检测到一次EV2事件,就接收一次数据
            break;

        /* Check on EV4 */
        case (I2C_EVENT_SLAVE_STOP_DETECTED):
            /* write to CR2 to clear STOPF flag */
            I2C->CR2 |= I2C_CR2_ACK;
            for (i=0; i<50; i++)
            {
                DATA_BUFF[i] = Slave_Buffer_Rx[i];
            }
            FINISH_RECEIVE_FLAG = 1;    //等到数据接收完后,才进行相应的操作(写内部EEPROM 等)
            Rx_Idx = 0;                 //从头重新开始存储,毕竟BUFFER的大小有限
            break;

        default:
            break;
    }
}
####################################

使用特权

评论回复
5
oyljxilige| | 2012-11-17 17:20 | 只看该作者
楼主可以去看下我这个帖子,https://bbs.21ic.com/frame.php?fr ... .com/iclist-49.html不知道是不是和我遇到一样的问题了,我从数据手册上读到从发射模式是检测不到停止位的,只能检测到一个AF(NACK)中断标志位,我觉得你要是以I2C_SR1_BTF作为中断接收数据的标志位的话是肯定会多发射一个数据的,因为BIF中断完了之后还会TXE中断标志位还会置一,还会在进一次中断发一次数据,而且你上面写的*(pu8_DataBuffer_cpy++) = I2C->DR;是处于接收模式而不是发射模式吧

使用特权

评论回复
6
明月小厨| | 2012-12-2 13:15 | 只看该作者
本帖最后由 明月小厨 于 2012-12-2 15:56 编辑

应答
(主控发)
最后一个8位字节数据
(从机发)
非应答
(主控发)
停止
(主控发)
这个格式才是正确的时序;

上面是I2C总线上信号出现的顺序;
非应答由主控接收方发送;(注:从发送方检测到此非应答信号后就应该停止)
楼主的问题估计就出在这里,从方一直想等到STOP信号再停止,而且始终收不到;
其实,主控方发送STOP信号,但从方真的是收不到,从方此时还忙着埋头发数据呢.(总线已经冲突了)
主控方埋头发出一个STOP后就自动进入从模式,处于待命状态了;
主控一直是正常的可控状态;但从方因为没有注意检测总线上出现的非应答信号并做出调整(停止发送并结束本次通讯),所以一直在瞎忙;

使用特权

评论回复
7
明月小厨| | 2012-12-2 16:03 | 只看该作者
楼主 对主控方的控制完全正确;
但对从方的理解出现偏差,误以为收到STOP信号才停止;
主控方发送SOTP信号其实就是自言自语,意思是告诉自己的内部硬件系统,本次通讯已经结束了;
而做为从方,根本不用理会这个STOP信号,只关注STOP前面的非应答即可;
如果从方的设置正确,收到非应答后立即释放总线,
总线在主控方发STOP的时候已经是空闲状态,不然双方抢着发数据,听谁的?

使用特权

评论回复
8
明月小厨| | 2012-12-2 16:14 | 只看该作者
总结:I2C总线比较烦,完全不同于51的串口;要对下一个动作做出反应,需要预判,预设;
一环扣一环,流水线式的工作模式;而异步通讯的串口,则一个数据,一个数据处理;而这里是一串一串处理;而且还要有应答握手信号;
SPI串口就不搞这些东西,可以闭着眼埋头收发数据,不需要CPU介入处理通讯的细节;

使用特权

评论回复
9
njchenmin| | 2012-12-2 17:36 | 只看该作者
最好参考一下例程,这样就比较有底。

使用特权

评论回复
10
beanandpeach| | 2012-12-2 20:25 | 只看该作者
库函数用起来方便安全点

使用特权

评论回复
11
figo20042005| | 2012-12-2 21:29 | 只看该作者
还是用库函数做一下,再看看波形有没停止信号

使用特权

评论回复
12
wuwei86| | 2014-1-19 15:42 | 只看该作者
明月小厨,问下你,再检测到AF信号后应该怎么办,我是直接复位整个I2C,用来复位总线!

使用特权

评论回复
13
xibaocell| | 2015-1-21 14:11 | 只看该作者
说说我在双机通信时需要注意的问题:
1、主机stm8在主接收状态时,接收完最后第二个数据后要进行ACK信号的关闭(也就是I2C_CR2中ACK位的使能位置0),在接收到最后一个字节后就不会返回ACK信号了
2、从机stm8在发送状态时,发送完最后一个数据后收到NACK信号(因为主机设置了ACK不应答)。要非常注意的事情就在这儿:stm8产品手册上说,从机接收到NACK信号(判断I2C_SR2中的AF位),其TxE和BTF标志位是不会置1的,也就是说不会再次进入中断的(如果采用的是中断方式),然后通过置IIC_CR2中的停止位进行总线的释放。但我发现其实从机在收到NACK信号后,还会产生TxE的置位,并且重新进入中断,引起逻辑混乱。
3、后来我发现,其实在设置停止位后,延迟一定的时间(几十个机器周期),其状态寄存器I2C_SR1的状态也就正常了。可能是stm8需要一定的时间进行总线的复位。
希望这个发现对大家有所帮助。

使用特权

评论回复
14
steven0419| | 2018-4-15 17:08 | 只看该作者
明月小厨 发表于 2012-12-2 16:03
楼主 对主控方的控制完全正确;
但对从方的理解出现偏差,误以为收到STOP信号才停止;
主控方发送SOTP信号其实 ...

那请问下,STM32中是怎么检测到NACK信号的?是发生了哪一个中断事件。谢谢

使用特权

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

本版积分规则

0

主题

2

帖子

0

粉丝