OpenEdv-开源电子网

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

战舰例程STM32f103模拟IIC问题

[复制链接]

16

主题

108

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
343
金钱
343
注册时间
2015-12-3
在线时间
55 小时
发表于 2017-10-10 18:31:36 | 显示全部楼层 |阅读模式
2金钱
1、IIC停止信号产生,感觉与IIC时序不一致
代码如下:
void IIC_Stop(void)
{
        SDA_OUT();//sda线输出
        IIC_SCL=0;
        IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
        delay_us(4);
        IIC_SCL=1;
        IIC_SDA=1;//发送I2C总线结束信号
        delay_us(4);                                                                  
}


2、等待应答信号函数中,将SDA设置为输入,后更改SDA的脚状态,不能够理解。
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{
        u8 ucErrTime=0;
        SDA_IN();      //SDA设置为输入  
        IIC_SDA=1;delay_us(1);           
        IIC_SCL=1;delay_us(1);         
        while(READ_SDA)
        {
                ucErrTime++;
                if(ucErrTime>250)
                {
                        IIC_Stop();
                        return 1;
                }
        }
        IIC_SCL=0;//时钟输出0            
        return 0;  
}

最佳答案

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

原子例程里的模拟IIC的stop信号是有bug的,论坛里某个帖子做了说明了的。 这是我根据论坛那个帖子改了的stop信号。 [mw_shl_code=c,true]//产生IIC停止信号 void IIC_Stop(void) { SDA_OUT();//sda线输出 IIC_SCL=0; IIC_SDA=0;//STOP:when CLK is high DATA change form low to high delay_us(4); IIC_SCL=1; delay_us(4); IIC_SDA=1;//发送I2C总线结束 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

33

主题

984

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8024
金钱
8024
注册时间
2014-8-13
在线时间
1595 小时
发表于 2017-10-10 18:31:37 | 显示全部楼层
本帖最后由 mack13013 于 2017-10-15 00:55 编辑

原子例程里的模拟IIC的stop信号是有bug的,论坛里某个帖子做了说明了的。


这是我根据论坛那个帖子改了的stop信号。
[mw_shl_code=c,true]//产生IIC停止信号
void IIC_Stop(void)
{
        SDA_OUT();//sda线输出
        IIC_SCL=0;
        IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
         delay_us(4);
        IIC_SCL=1;
       delay_us(4);
        IIC_SDA=1;//发送I2C总线结束信号
}[/mw_shl_code]


重新搜索了一下那个帖子,发现以下几个帖子提到了这个问题:
http://openedv.com/forum.php?mod=viewthread&tid=96021&highlight=IIC

http://openedv.com/forum.php?mod=viewthread&tid=87513&highlight=IIC

其中第二个地址讨论比较详细。

具体说来就是原子例程中的stop信号没有严格的执行IIC的stop时序。通常,大部分的IIC协议器件在通讯时使用原子例程是没有问题的,
主要原因是大部分IIC器件速度比较快,有足够速度响应
[mw_shl_code=c,true]
        IIC_SCL=1;
        IIC_SDA=1;//发送I2C总线结束信号
[/mw_shl_code]
这样的操作:在SCL拉高后,1us以内(可能只有几十ns)迅速拉高SDA。

当然,对于“大部分”的IIC协议器件,这样的操作是没有问题的。

我就比较惨了,碰到了一个神经病一样的EEPROM,使用原子例程里的stop信号时序通讯就失败了。

器件型号24C021,ST的产品,测试发现该器件速率神经病一样的低,大部分的24Cxx都是100K  400K 1M的速率的,
这个24C021的SCL的周期超过40us,也就是说,这个24C021的频率低于25K。
在这么低的频率下,STM32F4的SDA紧随着SCL拉高后拉高,在24C021方面,可能还没响应完SCL的拉高信号,SDA就已经拉高了。
我们一般的数字电路里,一般说来,一个信号比另外一个信号慢,是能够体现出来的。但是这个24C021是一个包含时序逻辑的器件,很可能它对stop信号的响应是这样的:在某个寄存器为1(或者0)的情况下检测有没有SDA的上升沿信号。
那么24C021用原子例程IIC通讯失败的大概原因也就出来了:
原子例程里,SCL拉高后,没任何延时就直接拉高了SDA,而24C021方面,在收到SCL拉高后,因为这个24C021速度实在太慢,可能还没来得及将某个寄存器置1(或者0)SDA就已经被拉高了,等某个寄存器置1(或者0)完成后,已经等不到SDA上升沿信号了,所以stop信号就失败了。
所以我在SCL拉高之后加入了一个几us的延时,通讯就正常了。

实在抱歉,其实是我把前后几个测试搞混了,最早发现stop通讯失败的器件是24C16,stop修改之后跟24C16通讯就正常了。然而过了不久分析同样一个型号的配件又发现了24C021的低速率问题,在IIC驱动中加入了非常多的delay_us(5);之后,与24C021的通讯才正常。
想起我搞混测试之后,帖子已经编辑了大部分了,就懒得改了,好在对于理解stop问题还不影响。

回复

使用道具 举报

16

主题

108

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
343
金钱
343
注册时间
2015-12-3
在线时间
55 小时
 楼主| 发表于 2017-10-10 18:31:53 | 显示全部楼层

1、IIC停止信号产生,感觉与IIC时序不一致
代码如下:
void IIC_Stop(void)
{
        SDA_OUT();//sda线输出
        IIC_SCL=0;
        IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
        delay_us(4);
        IIC_SCL=1;
        IIC_SDA=1;//发送I2C总线结束信号
        delay_us(4);                                                                  
}


2、等待应答信号函数中,将SDA设置为输入,后更改SDA的脚状态,不能够理解。
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{
        u8 ucErrTime=0;
        SDA_IN();      //SDA设置为输入  
        IIC_SDA=1;delay_us(1);           
        IIC_SCL=1;delay_us(1);         
        while(READ_SDA)
        {
                ucErrTime++;
                if(ucErrTime>250)
                {
                        IIC_Stop();
                        return 1;
                }
        }
        IIC_SCL=0;//时钟输出0            
        return 0;  
}
回复

使用道具 举报

42

主题

95

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
456
金钱
456
注册时间
2017-9-8
在线时间
58 小时
发表于 2017-10-10 21:58:34 | 显示全部楼层
皇者~景帝 发表于 2017-10-10 18:31
1、IIC停止信号产生,感觉与IIC时序不一致
代码如下:
void IIC_Stop(void)

同问  !!!



还有就是 为什么你截的图看的那么暗啊,别人都不想看了?
回复

使用道具 举报

16

主题

108

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
343
金钱
343
注册时间
2015-12-3
在线时间
55 小时
 楼主| 发表于 2017-10-11 11:50:37 | 显示全部楼层

我在二楼重新贴了代码的
回复

使用道具 举报

42

主题

95

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
456
金钱
456
注册时间
2017-9-8
在线时间
58 小时
发表于 2017-10-11 22:40:36 | 显示全部楼层
皇者~景帝 发表于 2017-10-11 11:50
我在二楼重新贴了代码的

你解决你的问题了吗     可否赐教一下
回复

使用道具 举报

16

主题

108

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
343
金钱
343
注册时间
2015-12-3
在线时间
55 小时
 楼主| 发表于 2017-10-12 09:16:30 | 显示全部楼层
15767909146 发表于 2017-10-11 22:40
你解决你的问题了吗     可否赐教一下

并没有遇见问题,只是感觉原子例程中模拟IIC 与标准IIC不一致,怎么还可以正常使用,有点儿想不通而已。之前看过一个帖子说。IIC对时序要求并不是很高,感觉这种说法很牵强,所以贴出来问下。
回复

使用道具 举报

16

主题

108

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
343
金钱
343
注册时间
2015-12-3
在线时间
55 小时
 楼主| 发表于 2017-10-13 10:22:51 | 显示全部楼层
顶一下,哪位大神给解释下呀
回复

使用道具 举报

14

主题

94

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
362
金钱
362
注册时间
2017-10-2
在线时间
80 小时
发表于 2017-10-14 22:19:00 | 显示全部楼层
+1.我也有点不懂。
回复

使用道具 举报

2

主题

685

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3448
金钱
3448
注册时间
2017-7-4
在线时间
869 小时
发表于 2017-10-14 23:32:54 | 显示全部楼层
1、第一点没看出时序哪里不一致?[mw_shl_code=c,true]static void i2c_bitops_stop(struct ops_i2c_dev *i2c_bus)
{
                i2c_bus->set_sda(0);                                        //stop:when CLK is high DATA change form low to high
                //i2c_bus->delayus(3);
                i2c_bus->set_scl(1);
                i2c_bus->delayus(3);
                i2c_bus->set_sda(1);                                                               
                i2c_bus->delayus(5);                                                                  
}[/mw_shl_code]
2、IO口设置为开漏模式,无需切换输入、输出状态,入DS18B20的单总线时序也是,设置为开漏模式![mw_shl_code=c,true]static char i2c_bitops_wait_ack(struct ops_i2c_dev *i2c_bus)
{
                char  ack = 1;
       
                i2c_bus->set_sda(1);
                i2c_bus->delayus(3);   
                i2c_bus->set_scl(1);
                i2c_bus->delayus(3);               
                ack = i2c_bus->get_sda();
          i2c_bus->set_scl(0);         
               
          return ack;  
}[/mw_shl_code]
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-11 18:00

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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