介绍:Philips公司研发的I2C总线是由俩根通讯线:SCL(控制线),SDA(数据线),且同步、半双工、带数据应答的通用数据总线。
时序说明:
默认状态:SCL、SDA都处于高阻态,防止短路
空闲状态:SCL、SDA都处于高电平时称总线处于空闲状态。
一、起始条件:SCL高电平期间,SDA由高电平切换位低电平。
代码:
/**
* @brief I2C开始
* @param 无
* @retval 无
**/
void I2C_Start()
{
I2C_SDA=1; //先将SDA置高
I2C_SCL=1; //SCL置高
I2C_SDA=0; //在SCL置高期间将SDA拉低
I2C_SCL=0; //最后将SCL拉低
}
二、终止条件:SCL高电平期间,SDA由低电平切换为高电平。
代码:
/**
* @brief I2C停止
* @param 无
* @retval 无
**/
void I2C_Stop()
{
I2C_SDA=0; //先SDA拉低
I2C_SCL=1; //将SCL拉高
I2C_SDA=1; //最后拉高SDA,使其处于空闲状态
}
三、发送一个字节:在SCL低电平期间,主机将数据依次放在SDA上(高位在前),然后拉高SCL,从机在SCL高电平期间读取数据位(SCL高电平期间不允许SDA上的数据位发生改变),循环8次,即可发送一个字节。
代码:
/**
* @brief I2C发送一个字节
* @param Byte 一个字节
* @retval 无
**/
void I2C_SendByte(unsigned char Byte)
{
unsigned char i;
I2C_SCL=0;
for(i=0;i<8;i++)
{
I2C_SDA=Byte&(0X80>>i); //在SCL地电平期间依次将数据放入SDA上(高位在前)
I2C_SCL=1; //将SCL拉高,让从机读取数据
I2C_SCL=0; //再将SCL拉低便于发送下一位数据
}
}
四、接受一个字节:在SCL低电平期间,从机将数据依次放在SDA上(高位在前),然后拉高SCL,主机在SCL高电平期间读取数据位(SCL高电平期间不允许SDA上的数据位发生改变),循环8次,即可发送一个字节。(主机在接受前需要释放SDA)
代码:
/**
* @brief I2C接受一个字节
* @param Byte 一个字节
* @retval 无
**/
unsigned char I2C_ReceiveByte()
{
unsigned char i,Byte=0X00; //初始化
I2C_SCL=0; //先将SCL拉低
I2C_SDA=1; //释放SDA
for(i=0;i<8;i++)
{
I2C_SCL=1; //拉高SCL,让主机读取数据
if(I2C_SDA) //如果读取的数据非0
{
Byte|=(0X80>>i); //将数据转换到Byte上(按位转换)
}
I2C_SCL=0; //拉低SCL,便于读取第下一位数据
}
return Byte; //返回所接受的值
}
五、发送应答:将一个字节接受完之后,再下一个时钟时,主机发送一位数据,0表示应答、1表示非应答。
代码:
/**
* @brief I2C发送应答
* @param AckByte 应答位 0为应答 1为不应答
* @retval 无
**/
void I2C_SendAck(unsigned char AckByte)
{
I2C_SDA=AckByte; //发送应答位
I2C_SCL=1;
I2C_SCL=0;
}
六、接受应答:将一个字节发送完之后,再下一个时钟时,主机接受一位数据,判断从机是否应答,0表示应答、1表示非应答。(主机接受前需要释放SDA)
代码:
/**
* @brief I2C接受应答
* @param 无
* @retval 接受到的应答位 0为应答 1为不应答
**/
unsigned char I2C_ReceiveAck()
{
unsigned char AckByte;
I2C_SDA=1; //释放SDA
I2C_SCL=1;
AckByte=I2C_SDA; //读取应答位
I2C_SCL=0;
return AckByte; //返回应答位
七、写数据帧
八、读数据帧