IIC协议

一、IIC通信简介

1.IIC总线有两根双向信号线,一根是时钟线SCL,另一根是数据线SDA。

2.IIC总线上所有器件的SDA、SCL引脚输出驱动都为 开漏 结构,通过外接上拉电阻实现总线上所有节点SDA、SCL信号的线与逻辑关系;

3.总线上的所有设备通过软件寻址且具有唯一的地址

4.主从关系。从设备不能主动发起传输,其传输是受到主设备控制的。所以主机读取从机时,需先由主机向从机发读命令,然后从机发送数据到主机。

二、工作时序

1.START与STOP条件

与主设备的IIC通信由主设备发送START条件启动,并由主设备发送STOP条件终止。当SCL为高电平时,SDA线上由高到低的转换定义了START条件。当SCL为高电平时,SDA线上由低到高的转换定义了STOP条件。

2.数据有效性

在SCL的每个时钟脉冲期间传输一个数据位,一个字节由SDA线上的8位组成。字节可以是器件地址,寄存器地址,也可以是写入从器件或从器件读取的数据。数据首先传输最高位(MSB)。在START和STOP条件之间,可以从主向从传输任意数量的数据字节。SDA线上的数据必须在时钟周期的高电平期间保持稳定,因为当SCL为高电平时数据线的变化被解释为控制命令(START和STOP)。其中ACK为应答位。

                                                                                                                3. 重复开始信号

重复开始信号(ReSTART/Sr): 在结束时不给出STOP信号,而以一个时钟周期内再次给出开始信号作为替代   

4.应答信号

 协议规定数据传输过程必须包含应答(ACK)。接收器通过应答告知发送的字节已被成功接收,之后发送器可以进行下一个字节的传输。主机产生数据传输过程中的所有时钟,包括用于应答的第9个时钟。发送器在应答时钟周期内释放对SDA总线的控制,这样接收器可以通过将SDA线拉低告知发送器:数据已被成功接收。
  应答信号分为两种:
    1)当第9位(应答位)为 低电平 时,为 ACK  (Acknowledge)   信号
    2)当第9位(应答位)为 高电平 时,为 NACK(Not Acknowledge)信号
  主机发送数据,从机接收时,ACK信号由从机发出。当在SCL第9位时钟高电平信号期间,如果SDA仍然保持高电平,则主机可以直接产生STOP条件终止以后的传输或者继续ReSTART开始一个新的传输
  从机发送数据,主机读取数据时,ACK信号由主机给出。主机响应ACK表示还需要再接收数据,而当主机接收完想要的数据后,通过发送NACK告诉从机读取数据结束、释放总线。随后主机发送STOP命令,将总线释放,结束读操作。

三、一般过程

主设备想要向从设备发送数据:

1.主发送器发送START条件并寻址从接收器‘

2.主发送器将数据发送到从接收器

3.主发送器以STOP条件终止传输

主设备想要从从设备接收/读取数据:

1.主发送器发送START条件并寻址从接收器‘

2.主发送器发送请求读取的寄存器

3.主发送器从从发送器接收数据

4.主发送器以STOP条件终止传输

四、IIC模块代码

#define DELAY_TIME 5

/** 定义IIC总线时钟线和数据线 */
sbit scl = P2^0;
sbit sda = P2^1;

/**
* @brief I2C总线中一些必要的延时
*
* @param[in] i - 延时时间调整
* @return none
*/
void i2c_delay(unsigned char i)
{
    do
    {
        _nop_();	
    }
    while(i--);        
}

/**
* @brief 产生IIC总线启动条件
*
* @param[in] none
* @param[out] none
* @return none
*/
void i2c_start(void)
{
    sda = 1;
    scl = 1;
    i2c_delay(DELAY_TIME);
    sda = 0;
    i2c_delay(DELAY_TIME);
    scl = 0;    
}

/**
* @brief 产生IIC总线停止条件
*
* @param[in] none
* @param[out] none.
* @return none
*/
void i2c_stop(void)
{
    sda = 0;
    scl = 1;
    i2c_delay(DELAY_TIME);
    sda = 1;
    i2c_delay(DELAY_TIME);       
}

/**
* @brief I2C发送一个字节的数据
*
* @param[in] byt - 待发送的字节
* @return none
*/
void i2c_sendbyte(unsigned char byt)
{
    unsigned char i;
//
	EA = 0;   //关闭中断,避免因为中断而影响总线读写的时序,导致读写失败。
    for(i=0; i<8; i++){
        scl = 0;
        i2c_delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
        i2c_delay(DELAY_TIME);
        scl = 1;
        byt <<= 1;
        i2c_delay(DELAY_TIME);
    }
	EA = 1;
//
    scl = 0;  
}

/**
* @brief 等待应答
*
* @param[in] none
* @param[out] none
* @return none
*/
unsigned char i2c_waitack(void)
{
	unsigned char ackbit;
	
    scl = 1;
    i2c_delay(DELAY_TIME);
    ackbit = sda; //while(sda);  //wait ack
    scl = 0;
    i2c_delay(DELAY_TIME);
	
	return ackbit;
}

/**
* @brief I2C接收一个字节的数据
*
* @param[in] none
* @param[out] da
* @return da - 从IIC总线上接收得到数据
*/
unsigned char i2c_receivebyte(void)
{
	unsigned char da;
	unsigned char i;
//
	EA = 0;	
	for(i=0;i<8;i++){   
		scl = 1;
		i2c_delay(DELAY_TIME);
		da <<= 1;
		if(sda) 
			da |= 0x01;
		scl = 0;
		i2c_delay(DELAY_TIME);
	}
	EA = 1;
//
	return da;    
}

/**
* @brief 发送应答
*
* @param[in] ackbit - 设定是否发送应答
* @return - none
*/
void i2c_sendack(unsigned char ackbit)
{
    scl = 0;
    sda = ackbit;  //0:发送应答信号;  1:发送非应答信号
    i2c_delay(DELAY_TIME);
    scl = 1;
    i2c_delay(DELAY_TIME);
    scl = 0; 
	sda = 1;
    i2c_delay(DELAY_TIME);
}

               

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值