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

📄 i2c0.c

📁 基于PHILIPS ARM7的I2C驱动程序
💻 C
字号:
/*----------------------------------------------------------------------------------
                                      文件描述
文件名: I2C0.c
功能描述:I2C的驱动程序
编译环境:KEIL C FOR ARM  - ARTX
目标CPU: LPC2XXX
作者:卢业亮
创建时间:2006.04.03
建议编辑环境:UltraEdit 11.00a+  制表符宽度为三个字符,程序可读性更好。
----------------------------------------------------------------------------------*/					  
#include		"RTOS.h"

#define		IIC0_GLOBALS	1

#include		"I2C0.h"
#include    <string.h>
#define		I2C_FREQUENCY      172800

#if (I2C_FREQUENCY >= 400000)
#error  "Out of IIC MAX Frequency"
#endif	


unsigned char saa_iic_mark=0;
/* -------------------------------------------------------------------------------------------
函数名称:IIC_Read
功能描述:按指定的从机地址的当前存储地址和长度读取数据
入口参数:SlaveAddr-从机地址,Comm-IIC总线号,Length-为要读取的长度,pBuffer-读取数据缓冲区
出口参数:OK=发送成功,ERROR=发送失败
全局变量: 结构体IIC
创建时间:2006.03.31 15:00
修改时间:2006.03.31 15:00
---------------------------------------------------------------------------------------------*/

//-------------------以上原形声明的函数供本函数调用-------------------------
uchar        IIC_Read(uchar SlaveAddr,uchar Comm,uint Length,uchar *pBuffer)
{
	NOP();	NOP();
	if(IIC.Busy)
		return ERROR;
	IIC.Busy = TRUE;
	IIC.SlaverAddress = SlaveAddr;
	IIC.Command = Comm;
	IIC.RLen = Length;	
	IIC.ReadWrite = TW_READ;
	IIC.RW_Type = IIC_READ_COMM;
	IIC.pReadBuffer = pBuffer;
	TW_Start();
	saa_iic_mark=1;		
	return OK;
}	// End of <IIC_Read> function
/* -------------------------------------------------------------------------------------------
函数名称:IIC_Write
功能描述:写数据到从机
		  1-可以用于向指定的从机的指定地址写入数据,此时pBuffer指向的是子地址+要写入数据
入口参数:Addr-从机地址,Comm-IIC总线号,Length-为要写数据的长度,pBuffer-要写数据的头指针
出口参数:OK=发送成功,ERROR=发送失败
全局变量: 结构体IIC
创建时间:2006.03.31 15:00
修改时间:2006.03.31 15:00
---------------------------------------------------------------------------------------------*/

//-------------------以上原形声明的函数供本函数调用-------------------------
uchar        IIC_Write(uchar SlaveAddr,uchar Comm,uint Length,uchar *pBuffer)
{
	NOP();	NOP();
	if(IIC.Busy)
		return ERROR;
	IIC.Busy = TRUE;
	IIC.SlaverAddress = SlaveAddr;
	IIC.Command = Comm;
	IIC.WLen = Length;	
	IIC.ReadWrite = TW_WRITE;	
	IIC.RW_Type = IIC_WRITE_COMM;
	IIC.pWriteBuffer = pBuffer;
	TW_Start();
	saa_iic_mark=1;	
	return OK;
	
}	// End of <IIC_Write> function
/* -------------------------------------------------------------------------------------------
函数名称:IIC_WriteRead
功能描述:按指定的从机地址的随机存储地址读取数据
		  1-可以用于从指定的从机的指定地址读取数据,此时pW指向要读取的地址,Wlen为要地址的长度
入口参数:Addr-从机地址,Comm-IIC总线号,Wlen-写数据或地址长度,pW-地址或数据缓冲指针
		  RLen-读数据长度,pR-读取数据的缓冲区
出口参数:OK=发送成功,ERROR=发送失败
全局变量: 结构体IIC
创建时间:2006.03.31 15:00
修改时间:2006.03.31 15:00
---------------------------------------------------------------------------------------------*/

//-------------------以上原形声明的函数供本函数调用-------------------------
uchar   IIC_WriteRead(uchar Addr,uchar Comm,uint16 WLen,uchar *pW,uint16 RLen,uchar *pR)
{		  
	NOP();	NOP();
	if(IIC.Busy)					//忙则返回错误标志以便等待
		return ERROR;
	IIC.Busy = TRUE;				//I2C忙
	IIC.SlaverAddress = Addr;		//I2C的从机地址
	IIC.Command = Comm;				//I2C的标即,使用I2C1还是I2C0口
	IIC.WLen = WLen;				//写长度
	IIC.ReadWrite = TW_WRITE;		//I2C的读写状态为写
	IIC.RW_Type = IIC_RW_COMM;		//IIC写读(需重复开始信号)
	IIC.pWriteBuffer = pW;			//写缓冲	
	IIC.RLen = RLen;				//读长度
	IIC.pReadBuffer  = pR;	  		//读缓冲
	TW_Start();						//启动IIC
	saa_iic_mark=1;
	return OK;
}	// End of <IIC_WriteRead> function

/* --------------------------------------------------------------------------------
函数名称:ReadEEPROM
功能描述:读EEPROM
入口参数:DAddr-器件地址,RAddr-要读数据的头地址,RLen-要读长度,pData-读取存储指针
出口参数:无
全局变量: 无
创建时间:2006.03.31 15:30
修改时间:2006.03.31 15:30
--------------------------------------------------------------------------------*/

//-------------------以上原形声明的函数供本函数调用-------------------------
void		ReadEEPROM(uchar DAddr,uint16 RAddr,uint16 RLen,uchar *pData)
{
	uchar		sAddr[2];
	NOP();	NOP();
	sAddr[0] = RAddr>>8;
	sAddr[1] = RAddr;
	while(IIC_WriteRead(DAddr,0,2,sAddr,RLen,pData));
	while(saa_iic_mark);
	//os_dly_wait(1);
	NOP();	NOP();
} // End of <ReadEEPROM> function
/* --------------------------------------------------------------------------------
函数名称:EEPROM_Write
功能描述:写EEPROM
入口参数:DAddr-器件地址,PageLen-器件页长度,WAddr-数据要写入从机的子地址头
		  WLen-要写入数据长度,pData-指向要写入的数据头地址	      
出口参数:输入成功与否(只判断输入EEPROM,不判断是否写成功),返回0表示成功
全局变量: 无
创建时间:2006.03.31 15:30
修改时间:2006.03.31 15:30
---------------------------------------------------------------------------------*/ 

//-------------------以上原形声明的函数供本函数调用-------------------------
uchar		WriteEEPROM(uchar  DAddr,uchar PageLen,uint16 WAddr,uint16 WLen,uchar *pData)
{
	uchar		PageBuffer[68];
	uchar		owLen;		// One time Write Len
	NOP();	NOP();
	if(PageLen%8)		return ERROR;		// 页长度必须为8的位数	
	//写首址
	PageBuffer[0] = WAddr>>8;
	PageBuffer[1] = WAddr;
	//写入的地址%页长度=页地址偏移+要写入长度
	if((WLen+(WAddr%PageLen))<=PageLen)		//要写入数据所需空间小于当前要写入页的剩余空间,则无须翻页,直接写入
	{
		memmove(&PageBuffer[2],pData,WLen);		//把要写入的地址头插入到要发送的数据头的前面组合在缓冲区里
		while(IIC_Write(DAddr,0,(WLen+2),PageBuffer));
		//IIC_Write(DAddr,0,(WLen+2),PageBuffer);	//调用I2C写函数,将数据写入指定器件
		while(saa_iic_mark);
		//os_dly_wait(1);							//任务休眠等待10MS后唤醒
	}
	else	//要写入数据所需空间超过当前要写入页的剩余空间,也就是说须翻页,则先写当前页的剩余空间,再进入翻页写数据循环,直到写完
	{
		if(WAddr%PageLen)						//要写入地址不是从整页首地址开始写
		{
			owLen = PageLen-WAddr%PageLen;					// 第一轮写的长度为当前页的剩余空间
			memmove(&PageBuffer[2],pData,owLen);			// 把要写入的头地址插入第一轮写的数据的前面
			while(IIC_Write(DAddr,0,(owLen+2),PageBuffer));	//把地址和数据写入EEPROM,先写头地址后写数据
			while(saa_iic_mark);
			//os_dly_wait(1);				//任务挂起10MS后唤醒
			WAddr += owLen;				//计算出要写入的下一页地址
			pData += owLen;				//计算下次要发送数据指针的头地址
			WLen -= owLen;				//计算剩余要发送数据的长度
		}
		
		while(WLen)						//要写入地址是从整页首地址开始写	
		{
			PageBuffer[0] = WAddr>>8;	//便于处理多页写,把新的写地址再次写入
			PageBuffer[1] = WAddr;		
			if(WLen>=PageLen)			//剩余要写入数据长度大于页长度则,一次写入一页
				owLen = PageLen;		
			else						//否则写入最后剩余的数据
				owLen = WLen;
			memmove(&PageBuffer[2],pData,owLen);				//把要写入的地址头插入到要发送的数据头的前面组合在缓冲区里
			while(IIC_Write(DAddr,0,(owLen+2),PageBuffer));		//把地址和数据写入EEPROM,先写头地址后写数据
			while(saa_iic_mark);
			//os_dly_wait(1);				//任务挂起10MS后唤醒		
			WAddr += owLen;				//计算出要写入的下一页地址
			pData += owLen;				//计算下次要发送数据指针的头地址
			WLen  -= owLen;				//计算剩余要发送数据的长度
		}
	}
	return OK;
}


/* ----------------------------------------------------------------
函数名称:I2C0_INT
功能描述:IIC0中断报务函数
入口参数:无
出口参数:无
全局变量: 结构体IIC		  
创建时间:2006.03.31 15:30
修改时间:2006.03.31 15:30
------------------------------------------------------------------*/ 
void	I2C0_INT(void)   __irq      // IIC0 interrupt function
{
	uchar		s;
	NOP();	NOP();
	s = IIC.Status = I20STAT;
	NOP();	NOP();
	switch(s)
	{			
	   /// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
		/// Start or repeat Start bit has been Transmitted
		case TW_MS_START:		//0x08:发送起始条件成功;
		case TW_MS_REP_START: 	//0x10:重复发送起始条件成功				
			I20DAT = (IIC.SlaverAddress)|IIC.ReadWrite;	//装入从机地址和读写位
			break;			
		///&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
		//主模式I2C的发送
		case TW_MT_SLA_ACK:		//0x18:成功发送从机地址和写控制位(SLA+W)成功并接收到应答ACK后
			I20DAT = *IIC.pWriteBuffer++;//若有从机子地址,写则发送地址+数据,写读则发送地址,若无则发送单写1字节数据			
			break;
		case TW_MT_DATA_ACK:	//0x28:已经发送I2DAT中的数据字节并接手到ACK 					
			IIC.WLen--;			//结构体IIC.WLEN即要向从机写的数据或地址的长度
			
			if(IIC.WLen)		//写的数据或子地址未发送完,则继续发送
			{
				I20DAT = *IIC.pWriteBuffer++;
			}			
			else
			{
			  	
				if(IIC.RW_Type==IIC_RW_COMM)		//如果读写类型为:IIC写读,则需重复开始信号即为有子地址的I2C操作,则
				{										
					IIC.ReadWrite = TW_READ;		//更改当前I2C的当前的读写状态为读
					IIC.RW_Type = IIC_READ_COMM;	//更改当前读写类型为读写IIC读命令(没有重复开始信号)
					I20CONCLR = (TW_INT_FLAG);    	//清除IIC中断标志
					VICVectAddr = 0;				//清除总中断标志
					TW_Start();						//再次启动IIC为主模式I2C数据接收
					return;
				}
				else			//当无子地址写时为单写完成,用于向从机写入1字节数据
				{				//当有子地址写时为连续写数据完成
					UserEvtFlag.IIC = IIC_WRITE_EVT_OK;
					TW_Stop();        //  结束总线 
					IIC.Busy = FALSE;
					saa_iic_mark=0;
				}
			}
			break;
		///&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
		// 主模式I2C的数据接收
		case TW_MR_SLA_ACK:		//0x40:成功发送从机地址和写控制位(SLA+R)成功并返回应答ACK后		
			if(IIC.RLen>1)		//如果要接收的数据长度大于1则
				TW_Ack();       //设置AA=1,控制下次接收到数据后发送应答信号
			else
				TW_NoAck();     //设置AA=0,控制下次接收到数据后发送非应答信号				
			break;		
		case TW_MR_DATA_ACK:	//已经接收到数据并接收到应答ACK,则
			*IIC.pReadBuffer++ = I20DAT;	//接收数据到缓冲区						
			IIC.RLen--;
			if(IIC.RLen==1)		//如果下次接收到最后一字节,则
				TW_NoAck();     //设置AA=0,控制下次接收到数据后发送非应答信号	
			break;		
		case TW_MR_DATA_NACK:	//0x40:成功发送从机地址和写控制位(SLA+R)成功并返回到非应答NACK后	
			*IIC.pReadBuffer++ = I20DAT;	//接收最后一字节数据到缓冲区	
			NOP(); 
			TW_Stop();          //结束总线 			
			IIC.Busy = FALSE;	//释放IIC
			saa_iic_mark=0;
			break;
		///&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
		// 主模式异常处理  //////////////////////////////////////////////////
		case TW_MR_SLA_NACK:		// 发送了SLA+R,接收到非ACK
		case TW_MT_SLA_NACK:		// 发送了SLA+W,接收到非ACK
		case TW_MT_DATA_NACK:		// 发送了数据,接收到非ACK
		case TW_MT_ARB_LOST:		// 丢失仲裁
		default: 
			TW_Stop();			
			IIC.Busy = FALSE;
			saa_iic_mark=0;
			break;		
	}
	I20CONCLR = (TW_INT_FLAG);    // 清除中断标志(清除STA和SI位)
	NOP();	NOP();
	VICVectAddr = 0;
}
/* ----------------------------------------------------------------
函数名称:I2cInit
功能描述:I2c初始化函数
入口参数:无
出口参数:无
全局变量: 结构体IIC		  
创建时间:2006.03.30 16:30
修改时间:2006.03.30 16:30
------------------------------------------------------------------*/ 
void		I2C0_Init(void)
{
	I20CONCLR = 0x6C;                             /* 清除控制寄存器I20CONSET中的各位*/
   	VICIntEnClr = (1<<IIC0_INT_VECT);             /* 禁止能I2c中断 */   	   
  	PINSEL0 = (PINSEL0 & 0xffffff0f) | 0x50;      /* 选择管脚为I2c */	
   	I20SCLH = (Fpclk / I2C_FREQUENCY + 1) / 2;    /* 设置高电平时间 */
   	I20SCLL = (Fpclk / I2C_FREQUENCY) / 2;        /* 设置低电平时间 */              
   	I20CONSET = 1<<TW_ENABLE;       	 		//设置为I2C主模式
   	/////////////////////////////////////////////
   	VICVectAddr6  = (uint32)I2C0_INT;			//将I2C0的中断的向量地址设置在IRQ通道6位置
  	VICVectCntl6  = (IRQ_ENABLE|IIC0_INT_VECT);	//将I2C0向量IRQ使能,其优先级为6。从而产生唯一的ISR号,并将UART0的中断编号设置为9
   	VICIntEnable  |= (1<<IIC0_INT_VECT);		//使能中断编号为9的中断请求   

	IIC.Busy = IIC.WLen = IIC.RLen = IIC.RW_Type = 0;//清除I2C的各类标志
	IIC.Command = 0;
	IIC.SlaverAddress = 0;

} //End of <I2C0_Init> Function

⌨️ 快捷键说明

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