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

📄 i2c.c

📁 周立功2103开发板CD资料
💻 C
📖 第 1 页 / 共 2 页
字号:
/*********************************************************************************************************
**文件名称:I2CINT.c
**功能说明:硬件I2C中断方式软件包。
**使用说明:软件包采用中断方式进行操作。
********************************************************************************************************/
#include "config.h"

/*定义用于和I2C中断传送信息的全局变量*/
volatile	uint8	slarv;			//子地址接收标志,为1时表示已接收从机子地址
volatile	uint32	adrpoint;		//定义从机缓冲区读写操作指针
volatile	uint8	I2C_n;			//I2C器件顺序号
volatile	uint8	I2C_sla;		//I2C器件从地址
volatile	uint32	I2C_suba;		//I2C器件的内部子地址
volatile	uint8	I2C_suba_num;	//I2C子地址字节数
volatile	uint8	*I2C_buf;		//I2C数据缓冲区指针,
									//如果要将I2C接口设置为从机模式,
									//那么,在调用软件包前要设置I2C数据缓冲区指针 I2C_buf
volatile	uint32	I2C_num;		//要读取/写入的数据个数
volatile	uint8	I2C_end;		//I2C总线结束标志:结束总线时置1
volatile	uint8	I2C_suba_en;	/*	子地址控制
										0-子地址已经处理或者不需要子地址
										1-读取操作
										2-写操作
									*/	
/*********************************************************************************************************
**函数名称:IRQ_I2C()
**函数功能:硬件I2C服务程序
**入口参数:无
**出口参数:无
**说明:注意处理子地址为2字节的情况
********************************************************************************************************/
void  IRQ_I2C(void)
{
	/*	读取I2C状态寄存器I2STAT
		按照全局变量的设置进行操作及设置软件标志
		清除中断逻辑,中断返回
	*/
	uint8 stat;		//用来读取I2C状态寄存器I2STAT
	stat = *((volatile uint32 *)(&I2C0STAT) + (I2C_n*0x10000));	//读取I2STAT,I2STAT=0xE001C004
	switch(stat & 0xF8)
	{
	/*根据状态码进行相应的处理*/
		case 	0x08:	/*已发送起始条件*/		//主发送和主接收都有
			/*装入SLA+W或者SLA+R*/
			if(I2C_suba_en == 1)	/*SLA+R*/	//指定子地址读
			{
				*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) = I2C_sla &0xfe;	//先写入地址
			}
			else	/*SLA+W*/
			{
				*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) = I2C_sla &0xfe;	//直接发送从机地址
			}
			/*清零SI位*/
			*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = (1<<3)|	//SI
																  (1<<5);	//STA
			break;
		case	0x10:	/*已发送重复起始条件*/	//主发送和主接收都有
			/*装入SLA+W或者SLA+R*/
			*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) = I2C_sla;	//重起总线后,重发从地址
			*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000))= 0x28;	//清零SI,STA
			break;
		case	0x18:
		case	0x28:	/*已发送I2DAT中的数据,已接收ACK*/
			if(I2C_suba_en == 0)
			{
				if(I2C_num > 0)		//如果还有数据需要读取
				{
					*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) = *I2C_buf++;	//读取数据
					*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x28;		//清零SI,STA
					I2C_num--;		//字节数减1
				}
				else	/*没有数据发送了*/
				{
					/*停止总线*/
					*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = (1<<4);	//STO
					*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x28;		//清零SI,STA
					I2C_end = 1;	//总线已经停止
				}
			}
			if(I2C_suba_en == 1)	/*若是指定地址读,则重新启动总线*/
			{
				if(I2C_suba_num == 2)			//如果是双字节子地址
				{
					*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) = ((I2C_suba>>8) & 0xff);	//先发送地址字节
					*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x28;					//清零SI,STA
					I2C_suba_num--;				//子地址字节数减1
					break;
				}
				if(I2C_suba_num == 1)			//如果是双字节子地址
				{
					*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) = (I2C_suba & 0xff);	//发送子地址低字节或单字节子地址
					*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x28;				//清零SI,STA
					I2C_suba_num--;				
					break;
				}
				if(I2C_suba_num == 0)	
				{
					*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x08;		//清零SI
					*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = 0x20;		//置位STA
					I2C_suba_en = 0;			//子地址已经处理
					break;
				}				
			}
			if(I2C_suba_en == 2)	/*指定子地址写,子地址尚未指定,则发送子地址*/
			{
				if(I2C_suba_num > 0)			
				{
					if(I2C_suba_num == 2)		//如果是双字节子地址
					{
					  	*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) =((I2C_suba>>8) & 0xff);	//先发送子地址高字节
						*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) =0x28;					//清零SI,STA
						I2C_suba_num--;				//子地址字节数减1
						break;				
					}
					if(I2C_suba_num == 1)			//如果是双字节子地址
					{
					  	*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) =(I2C_suba & 0xff);	//发送子地址低字节或单字节子地址
						*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) =0x28;				//清零SI,STA
						I2C_suba_num--;				
						I2C_suba_en = 0;
						break;
					}					
				}				
			}			
			break;
		case	0x40:	/*已发送SLA+R,已接收ACK*/
			if(I2C_num <= 1)	/*如果是最后一个字节*/
			{
				*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) =1<<2;	//下次发送非应答信号
			}
			else
			{
				*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = 1<<2;	//下次发送应答信号
			}
			*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x28;		//清零SI,SLA	
			break;
		case	0x20:	/*已发送SLA+W,已接收非应答*/
		case	0x30:	/*已发送I2DAT中的数据,已接收非应答*/
		case	0x38:	/*在SLA+R/W或数据字节中丢失仲裁*/
		case	0x48:	/*已发送SLA+R,已接收非应答*/
			*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x28;
			I2C_end = 0xff;	//总线出错
			break;		
		case	0x50:	/*已接收数据字节,已返回ACK*/
			*I2C_buf++ = *((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000));
			I2C_num--;
			if(I2C_num == 1)	/*接收最后一个字节*/
			{
				*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x2c;	//STA,SI,AA=0
			}
			else
			{
				*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = 0x04;	//AA=1
				*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x28;
			}
			break;
		case	0x58:	/*已接收数据字节,已返回非应答*/
			*I2C_buf++ = *((volatile uint32 *)(&I2DAT) + ((I2C_n*0x40000)/4));	//读取最后一字节数据
			*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = 0x10;			//结束总线
			*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x28;
			I2C_end = 1;			
			break;			
		/////////以下为从机模式所对应的状态信息/////////
		case	0x60:	//接收到自身SLA+W
		case	0x68:
			slarv = 0;
			*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = 0x04;			
			*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x38;	//清除I2C标志位,STA、STO、SI	
			break;
		case	0xa8:	//接收到SLA+R,或已经发送数据并接收到ACK位
		case	0xb0:
		case	0xb8:
			*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) = *(I2C_buf+adrpoint);	//将对应地址处的数据放入I2DAT中
			adrpoint++;
			*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = 0x04;
			*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x38;	//清除I2C标志位,STA、STO、SI	
			break;
		case	0x80:	//接收到数据
			if(slarv==0)
			{
				adrpoint = *((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000));
				slarv = 1;
			}
			else
			{				
				*(I2C_buf+adrpoint) = *((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000));
				adrpoint++;				
			}
			*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = 0x04;			
			*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x38;	//清除I2C标志位,STA、STO、SI	
			break;
		case	0xc0:	//总线结束,或总线重新启动
		default:		//其它状态
			*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = 0x04;				
			*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x38;	//清除I2C标志位,STA、STO、SI
			break;		
	}
	VICVectAddr = 0x00;				//中断处理结束
}
/*********************************************************************************************************
**函数名称:uint8  I2C_Init(uint8 n,uint8 MODE,uint32 Fi2c,uint8 Adr,uint8 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--接口初始化失败
********************************************************************************************************/

uint8  I2C_Init(uint8 n,uint8 MODE,uint32 Fi2c,uint8 Adr,uint8 slot)
{
	if(Fi2c > 400000)
	{
		Fi2c = 400000;				//强制将通信速率限制在0~400KHz的范围内
	}
	if((n!=0)&&(n!=1))						
	{
		return(0);					//n只能为0  1
	}
	if((MODE!=0)&&(MODE!=1))				
	{	
		return(0);					//MODE只能为0  1	

⌨️ 快捷键说明

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