IIC详解

一、IIC 简介
I2C 是内部整合电路的称呼, 是一种串行通讯总线, 使用多主从架构, 由飞利浦公司在1980年为了让主板、 嵌入式系统或手机用以连接低速周边装置而发展。 I2C的正确读法为"I-squared-C" , 而"I-two-C"则是另一种错误但被广泛使用的读法, 在中国则多以"I方C"称之。 I2C 总线支持任何IC 生产过程(NMOS CMOS、 双极性) 。 两线――串行数据(SDA) 和串行时钟 (SCL) 线在连接到总线的器件间传递信息。 每个器件都有一个唯一的地址识别(无论是微控制器——MCU、 LCD 驱动器、 存储器或键盘接口) , 而且都可以作为一个发送器或接收器。

分为开始信号,结束信号,应答信号
1、 SCL 为高电平时, SDA 由高电平向低电平跳变,开始传送数据。
2、 SCL 为高电平时, SDA 由低电平向高电平跳变,结束传送数据。
3、接收数据的 IC 在接收到 8bit 数

从机地址+R/W 描述
0000 0000 呼叫地址
0000 0001 起始字节
0000 001X CBUS地址
0000 010X 保留供不同的总线格式
0000 011X 保留将来用
0000 1XXX HS模式主机码
1111 0XXX 10位从机地址
1111 1XXX 保留将来用

        IIC是双向通信的,那主机肯定也是需要从外设读取数据的,那这个读取的过程又是怎么实现的呢?毕竟外设对于我们而言是不能直接操作的,我们能操作的只有stm32。我们知道,一个IIC总线上,可以挂载多个设备,那么stm32如何确定是哪个外设正在跟我进行通信呢。对于此,那些生产外设模块的厂商们就约定,要是这个设备使用IIC协议进行通信,那么就要给这个设备指定一个器件地址,以供芯片访问。这个器件地址会在你购买其模块的时候在使用手册上注明。所以,要跟哪个模块通信,就一定要通过查阅其使用手册,找到它的器件地址。
         在上文所述的最开始的一个字节的数据传输过程中,这一个数据往往是器件地址。这样,对应的外设才知道,是要跟我进行通信。读取数据,也是同理,要想从外设中读取到数据,主机要明确三点:从哪个外设中的哪个地方读取数据,读取到的数据要存到哪里。
         在开始读数据之前,主机必须要先给外设发器件地址,数据所在的地址,外设才会知道你要从该地址读取数据,从而把数据通过SDA线传出来。至于具体的每个字节的传输过程,和上面所讲的从主机到外设的过程差不多,只不过反了一个反向而已,并且主机的等待应答变成了主动应答。


 


void IIC_setSDAMode_In()
{

	GPIO_InitTypeDef GPIO_IIC;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	
	GPIO_IIC.GPIO_Mode  = GPIO_Mode_IN;					 //输出
	GPIO_IIC.GPIO_Pin   = GPIO_Pin_15;		             //引脚
	GPIO_IIC.GPIO_PuPd  = GPIO_PuPd_UP;   				 //上拉
	GPIO_Init(GPIOE, &GPIO_IIC);

}



void IIC_Start()
{
		IIC_setSDAMode_Out();
		
		IIC_SDA_OUT(1);                             //总线释放状态
		IIC_SCL_OUT(1);
		delay_us(5);
	
		IIC_SDA_OUT(0);                             //SDA跳变为低电平
		delay_us(5);
	
		IIC_SCL_OUT(0);        
	  delay_us(5);



}

void IIC_Stop()
{
		IIC_setSDAMode_Out();
		
		IIC_SDA_OUT(0);          
		IIC_SCL_OUT(0);
		delay_us(5);
	
		IIC_SCL_OUT(1);                              //SDA跳变为高电平
		delay_us(5);
	
		IIC_SDA_OUT(1);        
	  delay_us(5);

}

/*
	主机写入数据到外设中
	参数值:
				 data  要写入的一个字节
	返回值:NULL
*/

void IIC_writeByte(u8 data)
{
	
	IIC_setSDAMode_Out();
	
	IIC_SCL_OUT(0);                                 //只有时钟线拉低,SDA上的数据才允许写入
	delay_us(5);
	
	//将数据一位一位的发出去
	for(int i =0;i<8;i++)
	{
	
		if(data&(0x1<<(7-i)))               //高位先入
			{
					IIC_SDA_OUT(1);
			}
			else
			{
					IIC_SDA_OUT(0);
			}
			
			 IIC_SCL_OUT(1);                 //让外设读取数据
			 delay_us(5);
		
			 IIC_SCL_OUT(0);                 //重新拉低,准备写入下一位数据
			 delay_us(5);
	}
}
u8 IIC_readByte()
{

	
  u8 data = 0;
	IIC_setSDAMode_In();

	IIC_SCL_OUT(0);                  //先拉低,为读取数据做准备
	delay_us(5);

	for(int i=0;i<8;i++)
	{
	
			IIC_SCL_OUT(1);         // SCL为高期间才可以读取数据
			delay_us(5);
		
		if(IIC_SDA_IN)
		{
				data|=(0x01<<(7-i));
			
		}else{
			data &= ~(0x1<<(7-i));
		}	
		IIC_SCL_OUT(0);
		delay_us(5);
	}
	return data;


}

u8 IIC_waitAck()
{
	
	u8 ack =0;
	IIC_setSDAMode_In();

	IIC_SCL_OUT(0);             //准备时序
	delay_us(5);
	
	IIC_SCL_OUT(1);
	delay_us(5);
	

	if(IIC_SDA_IN)
	{
				ack =1;
	}
	else
	{
				ack =0;	
	}
	
	
	IIC_SCL_OUT(0);              //拉低,表示应答完成
	delay_us(5);
	
	
	return  ack;


}

你可能感兴趣的:(单片机,嵌入式硬件)