stm32软件i2c

本文详细介绍了如何通过软件模拟I2C协议与Max30102传感器进行通信,包括设置IO口模式、模拟起始和停止信号、读写时序以及应答信号的处理。模拟I2C不受硬件端口限制,但通信速率较慢。文中还提供了具体的代码示例,展示了如何写入和读取寄存器数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

模拟i2c不受端口限制,但是通信速率没有硬件I2C高

配置为开漏输出时可以读取输入引脚电平,需要外接上拉电阻。

配置为推挽输出时读出的数据是上一次写的数据,不能输入。

I2C起始条件和停止条件

读写时序:主机先发一个7位地址,再发一位读写位,从机应答;如果此时是写操作:主机收到应答后,就写入一个八位数据,从机再应答,以此循环;如果此时是读操作:从机发送完应答位之后,再次发送一个八位数据,主机发送应答,以此循环;

终止传输条件:接收设备不应答或者发送设备不想再发送

我们以max30102为例子来写一个i2c

由图可知,SDA和SCL都已经接了上拉电阻,所以我们直接将io口设置为开漏模式即可;

器件地址

手册对时序的介绍,起始信号和重复起始信号一样

软件模拟i2c步骤:

首先模拟起始信号和停止信号:

//起始信号:scl在高电平时将sda拉低
MyI2C_W_SDA(1);
MyI2C_W_SCL(1);
MyI2C_W_SDA(0);
MyI2C_W_SCL(0);
//停止信号:SCL在高电平时将SDA拉高
MyI2C_W_SDA(0);
MyI2C_W_SCL(1);
MyI2C_W_SDA(1);

模拟写入单字节数据:

/*起始信号后,主机发送一个7位地址,再次发送一个数据读写位,从机应答,数据传输时,
8个bit为一个数据,9个bit为1帧,SCL低电平时SDA翻转数据,SCL高电平时SDA不许翻转数据,
高位先行*/
void MyI2C_SendByte(uint8_t Byte)
{
    uint8_t i;
    for (i = 0; i < 8; i ++)
    {
        MyI2C_W_SDA(Byte & (0x80 >> i));
        MyI2C_W_SCL(1);
        MyI2C_W_SCL(0);
    }
}

模拟读出单字节数据:

/*读数据,判断从机每次发给主机的数据是高还是低即可,先是释放总线,接着判断SDA的电平,再将SCL
拉低即可获取一位数据,循环八次即可获取一个字节数据*/
uint8_t MyI2C_ReceiveByte(void)
{
    uint8_t i, Byte = 0x00;
    MyI2C_W_SDA(1);
    for (i = 0; i < 8; i ++)
    {
        MyI2C_W_SCL(1);
        if (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}
        MyI2C_W_SCL(0);
    }
    return Byte;
}

主机应答信号

/*主机直接写低电平即可*/
void MyI2C_SendAck(uint8_t AckBit)
{
    MyI2C_W_SDA(AckBit);
    MyI2C_W_SCL(1);
    MyI2C_W_SCL(0);
}

从机应答

/*同样是释放总线,判断收到的信号是否是低电平,是就是应答,否就是非应答*/
uint8_t MyI2C_ReceiveAck(void)
{
    uint8_t AckBit;
    MyI2C_W_SDA(1);
    MyI2C_W_SCL(1);
    AckBit = MyI2C_R_SDA();
    MyI2C_W_SCL(0);
    return AckBit;
}

通常最常见的使用方法:往一个寄存写值控制外设,或者不断读取一个寄存器,获取寄存器得到的数据

写值:主机发送起始信号,发送硬件地址,得到从机应答位,再次发送要写入的寄存器地址,得到应答位,写入数据,得到应答位,主机发送停止信号

void write_reg(uint8_t RegAddress, uint8_t Data)
{
    MyI2C_Start();
    MyI2C_SendByte(ID);
    MyI2C_ReceiveAck();
    MyI2C_SendByte(RegAddress);
    MyI2C_ReceiveAck();
    MyI2C_SendByte(Data);
    MyI2C_ReceiveAck();
    MyI2C_Stop();
}

读值:先写硬件地址,写入

/*主机发送起始信号,发送硬件地址,得到从机应答位,再次发送要写入的寄存器地址,得到应答位,
再次发送起始信号,发送硬件地址,此时要更改数据流向为读,接收到应答信号后,再次接收数据,
最后发送非应答或者应答后,主机发送停止信号*/
uint8_t read_reg(uint8_t ADDR)
{
    uint8_t ret;
    MyI2C_Start();
    MyI2C_SendByte(ID);
    MyI2C_ReceiveAck();
    MyI2C_SendByte(ADDR);
    MyI2C_ReceiveAck();
    
    MyI2C_Start();
    MyI2C_SendByte(ID|0x01);
    MyI2C_ReceiveAck();
    ret=MyI2C_ReceiveByte();
    MyI2C_SendAck(1);
    MyI2C_Stop();
    return ret;
}

注意释放总线是先拉高SDA再拉高SCL,如果搞反就是起始或者停止信号,在SCL高电平期间,从机拉高SDA是在传输数据,不会是停止信号,起始信号或者停止信号只有主机才拥有。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值