跳转至

STM32软件模拟I2C

初始化I2C通讯模块

开启对应外设时钟

 开启GPIO的APB2外设时钟。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE);

设置引脚输出模式

SCLSDA引脚输出模式需要设置为开漏输出模式。

1
2
3
4
5
6
7
GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;    //开漏输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_scl | GPIO_Pin_sda;  //SCL和SDA所对应的GPIO引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(IIC_GPIO_SELECT, &GPIO_InitStructure);

SCL、SDA引脚置高电平

 将SCL和SDA对应的GPIO引脚置高电平完成IIC的初始化。

GPIO_SetBits(IIC_GPIO_SELECT, IIC_SCL); //初始化SCL、SDA引脚置高电平
GPIO_SetBits(IIC_GPIO_SELECT, IIC_SDA);

IIC的6个基本时序单元

起始条件

确保SDA和SCL都被释放,然后先拉底SDA后拉低SCL就可以实现起始条件。

1
2
3
4
5
6
7
void IIC_Start(){ //起始条件
    IIC_W_SDA(1);   //确保SCL、SDA置高电平
    IIC_W_SCL(1);

    IIC_W_SDA(0);   //先拉低SDA后拉低SCL进入起始条件
    IIC_W_SCL(0);
}

终止条件

终止条件下,需要先拉低SDA,然后释放SCL,再释放SDA。

1
2
3
4
5
void IIC_Stop(){    //终止条件
    IIC_W_SDA(0);
    IIC_W_SDA(1);
    IIC_W_SDA(1);
}

发送一个字节

1
2
3
4
5
6
7
8
9
void IIC_SendBit(uint8_t Byte){ //发送一个字节
    uint8_t i;
    for (i=0;i<8;i++){      //循环8次发送一个字节
        IIC_W_SDA (Byte & (0x80 >> i)); //通过按位与的方式取出8位变量Byte的最高位

        IIC_W_SCL(1);   //驱动时钟
        IIC_W_SCL(0);
    }
}

接收一个字节

uint8_t IIC_ReceiveByte(){  //接收一个字节

    uint8_t i,Byte = 0x00;

    IIC_W_SDA(1);   //释放SDA

    for (i=0;i<8;i++){
        IIC_W_SCL(1);   //时钟置高电平接收数据

        if (IIC_R_SDA() == 1){  //如果读取数据为1
            Byte |= (0x80 >> i);    //最高位置1

            IIC_W_SCL(1);   //读取完成拉低SCL
        }
    }
    return Byte;
}

发送应答

1
2
3
4
5
6
void IIC_SendAck(uint8_t AckBit){   //发送应答
    IIC_W_SDA(AckBit);  //发送一个字节

    IIC_W_SCL(1);   //驱动时钟
    IIC_W_SCL(0);
}

接收应答

uint8_t IIC_ReceiveAck(){   //接收应答

    uint8_t AckBit;

    IIC_W_SDA(1);   //释放SDA

    IIC_W_SCL(1);   //时钟置高电平接收数据

    AckBit = IIC_R_SDA();   //读取值

    IIC_W_SCL(0);   //SCL置低

    return AckBit;
}