硬件电路
1、设备的SCL SDA均设置成开漏输出模式(高:断开,低:接地)(防止在SDA线上一个输出高电平,一个输出低电平导致短路)
2、SCL与SDA各添加上拉电阻(弱上拉)
//开漏输出模式需要输入时,先输出1,再读取输入寄存器就可以了。
函数改写:
#define PORT_SCL GPIOB
#define PIN_SCL GPIO_Pin_10
#define PORT_SDA GPIOB
#define PIN_SDA GPIO_Pin_11
void SCL_W(uint8_t Bitvalue){
GPIO_WriteBit(PORT_SCL ,PIN_SCL ,(BitAction)Bitvalue);
Delay_us(10);//此处延时时长看具体挂载外设而定
}
void SDA_W(uint8_t Bitvalue){
GPIO_WriteBit(PORT_SDA ,PIN_SDA ,(BitAction)Bitvalue);
Delay_us(10);
}
uint8_t SDA_R(void){
uint8_t Bitvalue;
Bitvalue = GPIO_ReadInputDataBit(PORT_SDA ,PIN_SDA );
Delay_us(10);
return Bitvalue;
}
待机状态:
SCL与SDA都处于高电平(即处于断开状态)
起始终止条件:
SCL处于高电平期间,SDA的电平发生变化,(起始:高->低,终止:低->高),
起始终止代码:
void I2C_Start_rw(void){
SDA_W(1);
SCL_W(1);
SDA_W(0); //SCL处于高电平时,SDA由高->低
SCL_W(0); //这一步的作用是让除了起始和终止条件,每个时序都是让SCL以低电平开始,低电平结束。
}
void I2C_Stop_rw(void){
SDA_W(0);
SCL_W(1);
SDA_W(1); //SCL处于高电平时,SDA由低->高
}
发送一个字节:
在SCL低电平期间,主机以高位先行的形式依次将数据发送到SDA数据线上,从机在SCL高电平期间读取数据位(一般在其上升沿期间读取)
void I2C_SendByte_rw(uint8_t Byte){
uint8_t i;
for(i=0;i<8;i++){
SDA_W(Byte & (0x80>>i));
SCL_W(1);
SCL_W(0);}
}
接收一个字节:
主机在接收之前,释放SDA(即SDA_W(1)),在SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),主机在SCL高电平期间读取数据位。
uint8_t I2C_ReceiveByte_rw(void){
uint8_t i;
uint8_t Byte = 0;
for(i=7;i>=0;i--){
SDA_W(1);
SCL_W(1);
Byte |= (SDA_R()<<i);
SCL_W(0);}
return Byte;
}
发送应答与接收应答
发送应答:主机接收完一个字节后,在下一个时钟发送单个数据,0表示应答,1表示非应答。
void I2C_SendAck_rw(uint8_t AckBit){
SDA_W(AckBit);
SCL_W(1);
SCL_W(0);
}
uint8_t I2C_ReceiveAck_rw(void){
uint8_t AckBit = 0;
SDA_W(1);
SCL_W(1);
AckBit = SDA_R();
SCL_W(0);
return AckBit;
}