I2C总线属于半双工,有一条SDA线和SCL线,前者数据线,后者时钟线,内部使用开漏驱动,只能拉低不能拉高,但可以给SDA和SCL加上拉电阻将其拉高,两者初始电平都是高电平
具体流程如图

1.起始位:当SCL高电平时,将SDA拉低,表示准备开始接受信号
2.地址位:主机发送从机的地址进行匹配,每个从机的地址唯一,只有匹配才会开启传输
3.读写位:从机的七位地址发送完后跟一个读写位,0为写(主到从),1为读(从到主)。
3.ACK/NACK:将主机发送的地址与从机匹配,若匹配成功则从机将SDA拉低表示返回一个ACK信号,反之将SDA拉高表示发送一个NACK信号。
4.数据位:发送或接收的数据,当主机发送数据完成后将SDA设为输入模式,等待从机发送ACK信号(SDA拉低)反之则发送NACK将SDA位拉高,并让主机重启或停止。
5.停止位:当SCL高电平时,SDA为高则表示数据停止发送
另外,在数据传输时只有当SCL为低时,SDA才允许被改变。否则SDA都应该稳定不变。
在用BH1750的时候用到了i2c,记录一下代码和大致流程。
#define SlaveAddress 0x46
/*定义器件在IIC总线中的从地址,根据ALT ADDRESS地址引脚不同修改
由于地址位是七位的,所以在换算2进制要在后面加一个0.也就是0x46是
01000110,在数据手册里只写了前七位,注意别看差了*/
uint8_t BUF[4]; //接收数据缓存区
/***************************************************************
** 功能: 产生IIC起始信号,,当SCL为高时,SDA从高变低
** 参数: 无参数
** 返回值: 无
****************************************************************/
void BH1750_Start()
{
SDA_OUT(); //SDA设置为输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
/***************************************************************
** 功能: 产生IIC停止信号,在SCL为高时,将SDA拉高表示停止
** 参数: 无参数
** 返回值: 无
****************************************************************/
void BH1750_Stop()
{
SDA_OUT();
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
IIC_SCL=1;
delay_us(4);
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);
}
/***************************************************************
** 功能: 产生IIC应答信号
** 参数: 无参数
** 返回值: 无
****************************************************************/
void BH1750_SendACK(u8 ack)
{
SDA_OUT();
if(ack)IIC_SDA=1; //写应答信号
else IIC_SDA=0;
IIC_SCL=1; //拉高时钟线
delay_us(2); //延时
IIC_SCL=0; //拉低时钟线
delay_us(2); //延时
}
/***************************************************************
** 功能: 产生IIC接收信号,注意接收要设置成输入模式
** 参数: 无参数
** 返回值: 无
****************************************************************/
u8 BH1750_RecvACK()
{
u8 data;
SDA_IN(); //SDA设置为输入
IIC_SCL=1; //拉高时钟线
delay_us(2); //延时
data = READ_SDA; //读应答信号
IIC_SCL=0; //拉低时钟线
delay_us(2); //延时
return data;
}
/***************************************************************
** 功能: 向IIC总线发送一个字节数据
** 参数: dat:一字节数据
** 返回值: 无
****************************************************************/
void BH1750_SendByte(u8 dat)
{
u8 i,bit;
SDA_OUT(); //sda线输出
for (i=0; i<8; i++) //8位计数器
{
bit=dat&0x80;
if(bit) IIC_SDA=1;
else IIC_SDA=0;
dat <<= 1; //移出数据的最高位
IIC_SCL=1; //拉高时钟线
delay_us(2); //延时
IIC_SCL=0; //拉低时钟线
delay_us(2); //延时
}
BH1750_RecvACK();
}
/***************************************************************
** 功能: 从IIC总线接收一个字节数据
** 参数: 无参数
** 返回值: dat:接收一字节数据
****************************************************************/
u8 BH1750_RecvByte()
{
u8 i;
u8 dat = 0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1; //使能内部上拉,准备读取数据,
for (i=0; i<8; i++) //8位计数器
{
dat <<= 1;
IIC_SCL=1; //拉高时钟线
delay_us(2); //延时
if(READ_SDA) dat+=1;
IIC_SCL=0; //拉低时钟线
delay_us(2); //延时
}
return dat;
}
/***************************************************************
** 功能: 向bh1750写入命令
** 参数: 无参数
** 返回值: 无
****************************************************************/
void Single_Write_BH1750(u8 REG_Address)
{
BH1750_Start(); //起始信号
BH1750_SendByte(SlaveAddress); //发送设备地址+写信号 0
BH1750_SendByte(REG_Address); //内部寄存器地址,
BH1750_Stop(); //发送停止信号
}
/***************************************************************
** 功能: 连续读出BH1750内部数据,根据数据手册知,测量后返回的数据是十六位的
** 参数: 无参数
** 返回值: 无
****************************************************************/
void Multiple_Read_BH1750(void)
{ u8 i;
BH1750_Start(); //起始信号
BH1750_SendByte(SlaveAddress+1); //发送设备地址+读信号 1
for (i=0; i<3; i++) //连续读取2个地址数据,存储中BUF
{
BUF[i] = BH1750_RecvByte(); //BUF[0]存返回的高8位,BUF[1]存返回的低8位
if (i == 3)
{
BH1750_SendACK(1); //最后一个数据需要回NOACK
}
else
{
BH1750_SendACK(0); //回应ACK
}
}
BH1750_Stop(); //停止信号
// delay_ms(150);
}
/***************************************************************
** 功能: 初始化BH1750
** 参数: 无参数
** 返回值: 无
****************************************************************/
void BH1750_Configure(void)
{
BH1750_PortInit();
Single_Write_BH1750(0x01); //给bh1750发通电指令0x01
ADDR = 0; //将ADDR位初始化拉低,此时为0100011
}
/***************************************************************
** 功能: 读取光照度
** 参数: 无参数
** 返回值: data:返回光照度值
****************************************************************/
uint16_t Get_Bh_Value(void)
{
float temp;
unsigned int data;
int dis_data ;
Single_Write_BH1750(0x01); // 发送通电指令
Single_Write_BH1750(0x10); // 发送高分辨率指令 0x10
delay_ms(200); //等待测量结束,数据手册中显示此测量模式要120ms时间
Multiple_Read_BH1750(); //连续读出两个数据,存储在BUF中
dis_data=BUF[0];
dis_data=(dis_data<<8)+BUF[1];//合成数据,即光照数据,16位的
temp=(float)dis_data/1.2;
data=(int)temp;
return data;
}
















