I2C数据总线协议之我见

前置知识:

  • I2C具有2根通讯线,SCL时钟线,SDA数据线;
  • 开漏输出和上拉电阻,使之闲时高电平,开漏后才低电平;
  • 一主多从(One Master N Slave)模式,程序控制主机,从机不控制;
  • 主机拿捏着SCL时钟线,即程序时刻按需变换SCL高低电平;
  • SDA由主机和从机共同操控,程序置SDA高电平 = 主机释放控制权;

时序图总览:

  • Start:开始;
  • SendByte:主机发送;
  • ReceiveAck:从机应答;(虚线)
  • ReceiveByte:从机发送;(虚线)
  • SendAck:主机应答;
  • Stop:停止;

拆分解析:

Start,开始的时序:在SCL=1的状态,SDA由1→0;

/**
  * @brief  I2C开始
  * @param  无
  * @retval 无
  */
void I2C_Start(void)
{
	I2C_SDA=1; //复合格式,第二次Start在从机应答之后调用,不确定SDA高低电平
	I2C_SCL=1;
	I2C_SDA=0;
	I2C_SCL=0;
}

SendByte,主机发送的时序:SCL拉高前,SDA跳变完成并保持住,等SCL开漏低电平后再动作;

/**
  * @brief  I2C主机发送字节(TO从机)
  * @param  8位字节
  * @retval 无
  */
void I2C_SendByte(unsigned char byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		I2C_SDA=byte&(0x80>>i);
		I2C_SCL=1;
		I2C_SCL=0;
	}
}

   

ReceiveAck,从机应答:主机要先释放数据控制权SDA=1,然后从机控制SDA了,主机控制时钟线高低中间,读取SDA中从机发的数据;

/**
  * @brief  I2C主机接收应答(From从机)
  * @param  无
  * @retval 1bit位
  */
unsigned char I2C_ReceiveAck(void)
{
	unsigned char bitAck;
	I2C_SDA=1; //主机释放数据控制权
	I2C_SCL=1;
	bitAck=I2C_SDA;
	I2C_SCL=0;
	return bitAck;
}

ReceiveByte,从机发送:主机要先释放数据控制权SDA=1,然后从机控制SDA了,通过中间变量byte一位一位存储bit,最后返回一字节;

/**
  * @brief  I2C主机接收字节(From从机)
  * @param  8位字节
  * @retval 无
  */
char I2C_ReceiveByte(void)
{
	unsigned char byte=0x00,i;
	I2C_SDA=1; //主机释放SDA;
	
	for(i=0;i<8;i++)
	{
		I2C_SCL=1;
		if(I2C_SDA){byte|=(0x80>>i);}
		I2C_SCL=0;
	}
	return byte;
}

SendAck,主机应答:主机拿到SDA的控制权,再控制SCL时钟线高→低;

/**
  * @brief  I2C主机发送应答(TO从机)
  * @param  1bit位
  * @retval 无
  */
void I2C_SendAck(unsigned char bitAck)
{
	I2C_SDA=bitAck;
	I2C_SCL=1;
	I2C_SCL=0;
}

Stop,停止:在SCL=1期间,SDA发生一个由低到高的跳变;

/**
  * @brief  I2C结束
  * @param  无
  * @retval 无
  */
void I2C_Stop(void)
{
	I2C_SDA=0;
	I2C_SCL=1;
	I2C_SDA=1;
}

拼图汇总:

将以上拼图模块,按照标准,顺序执行就能实现主机对从机的【写入】和【读取】。

以AT24C02这种E2PROM为例:

数据的写入:

void AT24C20_WriteByte(unsigned char addr,byte)
{
	char Ack;
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS); //输入从机地址找到目标从机
	Ack=I2C_ReceiveAck();
	I2C_SendByte(addr); //输入从机的字节地址
	Ack=I2C_ReceiveAck();
	I2C_SendByte(byte); //给该从机的该字节地址写入什么
	Ack=I2C_ReceiveAck();
	I2C_Stop();
}

数据的读出:

unsigned char AT24C02_ReadByte(unsigned char addr)
{
	unsigned char byte;
	unsigned char bitAck=0;
	unsigned char Ack;
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS); //输入从机地址找到目标从机
	Ack=I2C_ReceiveAck();
	I2C_SendByte(addr); //输入从机的字节地址
	Ack=I2C_ReceiveAck();
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS|0x01);  //输入从机地址找到目标从机,并置读
	Ack=I2C_ReceiveAck();
	byte=I2C_ReceiveByte(); //从机发送字节,主机收
	I2C_SendAck(bitAck);
	I2C_Stop();
	return byte;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值