用c语言实现24LC256读写
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
用c语言实现24LC256读写
用c语言实现24LC256读写
用c语言实现24LC256读写(非软件模拟方式)
24LC256工作电压为2.5V~5.5V,容量为32K×8bit,为两线串行接口总线,标准与I2C TM兼容。
SCL为24LC256的时钟输入管脚,SDA为其串行地址/数据输入/数据输出管脚。
24LC256提供读顺序地址内容的操作方式,其内部的地址指针在每次读操作完成之后加1,此地址指针允许在一次读操作期间,连续顺序地读出整个存储器的内容。
#include
unsigned char i=0;
unsigned char receive=0x00;
void i2c_start()
{
SEN=1; //启动
do{
}while(SSPIF==0);
SSPIF=0;
}
void i2c_stop()
{
PEN=1; //产生停止条件
do{
;
}while(SSPIF==0);
SSPIF=0;
}
void i2c_restart()
{
RSEN=1; //启动,反复启动
do{
;
}while(SSPIF==0);
SSPIF=0;
}
void i2c_dataout() //数据发送等待过程
{
do{
;
}while(SSPIF==0);
SSPIF=0;
}
void i2c_datain() //读取24LC256时,不是读的最后一个字节时使用
{
RCEN=1;
do{
;
}while(SSPIF==0);
SSPIF=0;
receive=SSPBUF;
ACKDT=0;
ACKEN=1;
do{
;
}while(SSPIF==0);
SSPIF=0;
}
void i2c_datainlast() //读取最后一个字节,或只读取24lc256中
一个字节{
SSPIF=0;
RCEN=1;
do{
;
}while(SSPIF==0);
SSPIF=0;
receive=SSPBUF;
ACKDT=1 ;
ACKEN=1;
do{
;
}while(SSPIF==0);
SSPIF=0;
}
void i2c_error()
{
i2c_stop();
return;
}
void write(unsigned int addr,unsigned char data,unsigned int n) //向iic写入一字节数据地址,数据,字节个数
{
i2c_start();
SSPBUF=0xA0;//EEPROM寻址码和写操作命令码
i2c_dataout(); //发送
if(ACKSTAT)
i2c_error(); //无应答,错误!
else if(!ACKSTAT)
SSPBUF=addr/256;
//高eeaddr/256 ,取eeprom数据地址高字节
i2c_dataout(); //发送
if(ACKSTAT)
i2c_error(); //无应答,错误!
else if(!ACKSTAT)
SSPBUF=addr%256;//低eeaddr%256 ,取eeprom数据地址低字节
i2c_dataout(); //发送
for(i=0;i<n;++i)< p="">
{
if(ACKSTAT)//应答
i2c_error(); //无应答,错误!
else if(!ACKSTAT)
SSPBUF=data;//eedata 入eeprom的数据
i2c_dataout();//发送
}
if(ACKSTAT)//应答
i2c_error();
i2c_stop(); //产生停止位,启动eeprom内部些过程
do{
i2c_start();
SSPBUF=0xA0;
i2c_dataout();
i2c_stop();
if(!ACKSTAT)break;
}while(ACKSTAT);
}
unsigned int current_read(void)//current address read ok!
{
i2c_start();
SSPBUF=0xA1;//寻址命令码0xA0 和读命令
i2c_dataout();
if(ACKSTAT)//应答
i2c_error();
else if(!ACKSTAT)
i2c_datainlast();
i2c_stop();
return ((unsigned int)receive);
}
unsigned int random_read(unsigned int eepromaddress)
{
i2c_start();
SSPBUF=0xA0;//EEPROM寻址码和写操作命令码
i2c_dataout(); //发送
if(ACKSTAT)
i2c_error(); //无应答,错误!
else if(!ACKSTAT)
SSPBUF=eepromaddress/256;
//高eeaddr/256 ,取eeprom数据地址高字节
i2c_dataout(); //发送
if(ACKSTAT)
i2c_error(); //无应答,错误!
else if(!ACKSTAT)
SSPBUF=eepromaddress%256;//低eeaddr%256 ,取eeprom 数据地址低字节 i2c_dataout(); //发送
if(ACKSTAT)
i2c_error(); //无应答,错误!
else if(!ACKSTAT)
i2c_restart();
SSPBUF=0xA1;//寻址命令码0xA0 和读命令
i2c_dataout();
if(ACKSTAT)//应答
i2c_error();
else if(!ACKSTAT)
i2c_datainlast();
i2c_stop();
return ((unsigned int)receive);
}
void i2c_init()
{
SSPSTAT=0x00;
TRISC=0xD8;
SSPADD=19;
SSPIE=0;
SSPCON=0x28;
}
实例1
/* 51系列单片机在使用时,有时需要模拟I2C总线_nbsp;
*/
/* 这里举出一个实例(读写串行EEPROM芯片at24C02_nbsp;
*/
/************************************************************** ****** ****/
/* Name:AT24C02存储器的读写程序,用到I2C总线,含相对独立的I2C总线读写函数 */
/* Language: C51单片机编程语
言 */
/* Platform: Win98,Intel Celeron 433 Processor,伟福仿真器,仿真875
1 */
/*Author:************************
m */
/* Date: 2003广朿1旿5朿2旿5朿9旿nbsp;
*/
/* Version: 1.1.1 */
/* Others: Non
e */
/************************************************************** ****** ****/
#i nclude
#i nclude
#i nclude
#define DELAY_TIME 60 /*经实验,不要小于50!否则可能造成时序混乱* /
#define TRUE 1
#define FALSE 0
sbit SCL=P1^7;/*假设由P1.7和P1.6控制*/
sbit SDA=P1^6;
/********** Definition 函数定义 ************/
void DELAY(unsigned int t) /*延时函数*/
{
while(t!=0)
t--;
}
void I2C_Start(void)
{
/*启动I2C总线的函数,当SCL为高电平时使SDA产生一个负跳变*/ SDA=1;
SCL=1;
DELAY(DELAY_TIME);
DELAY(DELAY_TIME);
SCL=0;
DELAY(DELAY_TIME);
}
void I2C_Stop(void)
/*终止I2C总线,当SCL为高电平时使SDA产生一个正跳变*/ SDA=0;
SCL=1;
DELAY(DELAY_TIME);
SDA=1;
DELAY(DELAY_TIME);
SCL=0;
DELAY(DELAY_TIME);
}
void SEND_0(void) /* SEND ACK */
{
/*发逿,在SCL为高电平时使SDA信号为低*/
SDA=0;
SCL=1;
DELAY(DELAY_TIME);
SCL=0;
DELAY(DELAY_TIME);
}
void SEND_1(void)
{
/*发逿,在SCL为高电平时使SDA信号为高*/
SDA=1;
SCL=1;
DELAY(DELAY_TIME);
DELAY(DELAY_TIME);
}
bit Check_Acknowledge(void)
{
/*发送完一个字节后检验设备的应答信号*/ SDA=1;
SCL=1;
DELAY(DELAY_TIME/2);
F0=SDA;
DELAY(DELAY_TIME/2);
SCL=0;
DELAY(DELAY_TIME);
if(F0==1)
return FALSE;
return TRUE;
void WriteI2CByte(char b)reentrant {
/*向I2C总线写一个字芿/
char i;
for(i=0;i <8;i++)
if((b < <i)&0x80)< p="">
SEND_1();
else
SEND_0();
}
char ReadI2CByte(void)reentrant
{
/*从I2C总线读一个字芿/
char b=0,i;
for(i=0;i <8;i++)
{
SDA=1; /*释放总线*/
SCL=1; /*接受数据*/
DELAY(10);
F0=SDA;
DELAY(10);
SCL=0;
if(F0==1)
{
b=b < <1;
b=b|0x01;
}
else
b=b < <1;
}
return b;
}
/**********以下为读冿4c02的函敿*********/ void Write_One_Byte(char addr,char thedata) {
bit acktemp=1;
/*write a byte to mem*/
WriteI2CByte(0xa0);
acktemp=Check_Acknowledge();
WriteI2CByte(addr);/*address*/
acktemp=Check_Acknowledge();
WriteI2CByte(thedata);/*thedata*/
acktemp=Check_Acknowledge();
I2C_Stop();
}
void Write_A_Page(char *buffer,char addr) { bit acktemp=1;
bit wrtmp;
int i;
/*write a page to at24c02*/
I2C_Start();
WriteI2CByte(0xa0);
acktemp=Check_Acknowledge();
WriteI2CByte(addr);/*address*/
acktemp=Check_Acknowledge();
for(i=0;i <7;i++)
{
WriteI2CByte(buffer[i]);
if(!Check_Acknowledge())
{
I2C_Stop();
}
}
I2C_Stop();
}
char Read_One_Byte(char addr)
{ bit acktemp=1;
char mydata;
/*read a byte from mem*/
WriteI2CByte(0xa0);
acktemp=Check_Acknowledge();
WriteI2CByte(addr);/*address*/
acktemp=Check_Acknowledge();
I2C_Start();
WriteI2CByte(0xa1);
acktemp=Check_Acknowledge();
mydata=ReadI2CByte();
acktemp=Check_Acknowledge();
return mydata;
I2C_Stop();
}
void Read_N_Bytes(char *buffer,char n,char addr) { bit acktemp=1;
int i=0;
/*read 8 bytes from mem*/
I2C_Start();
WriteI2CByte(0xa0);
acktemp=Check_Acknowledge();
WriteI2CByte(addr);/*address*/
acktemp=Check_Acknowledge();
I2C_Start();
WriteI2CByte(0xa1);
acktemp=Check_Acknowledge();
for(i=0;i <n;i++)< p="">
{
buffer[i]=ReadI2CByte();
if(i!=n-1)
SEND_0(); /*发送应筿/
else
SEND_1(); /*发送非应答*/ }
I2C_Stop();
}
void main()
{
int i;
char mybyte;
char myarray[8];
char myarray2[8];
char rdarray[16];
for(i=0;i <8;i++)
{
myarray[i]=i;
myarray2[i]=i+0x08;
}
Write_One_Byte(0x20,0x28);
Write_A_Page(myarray,0x10);
Write_A_Page(myarray2,0x18);
mybyte=Read_One_Byte(0x20);
Read_N_Bytes(rdarray,16,0x10);
}
====================================== ========================================= ============= ======
实例2
/********************************** I2C总线驱动*************************************
模块名:I2C总线驱动型号:I2C
创建人:陈曦日期_005-6-15
修改人:陈曦日期_005-6-19
功能描述_/p>
此模块包括发送数据及接收数据,应答位发送,并提供了几个直接面对器件的操作函数,能很
方便的与用户程序进行连接并扩展?br> 需要注意的是,函数是采用延时方法产甿SCL 脉冲,对高晶振频率要做一定的修改!!
在写E2PROM的时候一定要延时!!_br>
说明_/p>
1us机器周期,晶振频率要小于12MHz
返回 1 则操作成功,返回 0 则操作失败?br> sla 为器件从地址,suba 为器件子地址?/p>
*************************************************************** **********************/
#i nclude "AT89X52.h"
#i nclude
#define _Nop() _nop_() //定义空指仿/p>
sbit SDA = P1^3; //模拟I2C数据传输使br>sbit SCL = P1^2; //模拟I2C时钟控制使/p> bit bdata I2C_Ack; //应答标志使/p> /************************************ I2C_Start ************************************
函数名:void I2C_Start()
入口_br> 出口_/p>
功能描述:启动I2C总线,即发送I2C初始条件
调用函数_nbsp;
全局变量_/p>
创建者:陈曦日期_005-6-15
修改者:日期_/p>
*************************************************************** *******************/
void I2C_Start()
{
SDA = 1; //发送起始条件的数据信号
_Nop();
SCL = 1;
_Nop(); //起始条件建立时间大于4.7us,延时
_Nop();
_Nop();
_Nop();
SDA = 0; //发送起始信叿br> _Nop(); //起始条件建立时间大于4us,延时
_Nop();
_Nop();
_Nop();
_Nop();
SCL = 0; //钳住I2C总线准备发送或接收数据
_Nop();
_Nop();
}
/************************************ I2C_Stop ************************************
函数名:void I2C_Stop()
入口_br> 出口_/p>
功能描述:结束I2C总线,即发送I2C结束条件
调用函数_nbsp;
全局变量_/p>
创建者:陈曦日期_005-6-15
修改者:日期_/p>
*************************************************************** *******************/
void I2C_Stop()
{
SDA = 0; //发送结束条件的数据信号
_Nop();
SCL = 1; //发送结束条件的时钟信号
_Nop(); //结束条件建立时间大于4us,延时
_Nop();
_Nop();
_Nop();
SDA = 1; //发送I2C总线结束信号
_Nop();
_Nop();
_Nop();
_Nop();
}
/************************************ I2C_CheckAck ************************************
函数名:bit I2C_CheckAck(void)
入口_br> 出口_(无应答),1(有应答_/p>
功能描述_br> 检验I2C总线应答信号,有应答则返囿,否则返囿,超时值取255
调用函数:void I2C_Stop()
全局变量_/p>
创建者:陈曦日期_005-6-15
修改者:日期_/p>
*************************************************************** *******************/
bit I2C_CheckAck(void)
{
uchar errtime = 255; // 因故障接收方旿Ack,超时值为255
SDA = 1;
_Nop();
_Nop();
_Nop();
SCL = 1;
_Nop(); //时钟电平周期大于 4 us
_Nop();
_Nop();
_Nop();
while(SDA)
{
errtime--;
if(errtime==0)
{
I2C_Stop();
return(0);
}
}
SCL = 0;
_Nop();
return(1);
}
/************************************ I2C_SendB ************************************
函数名:void I2C_SendB(uchar c)
入口:uchar 型数捿br> 出口_/p>
功能描述_br> 字节数据传送函数,将数捿c 发送出去,可以是地址,也可以是数据,发完后等待应答,并对
此状态位进行操作
调用函数:bit I2C_CheckAck()
全局变量:I2C_Ack
创建者:陈曦日期_005-6-15
修改者:日期_/p>
*************************************************************** *******************/
void I2C_SendB(uchar c)
{
uchar BitCnt;
for (BitCnt=0; BitCnt<8; BitCnt++) //要传送的数据长度丿使br> {
if((c<<bitcnt)&0x80) p="" 判断发送位(从高位起发逿<="">
{
SDA = 1;
}
else
{
SDA = 0;
}
_Nop();
_Nop();
SCL = 1; //置时钟线为高通知被控器开始接收数据位
_Nop(); //保证时钟高电平周期大亿4us
_Nop();
_Nop();
_Nop();
_Nop();
SCL = 0;
}
_Nop();
_Nop();
I2C_Ack = I2C_CheckAck(); //检验应答信叿br> _Nop();
_Nop();
}
/************************************ I2C_RcvB ************************************
函数名:uchar I2C_RcvB()
入口_br> 出口:uchar型数捿/p>
功能描述_br> 接收从器件传来的数据,并判断总线错误(不发应答信号),收完后需要调用应答函数? /p>
调用函数_br> 全局变量_/p>
创建者:陈曦日期_005-6-15
修改者:日期_/p>
*************************************************************** *******************/
uchar I2C_RcvB()
{
uchar retc;
uchar BitCnt; //使/p>
retc = 0;
SDA = 1; //置数据总线为输入方弿br> for(BitCnt=0;BitCnt<8;BitCnt++)
{
_Nop();
SCL = 0; //置时钟线为低准备接收数据使br> _Nop(); //时钟低电平周期大亿.7us _Nop();
_Nop();
_Nop();
_Nop();
SCL = 1; //置时钟线为高使数据有敿br> _Nop();
_Nop();
retc = retc<<1;
if(SDA==1)
{
retc = retc + 1; //读数据位,接收的数据放入retc丿br> }
_Nop();
_Nop();
}
SCL = 0;
_Nop();
_Nop();
return(retc);
}
/************************************ I2C_Ackn ************************************
函数名:void I2C_Ackn(bit a)
入口_房
出口_/p>
功能描述:主控制器进行应答信号(可以是应答或非应答信号)调用函数_br> 全局变量_/p>
创建者:陈曦日期_005-6-15
修改者:日期_/p>
*************************************************************** *******************/
void I2C_Ackn(bit a)
{
if(a==0) //在此发送应答或非应答信叿br> {
SDA = 0;
}
else
{
SDA = 1;
}
_Nop();
_Nop();
_Nop();
SCL = 1;
_Nop(); //时钟电平周期大于 4 us
_Nop();
_Nop();
_Nop();
_Nop();
SCL = 0; //清时钟线钳住I2C总线以便继续接收
_Nop();
_Nop();
}
/******************************** I2C_ISendB ************************************
函数名:bit I2C_ISendB(uchar sla, uchar suba, uchar c)
入口:从器件地址 sla,子地址 suba, 发送字芿c
出口_(操作有误)_(操作成功)
功能描述:从启动总线到发送地址、数据,结束总线的全过程_br> 如果返回1,表示操作成功,否则操作有误?/p>
调用函数:I2C_Start(),I2C_SendB(uchar c),I2C_Stop()
全局变量:I2C_Ack
创建者:陈曦日期_005-6-15
修改者:日期_/p>
*************************************************************** *******************/
bit I2C_ISendB(uchar sla, uchar suba, uchar c)
{
I2C_Start(); //启动总线
I2C_SendB(sla); //发送器件地址
if(!I2C_Ack)
{
return(0);
}
I2C_SendB(suba); //发送器件子地址
if(!I2C_Ack)
{
return(0);
}
I2C_SendB(c); //发送数捿br> if(!I2C_Ack)
{
return(0);
}
I2C_Stop(); //结束总线
return(1);
}
/********************************** I2C_IRcvB ************************************
函数名:bit I2C_IRcvB(uchar sla, uchar suba, uchar *c)
入口:从器件地址 sla, 子地址 suba, 收到的数据在 c
出口_(操作成功)_(操作有误)
功能描述:从启动总线到发送地址、读数据,结束总线的全过程?/p>
调用函数_nbsp;I2CS_tart(),
I2C_SendB(uchar c),
I2C_RcvB(),
I2C_Ackn(bit a),
I2C_Stop()
全局变量:I2C_Ack
创建者:陈曦日期_005-5-15
修改者:日期_/p>
*************************************************************** *******************/
bit I2C_IRcvB(uchar sla, uchar suba, uchar *c)
{
I2C_Start(); //启动总线
I2C_SendB(sla);
if(!I2C_Ack)
{
return(0);
}
I2C_SendB(suba); //发送器件子地址
if(!I2C_Ack)
{
return(0);
}
I2C_Start(); //重复起始条件
I2C_SendB(sla+1); //发送读操作的地址
if(!I2C_Ack)
{
return(0);
}
*c = I2C_RcvB(); //读取数据
I2C_Ackn(1); //发送非应答使br> I2C_Stop(); //结束总线return(1);
}
</bitcnt)&0x80)>
</n;i++)<>
</i)&0x80)<>
</n;++i)<>。