⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c.c

📁 1、arm7芯片2148驱动大液晶 2、ym320240的液晶驱动 3、I2c通信at24c256 4、各种字符的显示
💻 C
字号:
#include "config.h"
#include "I2c.h"

volatile Uchar8 I2c_Mode;			//I2C工作模式0x11表示写,0x22表示读
volatile Uchar8 I2c_sla;			//I2C器件从地址
volatile Uint32 I2c_suba;			//I2C器件内部子地址
volatile Uchar8 I2c_suba_num;		//I2C子地址字节数
volatile Uchar8 *I2c_buf;			//I2C数据缓存区指针
volatile Uchar8 I2c_num;			//I2C要读取/写入的数据个数
volatile Uchar8 I2c_end;			//I2C总线结束标志:结束总线是置1
volatile Uchar8 I2c_suba_en;		//I2C子地址控制0:为子地址已经处理或者不震要子地址;1:为读取操作;2:为写操作

/*********************************************************************************************************
** 函数名称: Uchar8 I2cSendByte(Uchar8 sla, Uchar8 dat, Uint32 suba)
** 输 入: 	sla 		器件地址; 
			dat 		要发送的数据
			suba 		器件子地址
** 输 出:	返回0表示出错;返回1表示正确 
** 全局变量: 无
** 调用模块: 无
** 作 者: 邱志城
** 日 期: 2008_08_21
** 功能描述:向无子地址器件发送1字节数据
********************************************************************************************************/
Uchar8 I2cSendByte(Uchar8 sla, Uchar8 dat, Uint32 suba)
{
	I2c_sla = sla;			//器件的从机地址, R = 1
	I2c_suba = suba;			//器件子地址
	I2c_suba_num = 2; 			//器件子地址为2个字节

	I2c_buf = &dat;
	I2c_num = 1;
	I2c_suba_en = 2;
	I2c_end = 0;

	I2C0CONCLR = 0x2c;
   	I2C0CONSET = 0x40;             // 使能I2C
   	I2C0CONSET = 0x64;             // 设置为主机,并启动总线

	while(I2c_end == 0);
	if(I2c_end == 1) 	return(1);
	else return(0);
}
/*********************************************************************************************************
** 函数名称: Uchar8 I2cRcvByte(Uchar8 sla, Uchar8 *dat, Uint32 suba)
** 输 入: 	sla 		器件地址; 
			dat 		要发送的数据
			suba 		器件子地址
** 输 出:	返回0表示出错;返回1表示正确 
** 全局变量: 无
** 调用模块: 无
** 作 者: 邱志城
** 日 期: 2008_08_21
** 功能描述:从无子地址器件读取1字节数据
********************************************************************************************************/
Uchar8 I2cRcvByte(Uchar8 sla, Uchar8 *dat, Uint32 suba)
{
	I2c_sla = sla + 1;			//器件的从机地址, R = 1
	I2c_suba = suba;			//器件子地址
	I2c_suba_num = 2; 			//器件子地址为2个字节

	I2c_buf = dat;						//数据接收缓冲区指针
	I2c_num = 1;						//要读取的个数
	I2c_suba_en = 1;					//读使能
	I2c_end = 0;

	I2C0CONCLR = 0x2c;
   	I2C0CONSET = 0x40;             // 使能I2C
   	I2C0CONSET = 0x64;             // 设置为主机,并启动总线

	while(I2c_end == 0);
	if(I2c_end == 1) 	return(1);
	else return(0);
}
/*********************************************************************************************************
** 函数名称: Uchar8 I2c_ReadNByte(Uchar8 sla, Uchar8 suba_type, Uint32 suba, Uchar8 *s, Uint32 num)
** 输 入: 	sla 		器件从地址;
			suba_type 	子地址结构,1为单字节地址,2为双字节地址, 3为8+X结构 
			suba 		器件子地址
			*s 			数据接收缓冲区指针
			num 		读取个数
** 输 出:	返回0表示出错;返回1表示正确 
** 全局变量: 无
** 调用模块: 无
** 作 者: 邱志城
** 日 期: 2008_08_21
** 功能描述:从子地址器件任意地址开始读取N字节数据
********************************************************************************************************/
Uchar8 I2c_ReadNByte(Uchar8 sla, Uchar8 suba_type, Uint32 suba, Uchar8 *s, Uint32 num)
{
	if(num > 0)
	{
		switch(suba_type)
		{
			case 1:						 	//子地址为单个字节
				I2c_sla = sla + 1;			//器件的从机地址, R = 1
				I2c_suba = suba;			//器件子地址
				I2c_suba_num = 1; 			//器件子地址为1个字节
				break;
			case 2:							//子地址为两个字节
				I2c_sla = sla + 1;			//器件的从机地址, R = 1
				I2c_suba = suba;			//器件子地址
				I2c_suba_num = 2; 			//器件子地址为2个字节
				break;
			case 3:
				I2c_sla = sla + ((suba >> 7) & 0x0e) + 1;			//器件的从机地址, R = 1
				I2c_suba = suba & 0xff;			//器件子地址
				I2c_suba_num = 1; 			//器件子地址为8 + x个字节
				break;
		}
		I2c_buf = s;						//数据接收缓冲区指针
		I2c_num = num;						//要读取的个数
		I2c_suba_en = 1;					//有子地址
		I2c_end = 0;

		I2C0CONCLR = (1 << 2) | (1 << 3) | (1 << 5);			//置位:AA, SI, STA,清除AA,SI, STA的标地位
		I2C0CONSET = (1 << 5) | (1 << 6);					//置位STA, I2CEN。启动I2C总线 

		while(I2c_end == 0);
		if(I2c_end == 1) 	return(1);
		else return(0);
	}
	return(0);
}
/*********************************************************************************************************
** 函数名称: void I2c_ReadData(Uint32 suba, Uchar8 *s, Uint32 num)
** 输 入: 	
			suba 		器件子地址
			*s 			数据接收缓冲区指针
			num 		读取个数
** 输 出:	返回0表示出错;返回1表示正确 
** 全局变量: 无
** 调用模块: 无
** 作 者: 邱志城
** 日 期: 2008_08_21
** 功能描述:从子地址器件任意地址开始读取N字节数据
********************************************************************************************************/
void I2c_ReadData(Uint32 suba, Uchar8 *s, Uint32 num)
{
	if(I2c_Mode == I2c_ModeRead)
	{
		I2c_ReadNByte(AT24C256, 2, suba, s, num);
	}
}	


/*********************************************************************************************************
** 函数名称: Uchar8 I2c_WriteNByte(Uchar8 sla, Uchar8 suba_type, Uint32 suba, Uchar8 *s, Uint32 num)
** 输 入: 	sla 		器件从地址;
			suba_type 	子地址结构,1为单字节地址,2为双字节地址, 3为8+X结构 
			suba 		器件子地址
			*s 			将要写入的数据的指针
			num 		将要写入的数据的个数
** 输 出:	返回0表示出错;返回1表示正确 
** 全局变量: 无
** 调用模块: 无
** 作 者: 邱志城
** 日 期: 2008_08_21
** 功能描述:从子地址器件任意地址开始读取N字节数据
********************************************************************************************************/
Uchar8 I2c_WriteNByte(Uchar8 sla, Uchar8 suba_type, Uint32 suba, Uchar8 *s, Uint32 num)
{
	if(num > 0)
	{
		switch(suba_type)
		{
			case 1:						 	//子地址为单个字节
				I2c_sla = sla;			//器件的从机地址, R = 1
				I2c_suba = suba;			//器件子地址
				I2c_suba_num = 1; 			//器件子地址为1个字节
				break;
			case 2:							//子地址为两个字节
				I2c_sla = sla;			//器件的从机地址, R = 1
				I2c_suba = suba;			//器件子地址
				I2c_suba_num = 2; 			//器件子地址为2个字节
				break;
			case 3:
				I2c_sla = sla + ((suba >> 7) & 0x0e);			//器件的从机地址, R = 1
				I2c_suba = suba & 0xff;			//器件子地址
				I2c_suba_num = 1; 			//器件子地址为8 + x个字节
				break;
		}
		I2c_buf = s;						//数据接收缓冲区指针
		I2c_num = num;						//要读取的个数
		I2c_suba_en = 2;					//有子地址
		I2c_end = 0;

		I2C0CONCLR = (1 << 2) | (1 << 3) | (1 << 5);			//置位:AA, SI, STA,清除AA,SI, STA的标地位
		I2C0CONSET = (1 << 5) | (1 << 6);					//置位STA, I2CEN。启动I2C总线 

		while(I2c_end == 0);
		if(I2c_end == 1) 	return(1);
		else return(0);
	}
	return(0);
}

/*********************************************************************************************************
** 函数名称: void I2c_WriteData(Uint32 suba, Uchar8 *s, Uint32 num)
** 输 入: 	sla 		器件从地址;
			suba_type 	子地址结构,1为单字节地址,2为双字节地址, 3为8+X结构 
			suba 		器件子地址
			*s 			将要写入的数据的指针
			num 		将要写入的数据的个数
** 输 出:	返回0表示出错;返回1表示正确 
** 全局变量: 无
** 调用模块: 无
** 作 者: 邱志城
** 日 期: 2008_08_21
** 功能描述:从子地址器件任意地址开始读取N字节数据
********************************************************************************************************/
void I2c_WriteData(Uint32 suba, Uchar8 *s, Uint32 num)
{
	if(I2c_Mode == I2c_ModeWr)
	{
	   	IO1CLR |= I2c_wp;			//输出低地平,去掉写保护
		I2c_WriteNByte(AT24C256, 2, suba, s, num);
	   	IO1SET |= I2c_wp;			//输出低地平,去掉写保护
	}
}




/*********************************************************************************************************
** 函数名称: void I2c_IRQ(void) __irq
** 输 入: 无
** 输 出: 
** 全局变量: 无
** 调用模块: 无
** 作 者: 邱志城
** 日 期: 2008_08_21
** 功能描述:硬件I2C中断服务程序,注意处理为2字节的情况
********************************************************************************************************/
void __irq I2c_IRQ(void) 
{

	Uchar8  sta;
	
	sta = I2C0STAT;                    // 读出I2C状态字
	switch(sta)
	{  
		case  0x08:                   // 己发送起始条件
			if(1==I2c_suba_en) I2C0DAT = I2c_sla&0xFE;    // 指定子地址读时,先写入地址
			else I2C0DAT = I2c_sla;                     // 否则直接发送从机地址
			I2C0CONCLR = 0x28;        // SI=0
			break;
		
		case  0x10:
			I2C0DAT = I2c_sla;        // 重启动总线后,发送从地址
			I2C0CONCLR = 0x28;        // SI=0
			break;
		
		case  0x18:                   // 已发送SLA+W,并已接收应答
			switch(I2c_suba_en)
			{
				case 0:      // 无子地址,则直接发送数据
					if(I2c_num>0)
					{  
						I2C0DAT = *I2c_buf++;
						I2C0CONCLR = 0x28; 
						I2c_num--;
					}
					else
					{  
						I2C0CONSET = 0x10;  // 无数据发送,结束总线
						I2C0CONCLR = 0x28;
						I2c_end = 1;      // 设置总线操作结束标志
					}
					break;
				case 1:
					switch(I2c_suba_num)		   //地址字节数
					{
						case 0:
							I2C0DAT = (I2c_suba & 0xff);
							I2C0CONCLR = 0x28;
							I2c_suba_en = 0;     // 子地址己处理
							break;
						case 1:
							I2C0DAT = (I2c_suba & 0xff);		//发送子地址低字节或单字节地址
							I2C0CONCLR = 0x28;		//清除SI和STA的标志位
							I2c_suba_num--;
							break;
						case 2:								  //如果是双字节子地址
							I2C0DAT = ((I2c_suba >> 8) & 0xff);		//先发送地址字节
							I2C0CONCLR = 0x28;						//清除SI和STA的标志位
							I2c_suba_num--;							//字节数据减1
							break;
					}
					break;
				case 2:
					switch(I2c_suba_num)		  //地址字节数
					{
						case 0:
							I2C0DAT = (I2c_suba & 0xff);
							I2C0CONCLR = 0x28;
							I2c_suba_en = 0;     // 子地址己处理
							break;
						case 1:
							I2C0DAT = (I2c_suba & 0xff);		//发送子地址低字节或单字节地址
							I2C0CONCLR = 0x28;		//清除SI和STA的标志位
							I2c_suba_num--;
							break;
						case 2:								  //如果是双字节子地址
							I2C0DAT = ((I2c_suba >> 8) & 0xff);		//先发送地址字节
							I2C0CONCLR = 0x28;						//清除SI和STA的标志位
							I2c_suba_num--;							//字节数据减1
							break;
					}					
					break;
			}
			break;
		
		case  0x28:                   // 已发送I2C数据,并接收到应答
			switch(I2c_suba_en)
			{
				case 0:      // 无子地址,则直接发送数据
					if(I2c_num>0)
					{  
						I2C0DAT = *I2c_buf++;
						I2C0CONCLR = 0x28; 
						I2c_num--;
					}
					else
					{  
						I2C0CONSET = 0x10;  // 无数据发送,结束总线
						I2C0CONCLR = 0x28;
						I2c_end = 1; 
					}
					break;
				case 1:      // 若是指定地址读,则重新启动总线
					switch(I2c_suba_num)
					{
						case 0:
							I2C0CONSET = 0x20;
							I2C0CONCLR = 0x18;
							I2c_suba_en = 0;     // 子地址己处理
							break;
						case 1:
							I2C0DAT = (I2c_suba & 0xff);		//发送子地址低字节或单字节地址
							I2C0CONCLR = 0x28;		//清除SI和STA的标志位
							I2c_suba_num--;
							break;
						case 2:								  //如果是双字节子地址
							I2C0DAT = ((I2c_suba >> 8) & 0xff);		//先发送地址字节
							I2C0CONCLR = 0x28;						//清除SI和STA的标志位
							I2c_suba_num--;							//字节数据减1
							break;
					}
					break;
				case 2:      // 双字节地址
					switch(I2c_suba_num)
					{
						case 1:
							I2C0DAT = (I2c_suba & 0xff);		//发送子地址低字节或单字节地址
							I2C0CONCLR = 0x28;		//清除SI和STA的标志位
							I2c_suba_num--;
							I2c_suba_en = 0;
							break;
						case 2:								  //如果是双字节子地址
							I2C0DAT = ((I2c_suba >> 8) & 0xff);		//先发送地址字节
							I2C0CONCLR = 0x28;						//清除SI和STA的标志位
							I2c_suba_num--;							//字节数据减1
							break;
					}
					break;					
			}
			break;
		
		
		case  0x20:
		case  0x30:
		case  0x38:
			I2C0CONCLR = 0x28;        // 总线进入不可寻址从模式
			I2c_end = 0xFF;         // 总线出错,设置标志
			break;
		
		
		case  0x40:                   // 己发送SLA+R,并已接收到应答
			if(1==I2c_num)          // 最后一字节,接收数据后发送非应答信号
			{  
				I2C0CONCLR = 0x2C;     // AA=0,接收到数据后产生非应答
			}
			else                    // 接收数据并发送应答信号
			{  
				I2C0CONSET = 0x04;     // AA=1,接收到数据后产生应答
				I2C0CONCLR = 0x28;
			}
			break;
		
		case  0x50:
			*I2c_buf++ = I2C0DAT;     // 读取数据
			I2c_num--;
			if(1==I2c_num)
			{  
				I2C0CONCLR = 0x2C;     // AA=0,接收到数据后产生非应答
			}
			else
			{  
				I2C0CONSET = 0x04;     // AA=1,接收到数据后产生应答
				I2C0CONCLR = 0x28;
			}
			break;
		
		case  0x58:
			*I2c_buf++ = I2C0DAT;     // 读取最后一字节数据
			I2C0CONSET = 0x10;        // 结束总线
			I2C0CONCLR = 0x28;
			I2c_end = 1; 
			break;
			
		case  0x48:
			I2C0CONCLR = 0x28;        // 总线进入不可寻址从模式
			I2c_end = 0xFF; 
			break;
	}
	VICVectAddr = 0x00;              // 中断处理结束
}
/*********************************************************************************************************
** 函数名称: void I2C0_Init(void)
** 输 入: 无
** 输 出: 
** 全局变量: 无
** 调用模块: 无
** 作 者: 邱志城
** 日 期: 2008_08_21
** 功能描述:I2C初始化, FI2c是I2C的工作频率 
********************************************************************************************************/
void I2C0_Init(void)
{
	IO1DIR |= I2c_wp;			//设置引脚为输出 
	PINSEL0 = (PINSEL0 & 0xffffff0f) | 0x50; // P0.3 = SDA, P0.2 = SCL
	IO1DIR |= I2c_wp;			//设置引脚为输出 
   	IO1CLR |= I2c_wp;			//输出低地平,去掉写保护
	I2C0SCLH = (Fpclk / FI2c + 1) / 2;		 //设置I2C时钟
	I2C0SCLL = (Fpclk / FI2c) / 2;
	I2C0CONCLR = 0x2c;
	I2C0CONSET = 0x40;			//使能为主I2C
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -