www.pudn.com > M26(2M).rar > I2C.c, change:2015-10-14,size:10746b


/*************************************************************************************************** 
//	* Copyright (c) 2013 
//	* All rights reserved. 
//	* 文件名称: I2C.c 
//	* 摘 要:    模拟I2C底层驱动 
//	* 当前版本: 1.0, yijian, 2013-8-2 8:13 
//	* 历史版本: V1.0 
***************************************************************************************************/ 
#include "I2C.h" 
 
#define   SDA_H    		(*POUT_I2C |= BIT_SDA) 
#define   SDA_L    		(*POUT_I2C &= ~BIT_SDA) 
#define   SCL_H    		(*POUT_I2C |= BIT_SCL) 
#define   SCL_L    		(*POUT_I2C &= ~BIT_SCL) 
#define   SET_SDA_IN	(*DIR_I2C &= ~BIT_SDA) 
#define   SET_SDA_OUT	(*DIR_I2C |= BIT_SDA) 
#define   SET_SCL_OUT	(*DIR_I2C |= BIT_SCL) 
#define   SDA_RESULT	((*PIN_I2C) & BIT_SDA) 
 
u8 volatile *POUT_I2C;						//模拟I2C引脚所在端口输出寄存器地址 
u8 const volatile *PIN_I2C;					//模拟I2C引脚所在端口输入寄存器地址 
u8 volatile *DIR_I2C;						//模拟I2C引脚所在端口方向寄存器地址 
u8 BIT_SDA;									//模拟I2C中SDA引脚所在位 
u8 BIT_SCL;									//模拟I2C中SCL引脚所在位 
u8 I2C_Ack;									//I2C应答信号 
 
/*************************************************************************************************** 
 * 函 数 名: I2C_Config 
 * 功能描述: 模拟I2C配置函数,本函数用于对模拟I2C使用的端口进行配置 
 * 函数说明: 为了达到通用的目的,本函数形参为对应端口的物理地址,暂时只支持 
 			 SDA和SCL在同一个端口的情况 
 * 输  入: 无 
 * 返  回: 无 
***************************************************************************************************/ 
void I2C_Config(u8 volatile *pout_i2c, u8 volatile *dir_i2c, 
                u8 const volatile *pin_i2c, u8 bit_sda, u8 bit_scl) 
{ 
    POUT_I2C = pout_i2c; 
    BIT_SDA = bit_sda; 
    BIT_SCL = bit_scl; 
    DIR_I2C = dir_i2c; 
    PIN_I2C = pin_i2c; 
    SET_SCL_OUT; 
    SET_SDA_OUT; 
} 
 
/*************************************************************************************************** 
 * 函 数 名: I2C_Start 
 * 功能描述: 无 
 * 函数说明: 底层函数 
 * 输  入: 无 
 * 返  回: 无 
***************************************************************************************************/ 
void I2C_Start(void) 
{ 
	SDA_H; 
	_NOP(); 
	_NOP(); 
	SCL_H; 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	SDA_L; 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	SCL_L; 
	_NOP(); 
	_NOP(); 
} 
 
/*************************************************************************************************** 
 * 函 数 名: I2C_ReStart 
 * 功能描述: 无 
 * 函数说明: 底层函数 
 * 输  入: 无 
 * 返  回: 无 
***************************************************************************************************/ 
void I2C_ReStart(void) 
{ 
	SCL_L; 
	_NOP(); 
	_NOP(); 
	SDA_H; 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	SCL_H; 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	SDA_L; 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	SCL_L; 
	_NOP(); 
	_NOP(); 
} 
 
/*************************************************************************************************** 
 * 函 数 名: I2C_Stop 
 * 功能描述: 无 
 * 函数说明: 底层函数 
 * 输  入: 无 
 * 返  回: 无 
***************************************************************************************************/ 
void I2C_Stop(void) 
{ 
	SDA_L; 
	_NOP(); 
	_NOP(); 
	SCL_H; 
	_NOP(); 
	_NOP(); 
	SDA_H; 
	_NOP(); 
	_NOP(); 
} 
 
/*************************************************************************************************** 
 * 函 数 名: I2C_DataOut 
 * 功能描述: I2C数据输出 
 * 函数说明: 底层函数 
 * 输  入: data: 待输出数据 
 * 返  回: 无 
***************************************************************************************************/ 
void I2C_DataOut(u8 data) 
{ 
	u8 i; 
	for (i=0; i<8; i++) 
	{ 
		if(data & 0x80)									//高字节在前 
			SDA_H; 
		else 
			SDA_L; 
		_NOP(); 
		_NOP(); 
		SCL_H;											//产生时钟波形 
		_NOP(); 
		_NOP(); 
		_NOP(); 
		_NOP(); 
		SCL_L; 
		data = data << 1; 
	} 
	SDA_H;												//释放总线 
	SET_SDA_IN;											//SDA设置为输入,准备检测从器件应答 
	SCL_H;												//发送第九个时钟信号,从器件产生应答 
	_NOP(); 
	_NOP(); 
	if (SDA_RESULT) 
		I2C_Ack = 0;  									//SDA==0,有应答,ACK=1 
	else 
		I2C_Ack = 1;									//SDA==1,无应答,ACK=0 
	SCL_L;												//时钟信号结束 
	SET_SDA_OUT;										//重新设置SDA为输出 
} 
 
/*************************************************************************************************** 
 * 函 数 名: I2C_DataIn 
 * 功能描述: I2C数据输入 
 * 函数说明: 底层函数 
 * 输  入: 无 
 * 返  回: 输入的数据 
***************************************************************************************************/ 
static u8 I2C_DataIn(void) 
{ 
	u8 data = 0,i; 
	SDA_H;												//释放总线 
	SET_SDA_IN; 
	for (i=0; i<8; i++) 
	{ 
		data = data << 1; 
		_NOP(); 
		SCL_L; 
		_NOP(); 
		_NOP(); 
		_NOP(); 
		_NOP(); 
		SCL_H;											//产生时钟信号高电平,开始接收数据 
		_NOP(); 
		_NOP(); 
		_NOP(); 
		_NOP(); 
		if (SDA_RESULT) 
			data = data + 0x01;							//接收数值判断 
	} 
	SCL_L;												//接收完毕 
	SET_SDA_OUT;										//接收完毕,SDA重新设置为输出 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	_NOP();										        //发送应答位 
	SDA_L; 
	SCL_H; 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	SCL_L; 
	return data;										//返回接收值 
} 
 
/*************************************************************************************************** 
//	* 函数介绍:I2C数据输入,发送非应答位 
//	* 参数:    无 
//	* 返回值:  无 
//	* 备注:	内部函数 
***************************************************************************************************/ 
static u8 I2C_DataLastIn(void) 
{ 
	u8 data=0, i; 
	SDA_H;												//释放总线 
	SET_SDA_IN; 
	for (i=0; i<8; i++) 
	{ 
		data = data << 1; 
		_NOP(); 
		SCL_L; 
		_NOP(); 
		_NOP(); 
		_NOP(); 
		_NOP(); 
		SCL_H;											//产生时钟信号高电平,开始接收数据 
		_NOP(); 
		_NOP(); 
		_NOP(); 
		_NOP(); 
		if (SDA_RESULT) 
			data = data + 0X01;							//接收数值判断 
	} 
	SCL_L;												//接收完毕 
	SET_SDA_OUT;										//接收完毕,SDA重新设置为输出 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	_NOP();												//发送非应答位 
	SDA_H; 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	SCL_H; 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	_NOP(); 
	SCL_L; 
	return data;								        //返回接收值 
} 
 
/*************************************************************************************************** 
 * 函 数 名: I2C_WriteRata 
 * 功能描述: i2c对特定芯片,特定地址写数据函数 
 * 函数说明: 底层函数 
 * 输  入: IC_addr:目标芯片地址,addr:希望读写的地址,addr:写的数据 
 * 返  回: 无 
***************************************************************************************************/ 
void I2C_WriteByte(u8 IC_addr, u8 addr, u8 data) 
{ 
	u8 Count = 0; 
    I2C_Start();								        //发送起始位 
    I2C_DataOut(IC_addr);						        //发送I2C数据寻址命令 
   	I2C_DataOut(addr);							        //发送器件内部数据保存目标地址 
   	I2C_DataOut(data);							        //发送写数据 
   	I2C_Ack = 0; 
   	I2C_Stop();									        //发送停止位 
   	while(1) 
   	{ 
	   	Count++;								        //判断器件擦写完毕 
    	I2C_Start();							        //产生起始位 
   		I2C_DataOut(IC_addr&0xfe);				        //写入器件地址 
   		I2C_Stop();								        //产生停止位 
    	if (I2C_Ack) 
    		break;	            				        //如果有应答,表示器件擦写完成,写操作完成 
    	if (Count > 50) 
	    	break; 
   	} 
} 
 
/*************************************************************************************************** 
 * 函 数 名: I2C_ReadByte 
 * 功能描述: i2c对特定芯片,特定地址写数据函数 
 * 函数说明: 底层函数 
 * 输  入: IC_addr:目标芯片地址,addr:希望读写的地址 
 * 返  回: data: 读到的数据 
***************************************************************************************************/ 
u8 I2C_ReadByte(u8 IC_addr, u8 addr) 
{ 
	u8 data; 
	I2C_Start();								        //发送起始位 
	I2C_DataOut(IC_addr);						        //发送寻址命令 
	I2C_DataOut(addr);							        //发送读地址 
	I2C_ReStart(); 
	I2C_DataOut(IC_addr|0x01);					        //寻址码和写命令 
	data = I2C_DataLastIn();					        //接收8位数据 
	I2C_Stop();									        //发送停止位 
	return	data; 
} 
 
/*************************************************************************************************** 
 * 函 数 名: I2C_MultipleRead 
 * 功能描述: i2c对特定芯片,特定地址连续读数据 
 * 函数说明: 底层函数 
 * 输  入: IC_addr:目标芯片地址,addr:希望读写的地址,num:读数据个数 
 * 返  回: 无 
***************************************************************************************************/ 
void I2C_MultipleRead(u8 IC_addr, u8 addr, u8 *arry, u16 num) 
{ 
    u8 i; 
	I2C_Start();								        //发送起始位 
	I2C_DataOut(IC_addr);						        //发送寻址命令 
	I2C_DataOut(addr);							        //发送读地址 
	I2C_ReStart(); 
	I2C_DataOut(IC_addr+1);					            //寻址码和写命令 
    for (i=0; i<num-1; i++) 
        arry[i] = I2C_DataIn(); 
	arry[i] = I2C_DataLastIn(); 
	I2C_Stop();									        //发送停止位 
} 
 
/*************************************************************************************************** 
 * 函 数 名: I2C_Write2Bytes 
 * 功能描述: i2c对特定芯片,特定地址写两字节数据函数 
 * 函数说明: 底层函数 
 * 输  入: IC_addr:目标芯片地址,addr:希望读写的地址 
 * 返  回: 无 
***************************************************************************************************/ 
void I2C_Write2Bytes(u8 IC_addr, u8 addr, u16 data) 
{ 
	u8 Count = 0; 
	I2C_Start(); 
	I2C_DataOut(IC_addr); 
	I2C_DataOut(addr); 
	I2C_DataOut(data >> 8);							    //发送16位数据的高8位 
	I2C_DataOut(data);								    //发送16位数据的低8位 
	I2C_Ack = 0; 
	I2C_Stop();									        //发送停止位 
	while(1)									        //判断器件擦写完毕 
	{ 
		Count++; 
		I2C_Start();							        //产生起始位 
		I2C_DataOut(IC_addr);					        //写入器件地址 
		I2C_Stop();								        //产生停止位 
		if (I2C_Ack) 
			break;	            				        //如果有应答,表示器件擦写完成,写操作完成 
		if (Count > 50) 
			break; 
	} 
} 
 
/*************************************************************************************************** 
 * 函 数 名: I2C_Read2Bytes 
 * 功能描述: i2c对特定芯片,特定地址读两字节数据函数 
 * 函数说明: 底层函数 
 * 输  入: IC_addr:目标芯片地址,addr:希望读写的地址 
 * 返  回: data: 读到的数据 
***************************************************************************************************/ 
u16 I2C_Read2Bytes(u8 IC_addr, u8 addr) 
{ 
	u16 data; 
	I2C_Start();								        //发送起始位 
	I2C_DataOut(IC_addr);						        //发送寻址命令 
	I2C_DataOut(addr);							        //发送读地址 
	I2C_ReStart(); 
	I2C_DataOut(IC_addr+1);					            //寻址码和写命令 
	data = I2C_DataIn(); 
	data = data << 8; 
	data |= I2C_DataLastIn(); 
	I2C_Stop();									        //发送停止位 
	return data; 
}