STM32上进行I2C通讯
STM32上进行I2C通讯
起始信号:当SCL为高期间,SDA由高到低的跳变。
void I2C_Start(void)
{
MPU_SDA_OUT();//设置SDA为输出模式
I2C_SDA=1;
I2C_SCL=1;
I2C_Delay();
I2C_SDA=0;
I2C_Delay();
I2C_SCL=0;
}
停止信号:当SCL为高期间,SDA由低到高的跳变。
void I2C_Stop(void)
{
MPU_SDA_OUT();
I2C_SDA=0;
I2C_SCL=0;
I2C_Delay();
I2C_SCL=1;
I2C_Delay();
I2C_SDA=1;
}
应答信号ACK与非应答信号NACK: 发送器发送完一个字节的时候,就在时钟脉冲第9个周期的时候释放数据线,由接收器反馈到SDA一个应答信号。应答信号为低电平时,规定为有效应答位。规定高电平为非应答位(NACK)。
void I2C_Ack(void)
{
I2C_SCL=0;
MPU_SDA_OUT();
I2C_SDA=0;
I2C_Delay();
I2C_SCL=1;
I2C_Delay();
I2C_SCL=0;
}
void I2C_NAck(void)
{
I2C_SCL=0;
MPU_SDA_OUT();
I2C_SDA=1;
I2C_Delay();
I2C_SCL=1;
I2C_Delay();
I2C_SCL=0;
}
等待ACK信号:
u8 I2C_Wait_Ack(void)
{
u8 ucErrTime=0;
MPU_SDA_IN();
I2C_SDA=1;I2C_Delay();
I2C_SCL=1;I2C_Delay();
while(MPU_READ_SDA) //nack时sda为1,一直循环。ack时sda为0,停止循环。
{
ucErrTime++;
if(ucErrTime>250)
{
I2C_Stop();
return 1;
}
}
I2C_SCL=0;
return 0;
}
发送一个字节:
void I2C_Send_Byte(u8 txd)
{
u8 t;
MPU_SDA_OUT();
I2C_SCL=0;
for(t=0;t<8;t++)
{
I2C_SDA=(txd & 0x80)>>7; //发送txd里面的最高位,赋值到I2C_SDA
txd<<=1; //将txd的次高位放到最高位
I2C_SCL=1; //在SCL为高时数据有效,所以先准备好数据
I2C_Delay();
I2C_SCL=0;
I2C_Delay();
}
}
读取一个字节:
//ack=1时,发送ACK,ack=0,发送nACK
u8 I2C_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
MPU_SDA_IN();
for(i=0;i<8;i++ )
{
I2C_SCL=0;
I2C_Delay();
I2C_SCL=1;
receive<<=1;//将先前接收到的最低位的数据往高位方向移一位
if(MPU_READ_SDA)receive++;//数据始终保存在receive的最低位
I2C_Delay();
}
if (!ack)I2C_NAck();
else I2C_Ack();
return receive;
}
单字节写入、读取:
u8 Single_Write(unsigned char SlaveAddress,unsigned char REG_Address,unsigned char REG_data)
{
I2C_Start();
I2C_Send_Byte((SlaveAddress<<1) | 0);//发送器件地址,0代表写操作
I2C_Wait_Ack();
I2C_Send_Byte(REG_Address );//发送寄存器(Register,简写REG)地址
I2C_Wait_Ack();
I2C_Send_Byte(REG_data);//发送数据
I2C_Wait_Ack();
I2C_Stop();
return 0;
}
u8 Single_Read(unsigned char SlaveAddress,unsigned char REG_Address)
{
u8 REG_data;
I2C_Start();
I2C_Send_Byte((SlaveAddress<<1)|0);
I2C_Wait_Ack();
I2C_Send_Byte(REG_Address);
I2C_Wait_Ack();
I2C_Start();
I2C_Send_Byte((SlaveAddress<<1)|1);//发送器件地址,0代表读操作
I2C_Wait_Ack();
REG_data= I2C_Read_Byte(0);//读取数据发送nack,并把该8位数据赋值到数据寄存器中
I2C_Stop();
return REG_data;
}
连续写入、读取:
u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
//addr器件地址,reg寄存器地址,len数据长度,*buf数据起始地址
u8 i;
I2C_Start();
I2C_Send_Byte((addr<<1)|0);//0代表写入
I2C_Wait_Ack();
I2C_Send_Byte(reg);
I2C_Wait_Ack();
for(i=0;i<len;i++)
{
I2C_Send_Byte(buf[i]);
I2C_Wait_Ack();
}
I2C_Stop();
return 0;
}
u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
I2C_Start();
I2C_Send_Byte((addr<<1)|0);
I2C_Wait_Ack();
I2C_Send_Byte(reg);
I2C_Wait_Ack();
I2C_Start();
I2C_Send_Byte((addr<<1)|1);
I2C_Wait_Ack();
while(len)
{
if(len==1)*buf=I2C_Read_Byte(0);
else *buf=I2C_Read_Byte(1);
len--;
buf++;
}
I2C_Stop();
return 0;
}