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

📄 24cxx.c

📁 i2c 下的24c系列的源代码集
💻 C
字号:
#ifndef MCU_MODEL
	#define  MCU_MODEL avr	//<----在此设定mcu类型, 51代表51系列; avr代表avr系列
#endif

//-----------------------51类MCU-------------------------------------------
#if MCU_MODEL==51	

	#include<reg51.h>		//在此设定51类MCU的头文件
	#include<intrins.h>     //_nop_()函数需要
	#include"xd.h"
	#include"xdprj.h"
	
	//---------定义I2总线端口, 可根据实际使用改变-----------
	sbit SCL=P1^0;		//I2总线时钟线
	sbit SDA=P1^1;		//I2总线数据线
	
	#define SCL_L SCL=0
	#define SCL_H SCL=1
	#define SDA_L SDA=0
	#define SDA_H SDA=1
	
	#define SDA_TO_IN		//为配合avr共用次程序而空定义的宏
	#define SDA_TO_OUT		//为配合avr共用次程序而空定义的宏
	
	#define SDA_IF_L SDA==0	//如果sda为低
	#define SDA_IF_H SDA==1	//如果sda为高
	
	//------------------------------------------------------
	#define DELAY_us _nop_(); _nop_(); _nop_(); _nop_(); _nop_()	//延时用,如果要加长延时,可增加或减少 _nop_();
	
//------------------------avr类MCU-----------------------------------------
#elif MCU_MODEL==avr	

	#include<iom16v.h>		//在此设定avr类MCU的头文件
	#include<macros.h>
	#include"xd.h"
	#include"xdprj.h"
	
	//-----定义I2总线端口, 可根据实际使用改变----
	#define SCL_L PORTC&=~BIT(0)	//I2总线时钟线
	#define SCL_H PORTC|=BIT(0)
	#define SDA_L PORTC&=~BIT(1)	//I2总线数据线
	#define SDA_H PORTC|=BIT(1)
	
	#define SDA_TO_IN DDRC&=~BIT(1); _NOP()	//设数据线位输入
	#define SDA_TO_OUT DDRC|=BIT(1); _NOP()	//设数据线位输出
	
	#define SDA_IF_L (PINC&BIT(1))==0		//如果sda为低
	#define SDA_IF_H (PINC&BIT(1))==BIT(1)	//如果sda为高
	//-------------------------------------------

	#define DELAY_us tus(7)	//avr单片机在晶振为8MHz时,延时5us, 可根据实际情况改变
	
#endif
//---------------------------------------------------------------------------



//------在此设定芯片型号------
#define e2prom 32		// <---在此设定芯片型号, 1代表24C01; 16代表24C16; 512代表24C512

#if e2prom==1
	#define PAGE_SIZE 8
	#define SIZE 0x007f
#elif e2prom==2
	#define PAGE_SIZE 8
	#define SIZE 0x00ff
#elif e2prom==4
	#define PAGE_SIZE 16
	#define SIZE 0x01ff
#elif e2prom==8
	#define PAGE_SIZE 16
	#define SIZE 0x03ff
#elif e2prom==16
	#define PAGE_SIZE 16
	#define SIZE 0x07ff
#elif e2prom==32
	#define PAGE_SIZE 32
	#define SIZE 0x0fff
#elif e2prom==64
	#define PAGE_SIZE 32
	#define SIZE 0x1fff
#elif e2prom==128
	#define PAGE_SIZE 64
	#define SIZE 0x3fff
#elif e2prom==256
	#define PAGE_SIZE 64
	#define SIZE 0x7fff
#elif e2prom==512
	#define PAGE_SIZE 128
	#define SIZE 0xffff
#endif
//--------------------------

//--------在此设定芯片地址-------
#define W_ADD_COM 0xa0	//写字节命令及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 0
#define R_ADD_COM 0xa1	//读命令字节及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 1
//-------------------------------


//-----在此改变预置错误号-----
#define I2C_ERR	ERR_10	//写字节命令及器件地址错, 在此也就是读写器件错!!
//---------------------------




//-----------4个I2总线公用函数, 可供其它I2总线器件的程序调用--------------
void i2cstart(void);	//总线上起动开始条件
uchar i2cwt(uchar a);	//把一个字节数据输入器件
uchar i2crd(void);		//i2c读要调用的函数
void i2cstop(void);		//总线上起动停止条件 
//------------------------------------------------------------------------

uchar * wt24c_fc(uchar *p, uint ad, uchar n);	//向24Cxx写入数据wt24c_h()所要调用的函数

//向24Cxx写入数据
//参数: *p_rsc要输出数据的主机内存地址指针; ad_dst要写入数据的i2c的地址(双字节); num数据个数
//参数条件: ad_dst: ad_dst+(num-1)不能大于器件的最高地址; num必须>0;
void wt24c(uchar *p_rsc, uint ad_dst, uint num)
{   uint n;

    n=ad_dst/PAGE_SIZE;		//确定地址与块地址的差
	if(n) n=(ulong)PAGE_SIZE*(n+1)-ad_dst;	
	else n=PAGE_SIZE-ad_dst;
		
    if(n>=num)		//如果ad_dst所在的数据块的末尾地址 >= ad_dst + num, 就直接写入num个数据
    {	wt24c_fc(p_rsc, ad_dst, num);
    	if(syserr!=0) return;
    }
    else			//如果ad_dst所在的数据块末尾地址 < ad_dst + num, 就先写入ad_dst所在的数据块末尾地址与 ad_dst 之差个数据
    {   p_rsc=wt24c_fc(p_rsc, ad_dst, n);
    	if(syserr!=0) return;
		
		num-=n;     //更新剩下数据个数
        ad_dst+=n;	//更新剩下数据的起始地址

        //把剩下数据写入器件
        while(num>=PAGE_SIZE)	//先按PAGE_SIZE为长度一页一页的写入
        {	p_rsc=wt24c_fc(p_rsc, ad_dst, PAGE_SIZE);
        	if(syserr!=0) return;
        	
            num-=PAGE_SIZE;		//更新剩余数据个数
        	ad_dst+=PAGE_SIZE;	//更新剩下数据的起始地址
		}
        
		if(num)			//把最后剩下的小于一个PAGE_SIZE长度的数据写入器件
			wt24c_fc(p_rsc, ad_dst, num);
    }
}


//从24cxx读出数据
//参数: *p_dst要读入数据的主机内存地址指针; ad_rsc要输出数据的i2c的地址(整形); num数据个数(整形)
//参数条件:  ad_dst+(num-1)不能大于器件的最高地址; num必须>0;
void rd24c(uchar *p_dst, uint ad_rsc, uint num)
{   uchar t=0;

	#if e2prom<32
	t=ad_rsc>>8;
	t<<=1;
	#endif
		
	i2cstart();					//发送起始信号
		
	if(i2cwt(W_ADD_COM+t))		//发送写字节命令及器件地址
	{	
		#if e2prom>16
		i2cwt(ad_rsc>>8);		//ad_rsc的高位,  发送要读出数据的地址
		#endif
		i2cwt(ad_rsc);			//ad_rsc的低位
				
		i2cstart();				//再发送起始信号
		i2cwt(R_ADD_COM+t);		//发送SLA_R, 读命令字节及器件地址
				
		for(;num>0;num--)
		{   *p_dst=i2crd();		//从器件读出一个字节
			p_dst++;
		}
	}
	else syserr=I2C_ERR;		//写字节命令及器件地址错或对方无应答
		
	i2cstop();

}



//向24Cxx写入数据wt24c_h()所要调用的函数
//返回写入n个字节后的主机内存指针
uchar * wt24c_fc(uchar *p, uint ad, uchar n)
{	uchar t=0;

	#if e2prom<32
	t=ad>>8;
	t<<=1;
	#endif
	
	i2cstart();					//发送起始信号
		
	if(i2cwt(W_ADD_COM+t))		//发送写字节命令及器件地址
	{	
		#if e2prom>16
		i2cwt(ad>>8);			//ad_dst的高位到器件
		#endif
		i2cwt(ad);				//ad_dst的低位到器件
			
		for(;n>0;n--)			//发送要写入的数据
		{   i2cwt(*p);
			p++;
		}
	}
	else syserr=I2C_ERR;		//写字节命令及器件地址错
	
	i2cstop();
    tms(6);						//延时6ms
	
	return(p);
}



//-------------------------------以下为其它I2总线器件可调用的函数--------------------------

//起始信号
void i2cstart(void)
{   
	SCL_L; DELAY_us;
    SDA_H; DELAY_us;
    SCL_H; DELAY_us;
    SDA_L; DELAY_us;
    SCL_L; DELAY_us;
}


//把一个字节数据输入器件,并以收到应答信号为止
//写入成功返回1,失败返回0
uchar i2cwt(uchar a)
{   uchar i;
	
    for(i=0;i<8;i++)
    {   SCL_L; DELAY_us;
       	if((a<<i)&0x80) SDA_H;
    	else SDA_L;
    	DELAY_us;
        SCL_H; DELAY_us;
    }
    SCL_L; DELAY_us;
    SDA_H; DELAY_us;
    SCL_H; DELAY_us;
	
	SDA_TO_IN;			//如果是avr单片机,就设SDA引脚位输入状态
	
    if(SDA_IF_L)		//测试有无应答
    {	SDA_TO_OUT;
    	return(1);		//有应答
    }
    else
    {	SDA_TO_OUT;
    	return(0);		//无应答
    }
}


//i2c读要调用的函数
//从器件读出一个字节
uchar i2crd(void)
{   uchar i,temp;
            
    for(i=0;i<8;i++)
    {   SCL_L; DELAY_us;	
        SDA_H; DELAY_us;    //置数据线接上内部上拉(数据输入方式),此为必须
        SCL_H; DELAY_us;
        temp<<=1;
        
        SDA_TO_IN;			//如果是avr单片机,就设SDA引脚位输入状态
        
		if(SDA_IF_H) temp+=1;
        DELAY_us;
        
        SDA_TO_OUT;			//如果是avr单片机,就设SDA引脚位输出状态
	}
    SCL_L; DELAY_us;		//主器件应答脉冲
    SDA_L; DELAY_us;
    SCL_H; DELAY_us;
    return(temp);
}
	

//停止信号
void i2cstop(void)
{   SCL_L; DELAY_us;
    SDA_L; DELAY_us;
    SCL_H; DELAY_us;
    SDA_H;
}

//--------------------------------------

⌨️ 快捷键说明

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