OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 2921|回复: 13

I2C鬼怪的问题

[复制链接]

17

主题

56

帖子

0

精华

初级会员

Rank: 2

积分
158
金钱
158
注册时间
2016-7-18
在线时间
22 小时
发表于 2017-2-6 17:13:14 | 显示全部楼层 |阅读模式
60金钱
因为我一开始自己写的strar,wait_ACK,send函数,所以和原子哥的有一点不相同,归结的不相同就是原子哥每个函数末尾都释放总线即,SCL=0,而我不释放,在下一个函数开始在释放,结果大家看一下void IIC_Start(void)//和原子哥的一样,除了末尾没有释放总线
{
        SDA_OUT();
        IIC_SDA=1;//
        IIC_SCL=1;
        delay_us(4);//
        IIC_SDA=0;
        delay_us(4);//
}


void IIC_Stop(void)
{
        delay_us(4);
        IIC_SCL=0;
        delay_us(4);
        SDA_OUT();
        IIC_SDA=0;
        delay_us(4);
        IIC_SCL=1;
        delay_us(4);
        IIC_SDA=1;//结束信号
        delay_us(4);
}


u8 IIC_Wait_Ack(void)
{
        int i=0;
       IIC_SCL=0;//因为我没释放总线,所以我在这里释放
        SDA_IN();
        delay_us(5);
        IIC_SDA=1;          //这里是标记1,大家注意一下
        delay_us(2);
        IIC_SCL=1;
        while(READ_SDA==1)
        {
                i++;
                if(i>=250)
                {
                        IIC_Stop();
                        return 1;
                }
        }
        IIC_SCL=0; //这里是标记2,大家注意一下
        return 0;
}



void IIC_Send_Byte(u8 txd)
{
        u8 i;
        SDA_OUT();
        for(i=0;i<8;i++)
        {
                IIC_SCL=0;//这里释放总线
                delay_us(2);   
                IIC_SDA=(txd&0x80)>>7;
                txd<<=1;
                delay_us(2);
                IIC_SCL=1;
                delay_us(4);
        }         
}



//AT24C02读一个字节
u8 AT24CXX_ReadOneByte(u16 ReadAddr)
{                                  
        u8 temp=0;                                                                                                                                                               
    IIC_Start();  
        if(EE_TYPE>AT24C16)
        {
                IIC_Send_Byte(0XA0);           //
                IIC_Wait_Ack();
                IIC_Send_Byte(ReadAddr>>8);   
        }else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1)); //发送器件地址,写数据           
        IIC_Wait_Ack(); //第一个ACK
        IIC_Send_Byte(ReadAddr%256);  //发送低地址
        IIC_Wait_Ack();         //第2个ACK         //这里是标记3,大家注意一下
        IIC_Start();                     
        IIC_Send_Byte(0XA1);           //接收模式                          
        IIC_Wait_Ack();         
    temp=IIC_Read_Byte(0);                  
    IIC_Stop();//结束            
        return temp;
}



现在我的I2C出了问题,标记2出我在函数末尾,释放了总线,但这和我一开始末尾不释放总线的写法是有背的,我的I2C能起作用有两个方法,第一个方法:标记1处SDA=1,改成SDA=0,那么标记2处不释放总线I2C也有效。第2个方法,标记1处写SDA=0,但必须在标记2处释放总线,否则I2C就会出错。
这2种必须要满足一种,才能使I2C有用,但我看数据手册,看时序图,看了好久也找不到我错误在哪里。手上缺少分析仪


(ST_LINK调试的时候)最后一个读字节函数,当满足方法时,(总共有3个ACK)进入任一ACK后,SDA读会变成低电平,即得到从机相应,但是当不满足我的两个方法时,进入第一个ACK会有从机相应,即SDA=0,但在进入第2个ACK的时候得不到相应了,SDA=1,进入ACK中的stop信号。因为这2个ACK中间只隔了一个发送函数,我觉得是发送函数和ACK时序连接不好,但怎么看都没有问题,望各位指点一下


最佳答案

查看完整内容[请看2#楼]

开始信号末尾,最后必须scl=0,这是一定的,防止sda的跳变出现问题。那根本就不是什么释放总线,你都start了,还释放个毛啊,释放是完成控制后scl=1,sda=1.然后io切换到输入模式;原子这里是为了防止时序出现问题,其实不是原子要这么做,大家都是这么做。在读,写的时候sda io切换状态,很多芯片io切换状态都会有脉冲,你scl=1的时候,那就是开始,停止的标志。iic都是标准的,顶多读写的时候时序有一点点差别。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

4

主题

380

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3088
金钱
3088
注册时间
2015-10-17
在线时间
320 小时
发表于 2017-2-6 17:13:15 | 显示全部楼层
开始信号末尾,最后必须scl=0,这是一定的,防止sda的跳变出现问题。那根本就不是什么释放总线,你都start了,还释放个毛啊,释放是完成控制后scl=1,sda=1.然后io切换到输入模式;原子这里是为了防止时序出现问题,其实不是原子要这么做,大家都是这么做。在读,写的时候sda io切换状态,很多芯片io切换状态都会有脉冲,你scl=1的时候,那就是开始,停止的标志。iic都是标准的,顶多读写的时候时序有一点点差别。
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2017-2-6 18:08:01 | 显示全部楼层
为何要这么改?
回复

使用道具 举报

怀枫1993 该用户已被删除
发表于 2017-2-6 19:12:33 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

17

主题

56

帖子

0

精华

初级会员

Rank: 2

积分
158
金钱
158
注册时间
2016-7-18
在线时间
22 小时
 楼主| 发表于 2017-2-6 20:13:13 | 显示全部楼层

自己最开始肯定要自己写写I2C的协议啊,又不能一辈子照抄别人的,这样改有啥问题么原子哥
回复

使用道具 举报

17

主题

56

帖子

0

精华

初级会员

Rank: 2

积分
158
金钱
158
注册时间
2016-7-18
在线时间
22 小时
 楼主| 发表于 2017-2-6 20:14:18 | 显示全部楼层
怀枫1993 发表于 2017-2-6 19:12
在设置SDA口为输入时,我在逻辑分析仪上看到一个很短的负脉冲,有这种地方的注意一下。

是呀,这不是从机发低电平的脉冲信号么
回复

使用道具 举报

17

主题

56

帖子

0

精华

初级会员

Rank: 2

积分
158
金钱
158
注册时间
2016-7-18
在线时间
22 小时
 楼主| 发表于 2017-2-6 20:14:35 | 显示全部楼层
自己顶,有大神么
回复

使用道具 举报

4

主题

380

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3088
金钱
3088
注册时间
2015-10-17
在线时间
320 小时
发表于 2017-2-7 08:32:52 | 显示全部楼层
scl=0,是占用总线,在只有一个主控器件的时候,防止出现问题,都是最后scl=0,这样子sda就不用管他如何变了。scl=1,sda=1才是释放总线,有多个主控器件的时候用。看你也不可能是多个主控器件,多个主控,还要竞争冒险,你都没有。
回复

使用道具 举报

17

主题

132

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
367
金钱
367
注册时间
2016-9-27
在线时间
53 小时
发表于 2017-2-7 09:12:33 | 显示全部楼层
感觉还是时序问题,还是好好看看时序图,按时序图一句一句编写
回复

使用道具 举报

17

主题

56

帖子

0

精华

初级会员

Rank: 2

积分
158
金钱
158
注册时间
2016-7-18
在线时间
22 小时
 楼主| 发表于 2017-2-7 11:31:07 | 显示全部楼层
hgr211 发表于 2017-2-7 08:44
开始信号末尾,最后必须scl=0,这是一定的,防止sda的跳变出现问题。那根本就不是什么释放总线,你都start ...

恩恩,我看了好久以后写I2C也打算全部末尾加SCL=0,现在就是单纯纠结我的程序干嘛不行,如果是说IO切换的时候会有脉冲的话那我就有点明白了
回复

使用道具 举报

17

主题

56

帖子

0

精华

初级会员

Rank: 2

积分
158
金钱
158
注册时间
2016-7-18
在线时间
22 小时
 楼主| 发表于 2017-2-7 11:31:58 | 显示全部楼层
muk子夜 发表于 2017-2-7 09:12
感觉还是时序问题,还是好好看看时序图,按时序图一句一句编写

我都对了2天了!!!
回复

使用道具 举报

怀枫1993 该用户已被删除
发表于 2017-2-7 21:04:45 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

17

主题

132

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
367
金钱
367
注册时间
2016-9-27
在线时间
53 小时
发表于 2017-2-8 09:07:15 | 显示全部楼层
347185100 发表于 2017-2-7 11:31
我都对了2天了!!!

之前遇到一个iic通讯的传感器,按照以前的程序怎么就是不行,对时序一直觉得没有问题,找了好久。最终还是发现传感器规格书的时序有点不同,所以还是建议你仔细看看时序图
回复

使用道具 举报

23

主题

323

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1010
金钱
1010
注册时间
2016-11-8
在线时间
233 小时
发表于 2017-2-8 13:12:42 | 显示全部楼层
看看这个 ,看看能不能理解

I2C总线.pdf

561.77 KB, 下载次数: 128

亦余心之所善,
虽九死其犹未悔。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-8 06:30

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表