打印
[STM32F4]

STM32F4XX模拟i2c问题解决办法,送给模拟i2c苦恼的朋友。

[复制链接]
7817|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gbrlinux|  楼主 | 2016-12-17 12:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本人使用stm32单片机很多年了,一直都用模拟i2c(原因大家都知道),最近使用从103上拷贝过来的模拟i2c使用到STM32F4xx上,调试无法通过,读取不到应答,困扰了两天,开始以为是时钟速度过快,但是用示波器测试,其实速度很低,只有40K,时序也不应该有问题的,在103上面一直都正常使用,问题出在哪里呢?下面为大家慢慢分析。
先贴一段代码
    GPIO_Struct.GPIO_Pin = GPIO_PIN_SCL | GPIO_PIN_SDA;
    GPIO_Struct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_Struct.GPIO_OType = GPIO_OType_OD;
    GPIO_Struct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Struct.GPIO_Speed = GPIO_I2C_SPEED;
    GPIO_Init(GPIO_I2C, &GPIO_Struct);

#define Read_Bit()                  GPIO_ReadOutputDataBit(GPIO_I2C,GPIO_PIN_SDA)
相信很多人跟我一样,引脚都是这个配置。
再看字节发送
uint8_t I2C_Send_Byte(uint8_t Data)
{
    uint8_t i;
    for(i=0;i<8;i++)
        {
        if(Data&0x80)
                        I2C_SDA_H;
        else
                        I2C_SDA_L;
        I2C_Delay_us(2);
        I2C_SCL_H;
        I2C_Delay_us(2);
        Data<<=1;
        I2C_SCL_L;
        I2C_Delay_us(2);
        }
    I2C_SDA_H;
    I2C_Delay_us(2);
    I2C_SCL_H;
    I2C_Delay_us(2);
    if(Read_Bit())
                return I2C_ERR;
    I2C_SCL_L;
    I2C_Delay_us(2);
    I2C_SDA_L;
    I2C_Delay_us(2);
    return I2C_OK;
}

你是否跟我一样呢,一样就对了。
单步调试发现,问题出在
if(Read_Bit())
                return I2C_ERR;
这个地方,一直都返回错误,用示波器一看,SDA引脚是为低电平啊,这就是是问题关键点。
这个程序的写法在103上他确实没有问题,在F4上为什么就行不通呢。在查看引脚功能图上,没看出端倪。
然后我加了这样的代码
#define Read_Bit()                  GPIO_ReadInputDataBit(GPIO_I2C,GPIO_PIN_SDA)        //读SDA引脚电平
void I2C_SDA_Out(void)
{
    GPIO_InitTypeDef  GPIO_Struct;
    GPIO_Struct.GPIO_Pin = GPIO_PIN_SDA;
    GPIO_Struct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_Struct.GPIO_OType = GPIO_OType_OD;
    GPIO_Struct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Struct.GPIO_Speed = GPIO_I2C_SPEED;
    GPIO_Init(GPIO_I2C, &GPIO_Struct);
}
void I2C_SDA_In(void)
{
    GPIO_InitTypeDef  GPIO_Struct;
    GPIO_Struct.GPIO_Pin = GPIO_PIN_SDA;
    GPIO_Struct.GPIO_Mode = GPIO_Mode_IN;
//    GPIO_Struct.GPIO_OType = GPIO_OType_OD;
    GPIO_Struct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Struct.GPIO_Speed = GPIO_I2C_SPEED;
    GPIO_Init(GPIO_I2C, &GPIO_Struct);
}

uint8_t I2C_Send_Byte(uint8_t Data)
{
    uint8_t i;
    for(i=0;i<8;i++)
        {
        if(Data&0x80)
                        I2C_SDA_H;
        else
                        I2C_SDA_L;
        I2C_Delay_us(2);
        I2C_SCL_H;
        I2C_Delay_us(2);
        Data<<=1;
        I2C_SCL_L;
        I2C_Delay_us(2);
        }
    I2C_SDA_H;
    I2C_Delay_us(2);
    I2C_SDA_In();
    I2C_SCL_H;
    I2C_Delay_us(2);
    if(Read_Bit())
                return I2C_ERR;
    I2C_SDA_Out();
    I2C_SCL_L;
    I2C_Delay_us(2);
    I2C_SDA_L;
    I2C_Delay_us(2);
    return I2C_OK;
}


经测试,OK,没问题了。问题就出在SDA端口的状态。因此,F4系列在读取SDA应答的时候,必须要将GPIO变为输入模式,去读取输入寄存器的值,需要输出的时候,又必须将SDA端口改为OD输出。


按理,F1也必须这么做才可以的,为什么配置为OD也行,推测应该是工艺结构上的变化,知道的朋友解答下吧。
沙发
zhuomuniao110| | 2016-12-17 13:11 | 只看该作者
模拟I2C 必须弄懂时序图。

使用特权

评论回复
板凳
mmuuss586| | 2016-12-17 14:21 | 只看该作者
不错的经验分享

使用特权

评论回复
地板
香水城主| | 2016-12-17 21:59 | 只看该作者
无语

使用特权

评论回复
5
天灵灵地灵灵| | 2016-12-18 12:30 | 只看该作者
I2C的模拟还不错,当年做数控收音机的时候用过。

使用特权

评论回复
6
643757107| | 2016-12-18 12:39 | 只看该作者
这个在51上很容易做,在这高大上的芯片上不好做,收了楼主的资料

使用特权

评论回复
7
52wm| | 2016-12-25 20:20 | 只看该作者
一直都用模拟的。

使用特权

评论回复
8
xou822| | 2017-5-19 00:27 | 只看该作者
楼主可以分享一下完整版的代码吗

谢谢  

使用特权

评论回复
9
jkl21| | 2017-5-19 08:46 | 只看该作者
比较喜欢模拟iic,好调试。

使用特权

评论回复
10
jkl21| | 2017-5-19 08:47 | 只看该作者
使用集成的spi或者iic,不知道哪里出错了。

使用特权

评论回复
11
IT排头兵| | 2019-4-15 17:37 | 只看该作者
感谢楼主,我正好在发愁这个问题,看到有的模拟I2C例子里没有对SDA输入输出初始化,有的加了,纠结了半天到底为什么都可以,你这么一说我就不纠结了

使用特权

评论回复
12
manufact| | 2019-4-15 21:42 | 只看该作者
感谢楼主分享!一直用的模拟IIC

使用特权

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

本版积分规则

1

主题

1

帖子

0

粉丝