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

📄 i2c.c

📁 基于lpc2103的arm7代码
💻 C
字号:
#include "LPC210x.h"                        /* LPC21xx definitions */
#include "target.h"
#include "type.h"
#include "irq.h"
#include "uart.h"
#include "i2c.h"
#include "rtc.h"

/*定义用于和I2C中断传送信息的全局变量*/
volatile	BYTE	slarv;			//子地址接收标志,为1时表示已接收从机子地址
volatile	DWORD	adrpoint;		//定义从机缓冲区读写操作指针
volatile	BYTE	I2C_n;			//I2C器件顺序号
volatile	BYTE	I2C_sla;		//I2C器件从地址
volatile	DWORD	I2C_suba;		//I2C器件的内部子地址
volatile	BYTE	I2C_suba_num;	//I2C子地址字节数
volatile	BYTE	*I2C_buf;		//I2C数据缓冲区指针,
									//如果要将I2C接口设置为从机模式,
									//那么,在调用软件包前要设置I2C数据缓冲区指针 I2C_buf
volatile	DWORD	I2C_num;		//要读取/写入的数据个数
volatile	BYTE	I2C_end;		//I2C总线结束标志:结束总线时置1

volatile	BYTE	I2C_suba_en;	/*	子地址控制
										0-子地址已经处理或者不需要子地址
										1-读取操作
										2-写操作
									*/	

void I2C0MasterHandler (void) __irq 
{
	BYTE StatValue;

    	/* this handler deals with master read and master write only */
    	StatValue = I2STAT;
    	IENABLE;
	
	switch ( StatValue )
    	{
		/*根据状态码进行相应的处理*/
		case 	0x08:	/*已发送起始条件*/		//主发送和主接收都有
			/*装入SLA+W或者SLA+R*/
			I2DAT = I2C_sla;
			I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);
			break;

		case	0x10:	/*已发送重复起始条件*/	//主发送和主接收都有
			/*装入SLA+W或者SLA+R*/
			I2DAT = I2C_sla;
			I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);
			break;
	
		case	0x18:
		case	0x28:	/*已发送I2DAT中的数据,已接收ACK*/
			if(I2C_suba_en == 0)   //0-子地址已经处理或者不需要子地址
			{
				if(I2C_num > 0)		//如果还有数据需要读取
				{
					I2DAT = *I2C_buf++;	//读取数据
					I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);
					I2C_num--;		//字节数减1
				}
				else	/*没有数据发送了*/
				{
					/*停止总线*/
					I2CONSET = I2CONSET_STO;
					I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);   //清零SI,STA
					I2C_end = 1;	//总线已经停止
				}
			}

			if(I2C_suba_en == 1)	/*若是指定地址读,则重新启动总线*/
			{
				if(I2C_suba_num == 2)			//如果是双字节子地址
				{
					I2DAT = ((I2C_suba>>8) & 0xff);	//先发送地址字节
					I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);   //清零SI,STA
					I2C_suba_num--;				//子地址字节数减1
					break;
				}
				if(I2C_suba_num == 1)			//如果是双字节子地址
				{
					I2DAT = (I2C_suba & 0xff);	//发送子地址低字节或单字节子地址
					I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);   //清零SI,STA
					I2C_suba_num--;				
					break;
				}
				if(I2C_suba_num == 0)	
				{
					I2CONCLR = (I2CONCLR_SIC);//清零SI
					I2CONSET = I2CONSET_STA;   //置位STA
					I2C_suba_en = 0;			//子地址已经处理
					break;
				}				
			}

			if(I2C_suba_en == 2)	/*指定子地址写,子地址尚未指定,则发送子地址*/
			{
				if(I2C_suba_num > 0)			
				{
					if(I2C_suba_num == 2)		//如果是双字节子地址
					{
						I2DAT = ((I2C_suba>>8) & 0xff);	//先发送子地址高字节
						I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);   //清零SI,STA
						I2C_suba_num--;				//子地址字节数减1
						break;				
					}
					if(I2C_suba_num == 1)			//如果是双字节子地址
					{
						I2DAT = (I2C_suba & 0xff); //发送子地址低字节或单字节子地址
						I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);   //清零SI,STA
						I2C_suba_num--;				
						I2C_suba_en = 0;
						break;
					}					
				}				
			}			
			break;
	
		case	0x40:	/*已发送SLA+R,已接收ACK*/
			if(I2C_num <= 1)	/*如果是最后一个字节*/
			{
				I2CONCLR = I2CONCLR_AAC;   //下次发送非应答信号
			}
			else
			{
				I2CONSET = I2CONSET_AA;   //下次发送应答信号
			}
			I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);   //清零SI,STA
			break;
	
		case	0x20:	/*已发送SLA+W,已接收非应答*/
		case	0x30:	/*已发送I2DAT中的数据,已接收非应答*/
		case	0x38:	/*在SLA+R/W或数据字节中丢失仲裁*/
		case	0x48:	/*已发送SLA+R,已接收非应答*/
			I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);   //清零SI,STA
			I2C_end = 0xff;	//总线出错
			break;		

		case	0x50:	/*已接收数据字节,已返回ACK*/
			*I2C_buf++ = I2DAT;
			I2C_num--;
			if(I2C_num == 1)	/*接收最后一个字节*/
			{
				I2CONCLR = (I2CONCLR_STAC | I2CONCLR_SIC | I2CONCLR_AAC); //STA,SI,AA=0
			}
			else
			{
				I2CONSET = I2CONSET_AA;
				I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC); 
			}
			break;

		case	0x58:	/*已接收数据字节,已返回非应答*/
			
			*I2C_buf++ = I2DAT ;	//读取最后一字节数据
			I2CONSET =  0x10;			//结束总线
			I2CONCLR =  0x28;
			I2C_end = 1;			
			break;		
			
		/////////以下为从机模式所对应的状态信息/////////
		case	0x60:	//接收到自身SLA+W
		case	0x68:
			slarv = 0;
			I2CONSET  = 0x04;			
			I2CONCLR  = 0x38;	//清除I2C标志位,STA、STO、SI	
			break;

		case	0xa8:	//接收到SLA+R,或已经发送数据并接收到ACK位
		case	0xb0:
		case	0xb8:
			I2DAT = *(I2C_buf+adrpoint);	//将对应地址处的数据放入I2DAT中
			adrpoint++;
			I2CONSET = 0x04;
			I2CONCLR = 0x38;	//清除I2C标志位,STA、STO、SI	
			break;

		case	0x80:	//接收到数据
			if(slarv==0)
			{
				adrpoint = I2DAT;
				slarv = 1;
			}
			else
			{				
				*(I2C_buf+adrpoint) = I2DAT;
				adrpoint++;				
			}
			I2CONSET  = 0x04;			
			I2CONCLR  = 0x38;	//清除I2C标志位,STA、STO、SI	
			break;

		case	0xc0:	//总线结束,或总线重新启动
		default:		//其它状态
			I2CONSET = 0x04;				
			I2CONCLR = 0x38;	//清除I2C标志位,STA、STO、SI
			break;		
	}
	IDISABLE;
	VICVectAddr = 0x00;				//中断处理结束
}

/*********************************************************************************************************
**函数名称:BYTE  I2C_Init(BYTE n,BYTE MODE,DWORD Fi2c,BYTE Adr,BYTE slot)
**函数功能:初始化I2C接口
**入口参数:n		:I2C接口号,0--I2C0,1--I2C1
**          MODE	:工作模式,0--从模式,1--主模式
**			Fi2c	:I2C通信速率,0~400K,如果超过400K,则会强制设置为400KHz,如果设置为从机,该参数无效
**			Adr		:当设置为从模式时,Adr表示从地址,在主模式下,该参数是无效的,可以任意设置
**			slot	:由于I2C采用IRQ中断方式,所以需要指定对应的通道,0~15
**出口参数:1--接口初始化成功,0--接口初始化失败
********************************************************************************************************/

BYTE  I2C_Init(BYTE MODE, DWORD Fi2c, BYTE Adr)
{
	/*--- Clear flags ---*/
    I2CONCLR = I2CONCLR_AAC | I2CONCLR_SIC | I2CONCLR_STAC | I2CONCLR_I2ENC;    

	if(Fi2c > 400000)
	{
		Fi2c = 400000;				//强制将通信速率限制在0~400KHz的范围内
	}

	if((MODE!=0)&&(MODE!=1))				
	{	
		return(0);					//MODE只能为0  1	
	}

	    	if ( install_irq( I2C0_INT, (void *)I2C0MasterHandler ) == FALSE )
		{
			return( FALSE );
		}
	//else							//设置I2C1接口的引脚和中断
	//{
	//	PINSEL1 = (PINSEL1 &(~(0x0f<<2)))|(0x01<<2)|(0x01<<4);	//设置I2C1管脚有效
	//	SetISR(19,slot,(DWORD)IRQ_I2C);	//设置I2C1中断
	//}	
	
	if(MODE == 1)	//I2C设置为主模式
	{
		    I2SCLL   = (Fpclk/Fi2c)/2;
			I2SCLH   = (Fpclk/Fi2c)/2;			//设定I2C时钟
			I2CONCLR = 0x2C;	
			I2CONSET = 0x40;					//使能主I2C
	}
	else			//I2C设置为从模式
	{
			I2ADR = Adr&0xfe;	//设置从机地址 
			I2CONSET = 0x44;   //使能从I2C
			I2CONCLR = 0x28;
	}
	return( TRUE );
}

/*********************************************************************************************************
**函数名称:BYTE  I2C_SendByte(BYTE n,BYTE sla,BYTE dat)
**函数功能:向无子地址器件发送1字节数据
**入口参数:n	接口号0,1
**			sla	器件地址	
**          dat	要发送的数据
**出口参数:返回值为0时表示出错,为1时表示操作正确
**说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式,程序死等待操作完成
********************************************************************************************************/
BYTE  I2C_SendByte(BYTE sla, BYTE dat)
{
	/*参数设置*/
	I2C_sla 	= sla;		//写操作的器件地址
	I2C_buf 	= &dat;		//待发送的数据
	I2C_num 	= 1;		//发送1字节数据
	I2C_suba_en = 0;		//无子地址
	I2C_end		= 0;
	
	I2CONCLR = 0x2c;
	I2CONSET = 0x60;   //设置为主机,并启动总线

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

/*********************************************************************************************************
**函数名称:BYTE  I2C_RcvByte(BYTE n,BYTE sla,BYTE *dat)
**函数功能:向无子地址器件读取1字节数据
**入口参数:n	接口号0,1
**	    sla	器件地址	
**          dat	接受数据的指针变量
**出口参数:返回值为0时表示出错,为1时表示操作正确
**说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式,程序死等待操作完成
********************************************************************************************************/
BYTE  I2C_RcvByte(BYTE sla,BYTE *dat)
{
	/*参数设置*/
	I2C_sla		= sla+1;	//读操作的器件地址
	I2C_buf		= dat;		
	I2C_num		= 1;		//读取字节数为1
	I2C_suba_en	= 0;		//无子地址
	I2C_end		= 0;	

	I2CONCLR = 0x2c;
	I2CONSET = 0x60;   //设置为主机,并启动总线

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

/*********************************************************************************************************
**函数名称:BYTE I2C_ReadNByte(BYTE n,BYTE sla,DWORD suba_type,DWORD suba,BYTE *s,DWORD num)
**函数功能:从有子地址器件任意地址开始读取N字节数据
**入口参数:		n			接口号0,1
**			sla			器件从地址	
**			suba_type	子地址结构	1-单字节地址,2-双字节地址,3-8+X结构
**			suba		器件子地址
**			*s			数据接收缓冲区指针
**			num			读取的个数
**出口参数:		1			操作成功
**			0			操作失败
**说明:程序死等待操作完成
********************************************************************************************************/
BYTE I2C_ReadNByte(BYTE sla, DWORD suba_type, DWORD suba, BYTE *s, DWORD num)
{
	if(num > 0)		/*判断num个数的格式*/
	{
		/*参数设置*/
		if(suba_type == 1)
		{
			/*子地址为单字节*/
			I2C_sla 	 = sla + 1;		//读器件的从地址,R=1
			I2C_suba	 = suba;		//器件子地址
			I2C_suba_num = 1;			//器件子地址为1字节
		}
		if(suba_type == 2)
		{
			/*子地址为2字节*/
			I2C_sla 	 = sla + 1;		//读器件的从地址,R=1
			I2C_suba	 = suba;		//器件子地址
			I2C_suba_num = 2;			//器件子地址为2字节
		}
		if(suba_type == 3)
		{
			/*子地址结构为8+X*/		//如24C04/08/16的从地址中含有A8,A9,A10
			I2C_sla 	 = sla + ((suba>>7) & 0x0e) + 1;	//读器件的从地址,R=1
			I2C_suba	 = suba & 0x0ff;					//器件子地址
			I2C_suba_num = 1;								//器件子地址为8+X
		}
		I2C_buf 	= s;	//数据接收缓冲区指针
		I2C_num 	= num;	//要读取的个数
		I2C_suba_en = 1;	//有子地址读
		I2C_end		= 0;	//

			/*清除STA,SI,AA标志位*/
			I2CONCLR = (1<<2)|	//AA
                        (1<<3)|	//SI
						(1<<5);	//STA
			/*置位STA,启动I2C总线*/
			I2CONSET = (1<<5)|	//STA
                        (1<<6);	//I2CEN	
		
		/*等待I2C操作完成*/	
		while(I2C_end == 0);	

		if(I2C_end == 1)	return(1);
		else				return(0);
	}
	return(0);
}

/*********************************************************************************************************
**函数名称:BYTE  I2C_WriteNByte(BYTE n,BYTE sla,BYTE suba_type,DWORD suba,BYTE *s,DWORD num)
**函数功能:向有子地址器件写入N字节数据
**入口参数:		n			接口号0,1
**			sla			器件从地址	
**			suba_type	子地址结构	1-单字节地址,2-双字节地址,3-8+X结构
**			suba		器件子地址
**			*s			数据发送缓冲区指针
**			num			要写入的数据的个数
**出口参数:1			操作成功
**			0			操作失败
**说明:程序死等待操作完成
********************************************************************************************************/
BYTE  I2C_WriteNByte(BYTE sla, BYTE suba_type, DWORD suba, BYTE *s, DWORD num)
{	

	/*参数设置*/
	if(num > 0)		/*判断num个数的格式*/
	{
		if(suba_type == 1)
		{
			/*子地址为单字节*/
			I2C_sla 	 = sla;		//写器件的从地址
			I2C_suba	 = suba;	//器件子地址
			I2C_suba_num = 1;		//器件子地址为1字节
		}
		if(suba_type == 2)
		{
			/*子地址为2字节*/
			I2C_sla 	 = sla;		//写器件的从地址
			I2C_suba	 = suba;	//器件子地址
			I2C_suba_num = 2;		//器件子地址为2字节
		}
		if(suba_type == 3)
		{
			/*子地址结构为8+X*/
			I2C_sla 	 = sla + ((suba>>7) & 0x0e) ;	//写器件的从地址
			I2C_suba	 = suba & 0x0ff;				//器件子地址
			I2C_suba_num = 1;							//器件子地址为8+X
		}
		I2C_buf 	= s;	//数据发送缓冲区指针
		I2C_num 	= num;	//要发送的数据的个数
		I2C_suba_en = 2;	//有子地址,写操作
		I2C_end		= 0;	//

			/*清除STA,SI,AA标志位*/
			I2CONCLR = (1<<2)|	//AA
                        (1<<3)|	//SI
						(1<<5);	//STA
			/*置位STA,启动I2C总线*/
			I2CONSET = (1<<5)|	//STA
                        (1<<6);	//I2CEN	
		
		/*等待I2C操作完成*/	
		while(I2C_end == 0);	
		if(I2C_end == 1)	return(1);
		else				return(0);
	}
	return(0);	
}

//LM75A
int Read_Temp()  // 读取当前温度
{
	char MRD[2] = {0,0}; //接收缓冲区
	int tmp =0;

	I2C_ReadNByte(LM75A_ADDR, 1, 0x00, MRD, 2);

	if((MRD[0] & 0x80) == 0x80)
	{  // 负温度
	   tmp = MRD[0];
	   tmp <<= 3;
	   tmp += (MRD[1]>>5);     
	   tmp |= 0xf800;
	}
	else
	{	// 正温度
	   tmp = MRD[0];
	   tmp <<= 3;
	   tmp += (MRD[1]>>5);    
	}
	tmp *= 10;
	tmp /= 8;
	return tmp;
}

 
BYTE EEPROM_Write(const WORD start_address, BYTE user_data)
{
	if ( I2C_WriteNByte(EEPROM_ADDR, 1, start_address, &user_data, 1) )
	//if ( I2C_WriteNByte(0, EEPROM_ADDR, 2, start_address, &user_data, 1) ) //24c256
		return 1;
	else
		return 0;
}

BYTE EEPROM_Read(const WORD start_address, BYTE *user_data)
{
	if ( I2C_SendByte(EEPROM_ADDR, 0) )
	{
		if (I2C_RcvByte(EEPROM_ADDR, user_data) )
			return 1;
		else
			return 0;
	}
	else
		return 0;
}

⌨️ 快捷键说明

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