173 2438 5004
KEROS加密芯片——品牌直销 | 免费样品 | 技术支持
当前位置:网站首页 > 资讯中心 正文 资讯中心

单片机读写AT24CXX

htxw 2023-03-15 资讯中心 34 ℃

51单片机基于E2PROM AT24C02是怎么写入以及读取数据的?比如要想写进13,是怎么写进的?

void IIC_Start(void)

{

IIC_SDA=1;

IIC_SCL=1;

delay_us(5);

IIC_SDA=0;//START:when CLK is high,DATA change form high to low

delay_us(6);

IIC_SCL=0;//钳住I2C总线,准备发送或接收数据

}

//产生IIC停止信号

void IIC_Stop(void)

{

IIC_SCL=0;

IIC_SDA=0;//STOP:when CLK is high DATA change form low to high

delay_us(6);

IIC_SCL=1;

IIC_SDA=1;//发送I2C总线结束信号

delay_us(6);

}

//等待应答信号到来

//返回值:1,接收应答失败

// 0,接收应答成功

uchar IIC_Wait_Ack(void)

{

uchar ucErrTime=0;

IIC_SDA=1;delay_us(1);

IIC_SCL=1;delay_us(1);

while(IIC_SDA)

{

ucErrTime++;

if(ucErrTime250)

{

IIC_Stop();

return 1;

}

}

IIC_SCL=0;//时钟输出0

return 0;

}

//产生ACK应答

void IIC_Ack(void)

{

IIC_SCL=0;

IIC_SDA=0;

delay_us(2);

IIC_SCL=1;

delay_us(5);

IIC_SCL=0;

}

//不产生ACK应答

void IIC_NAck(void)

{

IIC_SCL=0;

IIC_SDA=1;

delay_us(2);

IIC_SCL=1;

delay_us(5);

IIC_SCL=0;

}

//IIC发送一个字节

//返回从机有无应答

//1,有应答

//0,无应答

void IIC_Send_Byte(uchar txd)

{

uchar t;

IIC_SCL=0;//拉低时钟开始数据传输

for(t=0;t8;t++)

{

IIC_SDA=(txd0x80)7;

txd=1;

delay_us(2); //对TEA5767这三个延时都是必须的

IIC_SCL=1;

delay_us(2);

IIC_SCL=0;

delay_us(2);

}

}

//读1个字节,ack=1时,发送ACK,ack=0,发送nACK

uchar IIC_Read_Byte(unsigned char ack)

{

unsigned char i,receive=0;

for(i=0;i8;i++ )

{

IIC_SCL=0;

delay_us(2);

IIC_SCL=1;

receive=1;

if(IIC_SDA)receive++;

delay_us(1);

}

if (!ack)

IIC_NAck();//发送nACK

else

IIC_Ack(); //发送ACK

return receive;

}

//在AT24CXX指定地址读出一个数据

//ReadAddr:开始读数的地址

//返回值 :读到的数据

uchar AT24CXX_ReadOneByte(uint ReadAddr)

{

uchar temp=0;

IIC_Start();

if(EE_TYPEAT24C16)

{

IIC_Send_Byte(0XA0); //发送写命令

IIC_Wait_Ack();

IIC_Send_Byte(ReadAddr8);//发送高地址

IIC_Wait_Ack();

}else IIC_Send_Byte(0XA0+((ReadAddr/256)1)); //发送器件地址0XA0,写数据

IIC_Wait_Ack();

IIC_Send_Byte(ReadAddr%256); //发送低地址

IIC_Wait_Ack();

IIC_Start();

IIC_Send_Byte(0XA1); //进入接收模式

IIC_Wait_Ack();

temp=IIC_Read_Byte(0);

IIC_Stop();//产生一个停止条件

return temp;

}

//在AT24CXX指定地址写入一个数据

//WriteAddr :写入数据的目的地址

//DataToWrite:要写入的数据

void AT24CXX_WriteOneByte(uint WriteAddr,uchar DataToWrite)

{

IIC_Start();

if(EE_TYPEAT24C16)

{

IIC_Send_Byte(0XA0); //发送写命令

IIC_Wait_Ack();

IIC_Send_Byte(WriteAddr8);//发送高地址

}else IIC_Send_Byte(0XA0+((WriteAddr/256)1)); //发送器件地址0XA0,写数据

IIC_Wait_Ack();

IIC_Send_Byte(WriteAddr%256); //发送低地址

IIC_Wait_Ack();

IIC_Send_Byte(DataToWrite); //发送字节

IIC_Wait_Ack();

IIC_Stop();//产生一个停止条件

}

//在AT24CXX里面的指定地址开始读出指定个数的数据

//ReadAddr :开始读出的地址 对24c02为0~255

//pBuffer :数据数组首地址

//NumToRead:要读出数据的个数

void AT24CXX_Read(uint ReadAddr,uchar *pBuffer,uint NumToRead)

{

while(NumToRead)

{

*pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);

NumToRead--;

}

}

//在AT24CXX里面的指定地址开始写入指定个数的数据

//WriteAddr :开始写入的地址 对24c02为0~255

//pBuffer :数据数组首地址

//NumToWrite:要写入数据的个数

void AT24CXX_Write(uint WriteAddr,uchar *pBuffer,uint NumToWrite)

{

while(NumToWrite--)

{

AT24CXX_WriteOneByte(WriteAddr,*pBuffer);

WriteAddr++;

pBuffer++;

}

}

void cheak_key()

{

if(key1==0)

{

fs=~fs;

delay(100);

while(key1==0);

}

if(key2==0)

{

TR0=~TR0;

delay(100);

while(key2==0);

}

if(key3==0) //数据清零复位

{

delay(100);

AT24CXX_WriteOneByte(0x01,0);

t=time=time_1=time_2=0;

led1=led2=1;

while(key3==0);

}

}

求助AT24C16与51单片机的应用(附上原理图还有程序)小弟定会感激不尽

AT24C08和16是差不多的,单片机部分的原理图就不用了吧。以下是AT24Cxx是H函数

#ifndef __AT24C08_H__

#define __AT24C08_H__

#include "delay.h"

#defineOP_READ0xa1// 器件地址以及读取操作,0xa1即为1010 0001B

#defineOP_WRITE 0xa0// 器件地址以及写入操作,0xa1即为1010 0000B

sbit SCL=P3^1;         //将串行时钟总线SDA位定义在为P3.1引脚

sbit SDA=P3^2;          //将串行数据总线SDA位定义在为P3.2引脚

/*************************************************************

函数名称:start

函数功能:开始传送函数

入口参数:无

返回值  :无

*************************************************************/

void start( void )

{

SDA = 1;    //SDA初始化为高电平“1”

  SCL = 1;    //开始数据传送时,要求SCL为高电平“1”

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

SDA = 0;    //SDA的下降沿被认为是开始信号

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

SCL = 0;    //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递) 

}

/*************************************************************

函数名称:stop

函数功能:传送结束函数

入口参数:无

返回值  :无

*************************************************************/

void stop( void )

{

SDA = 0;     //SDA初始化为低电平“0”_n

SCL = 1;     //结束数据传送时,要求SCL为高电平“1”

_nop_();     //等待一个机器周期

_nop_();     //等待一个机器周期

_nop_();     //等待一个机器周期

_nop_();     //等待一个机器周期

SDA = 1;    //SDA的上升沿被认为是结束信号

_nop_();     //等待一个机器周期

_nop_();     //等待一个机器周期

_nop_();     //等待一个机器周期

_nop_();     //等待一个机器周期

SDA=0;

SCL=0;

}

/*************************************************************

函数名称:ReadData

函数功能:从AT24Cxx读取数据,从AT24Cxx移入数据到MCU

入口参数:无

返回值  :ReadData()

*************************************************************/

unsigned char ReadData()

{

unsigned char i;

unsigned char x;   //储存从AT24Cxx中读出的数据

for(i = 0; i  8; i++)

{

SCL = 1;                //SCL置为高电平

x=1;                  //将x中的各二进位向左移一位

x|=(unsigned char)SDA;  //将SDA上的数据通过按位“或“运算存入x中

SCL = 0;                        //在SCL的下降沿读出数据

}

return(x);                //将读取的数据返回

}

/*************************************************************

函数名称:WriteCurrent

函数功能:向AT24Cxx的当前地址写入数据,在调用此数据写入函数前需首先调用开始函数start(),所以SCL=0

入口参数:y--储存待写入的数据

返回值  :WriteCurrent()

*************************************************************/

bit WriteCurrent(unsigned char y)

{

unsigned char i;

bit ack_bit;               //储存应答位

for(i = 0; i  8; i++)// 循环移入8个位

{

  SDA = (bit)(y0x80);   //通过按位“与”运算将最高位数据送到S

                                //因为传送时高位在前,低位在后

_nop_();            //等待一个机器周期 

 SCL = 1;            //在SCL的上升沿将数据写入AT24Cxx     

 _nop_();            //等待一个机器周期

_nop_();             //等待一个机器周期     

SCL = 0;            //将SCL重新置为低电平,以在SCL线形成传送数据所需的8个脉冲

y = 1;           //将y中的各二进位向左移一位

}

SDA = 1;  // 发送设备(主机)应在时钟脉冲的高电平期间(SCL=1)释放SDA线,

              //以让SDA线转由接收设备(AT24Cxx)控制

_nop_();        //等待一个机器周期

_nop_();        //等待一个机器周期

SCL = 1;       //根据上述规定,SCL应为高电平

_nop_();       //等待一个机器周期

_nop_();       //等待一个机器周期

_nop_();       //等待一个机器周期

_nop_();       //等待一个机器周期

ack_bit = SDA; //接受设备(AT24Cxx)向SDA送低电平,表示已经接收到一个字节

             //若送高电平,表示没有接收到,传送异常

SCL = 0;       //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递)

return  ack_bit;// 返回AT24Cxx应答位

}

/***************************************************

函数名称:WriteSet

函数功能:向AT24Cxx中的指定地址写入数据

入口参数:add (储存指定的地址);dat(储存待写入的数据)

返回  值:无

***************************************************/

void WriteSet(unsigned char add, unsigned char dat)

// 在指定地址addr处写入数据WriteCurrent

{

start();               //开始数据传递

WriteCurrent(OP_WRITE);  //选择要操作的AT24Cxx芯片,并告知要对其写入数据

WriteCurrent(add);       //写入指定地址

WriteCurrent(dat);       //向当前地址(上面指定的地址)写入数据

stop();                //停止数据传递

delayNms(4);       //1个字节的写入周期为1ms, 最好延时1ms以上

}

/***************************************************

函数名称:ReadCurrent

函数功能:从AT24Cxx中的当前地址读取数据

入口参数:无

出口参数:x (储存读出的数据)

***************************************************/

unsigned char ReadCurrent( void )

{

unsigned char x;

start();               //开始数据传递

WriteCurrent(OP_READ);   //选择要操作的AT24Cxx芯片,并告知要读其数据

x=ReadData();         //将读取的数据存入x

stop();                //停止数据传递

return x;              //返回读取的数据

}

/***************************************************

函数名称:ReadSet

函数功能:从AT24Cxx中的指定地址读取数据

入口参数:set_addr

出口参数:x

***************************************************/

unsigned char ReadSet(unsigned char set_addr)

// 在指定地址读取

{

start();                      //开始数据传递

WriteCurrent(OP_WRITE);       //选择要操作的AT24Cxx芯片,并告知要对其写入数据

WriteCurrent(set_addr);       //写入指定地址

return(ReadCurrent());        //从指定地址读出数据并返回

}

#endif

怎么调用?这样   WriteSet( 地址 ,数据);

单片机中,用c语言对at24c02进行操作时,判断应答信号是否有效时,有效则return(0),返回0有什么用?

#ifndef __AT24C02_H__

#define __AT24C02_H__

#includestc89.h //包含单片机寄存器的头文件

#includeintrins.h //包含NOP空指令的头文件

#define uchar unsigned char

#define uint unsigned int

/*宏定义器件地址*/ //AT24C器件ID 1 0 1 0 A2 A1 A0 RW

#define AT24_ID0 0XA0 //AT24C器件ID 1 0 1 0 0 0 0 RW

#define AT24_ID1 0XA2 //AT24C器件ID 1 0 1 0 0 0 1 RW

#define AT24_ID2 0XA4 //AT24C器件ID 1 0 1 0 0 1 0 RW

#define AT24_ID3 0XA6 //AT24C器件ID 1 0 1 0 0 1 1 RW

#define AT24_ID4 0XA8 //AT24C器件ID 1 0 1 0 1 0 0 RW

#define AT24_ID5 0XAA //AT24C器件ID 1 0 1 0 1 0 1 RW

#define AT24_ID6 0XAE //AT24C器件ID 1 0 1 0 1 1 1 RW

/*其他参数*/

#define AT24_INQ 255 //器件应答最大检测次数 超过此数量 无应答也会退出循环 以避免程序死循环

/*I2C总线驱动IO口*/

sbit I2C_SCL=P1^5;//串行时钟输入。SCL同步数据传输,上升沿数据写入,下降沿数据读出

sbit I2C_SDA=P3^6;//穿行地址和数据输入/输出。SDA是双向串行数据传输引脚,漏极开路,需外接上拉电阻到VCC(典型值10K)

/*最终使用的函数*/

void at24cxx_weite(uchar I2C_IDRW,I2C_ADDRESS,I2C_DATA);//写入AT24 I2C_IDRW器件地址 I2C_ADDRESS数据地址 I2C_DATA数据

uchar at24cxx_read(uchar I2C_IDRW,I2C_ADDRESS) ; //带地址的读取AT24 I2C_IDRW器件地址 I2C_ADDRESS数据地址

/*被调用的子函数*/

uchar at24cxx_rd(I2C_IDRD); //当前地址读取AT24 由 读取函数调用 I2C_IDRD 为器件地址

void at24cxx_com(uchar I2C_DATA); //AT24写公用函数 由写入读取函数调用 I2C_DATA 为要写入的变量(器件ID,数据地址,数据)

void at24cxx_start(); //AT24起始信号 由写入读取函数调用

void at24cxx_stop(); //AT24停止信号 由写入读取函数调用

void at24cxx_inquires(uchar I2C_IDRW);//AT24应答检测 由写入读取函数调用

void at24cxx_response(); //I2C总线应答检测 由写入读取函数调用

void at24cxx_ricom(); //器件应答与总线应答检测 公用函数 由器件应答和总线应答函数调用

/*字节写操作 起始条件 器件地址 写 字地址 数据停止条件*/

void at24cxx_weite(uchar I2C_IDRW,I2C_ADDRESS,I2C_DATA)//写入AT24I2C_IDRW器件地址 I2C_ADDRESS数据地址 I2C_DATA数据

{

//at24cxx_start(); //起始条件 开始写入数据

//at24cxx_com(I2C_IDRW0xfe); //写入芯片ID及读写选择位 0

//at24cxx_response(); //总线应答

at24cxx_inquires(I2C_IDRW0xfe);//器件应答检测 并写入器件ID以及读写选项 内部有起始条件

at24cxx_com(I2C_ADDRESS); //写入数据地址

at24cxx_response(); //总线应答

at24cxx_com(I2C_DATA); //写入数据

at24cxx_response(); //总线应答

at24cxx_stop(); //结束条件 终止写入数据

}

/*函数流程 起始条件 器件地址 写 字地址 起始条件 器件地址 读 读数据 停止条件*/

uchar at24cxx_read(uchar I2C_IDRW,I2C_ADDRESS) //带地址的读取AT24 I2C_IDRW器件地址 I2C_ADDRESS数据地址

{ uchar I2C_DATA; //最终读取的数据

//at24cxx_start(); //起始条件 开始写入数据

//at24cxx_com(I2C_IDRW0xfe); //写入芯片ID及读写选择位 0

//at24cxx_response(); //总线应答

at24cxx_inquires(I2C_IDRW0xfe); //器件应答检测 并写入器件ID以及读写选项 内部有起始条件

at24cxx_com(I2C_ADDRESS); //写入数据地址

at24cxx_response(); //总线应答

I2C_DATA=at24cxx_rd(I2C_IDRW|0x01);//写入芯片ID及读写选择位 1 程序内部有起始停止功能

return(I2C_DATA); //返回数据

}

/*起始条件 器件地址 读 数据 停止条件*/

/*当前地址读 起始条件 器件地址 读 数据 停止条件*/

/*接收器件地址(读/写选择为为1)、EEPROM应答ACK后,当前地址的数据就随时钟送出主器件无需应答0,但需要发送停止条件*/

uchar at24cxx_rd(I2C_IDRD) //当前地址读取AT24 I2C_IDRD为器件地址

{ uchar I2C_NUM,I2C_DAT; //定义8位变量用来做循环移位读取数据

at24cxx_start(); //起始条件

at24cxx_com(I2C_IDRD|0x01); //写入芯片ID及读写选择位 1

at24cxx_response(); //总线应答

for(I2C_NUM=0;I2C_NUM8;I2C_NUM++)

{ I2C_DAT=I2C_DAT1; //数据左移位

I2C_SCL=1; //拉高时钟线得到 要读的数据

_nop_(); //一个机器周期指令

if(I2C_SDA==1) //判断数据为1

{I2C_DAT=I2C_DAT|0X01;} //将数据变量赋值

I2C_SCL=0; //拉低时钟线 以获得新数据

nop_(); //一个机器周期指令

}

at24cxx_stop(); //结束条件 终止接收数据

return(I2C_DAT); //返回数据

}

/*由读写函数调用 目的:节省空间*/

void at24cxx_com(uchar I2C_DATA) //AT24写公用函数

{ uchar I2C_NUM,I2C_DAT; //定义8位变量用来做循环写入位

for(I2C_NUM=0;I2C_NUM8;I2C_NUM++)

{

I2C_DAT=(I2C_DATA7);//获得数据最高位

I2C_DAT=I2C_DAT0X01; //取数据的最高位数据

I2C_SCL=0; //拉低时钟线数据传输开始

_nop_(); //一个机器周期指令

I2C_SDA=I2C_DAT; //I2C数据线赋值

_nop_(); //一个机器周期指令

I2C_SCL=1; //拉高时钟线数据存储

_nop_(); //一个机器周期指令

I2C_DATA=I2C_DATA1; //数据移位

}

}

/*当SCL为高电平时SDA的下降沿(高到低)叫做起始条件(START)起始条件保持时间 最小值1.8V 0.6US:5V 0.25US 起始条件建立时间1.8V 0.6US:5V 0.25US */

void at24cxx_start()//AT24起始信号

{

I2C_SCL=1; //空闲总线

_nop_(); //一个机器周期指令

I2C_SDA=1; //空闲总线

_nop_(); //一个机器周期指令

I2C_SDA=0; //拉低数据线 发起起始信号

_nop_(); //一个机器周期指令

}

/*SDA的上升沿(低到高)叫做停止条件(STOP) 停止条件建立时间 最小值1.8V 0.6US:5V 0.25US */

void at24cxx_stop() //AT24停止信号

{

I2C_SDA=0; //拉低数据线 以便形成上升沿

_nop_(); //一个机器周期指令

I2C_SCL=1; //

_nop_(); //一个机器周期指令

I2C_SDA=1; //老高数据线 发起停止信号

_nop_(); //一个机器周期指令

}

/*一旦内部写周期启动,EEPROM输入无效,此时即可启动应答查询:发送起始条件和器件地址(读/写位为期望的操作)。

只有内部写周期完成EEPROM才会应答“0”。之后可继续读/写操作

应答查询流程:1.发送写命令 2.发送停止条件启动写周期 3.发送起始条件 4.发送控制字节R/W=0 5.器件是否应答(ACK=0)? 是 5.下一操作 否 重复2-4操作

*/

void at24cxx_inquires(uchar I2C_IDRW)//AT24应答查询

{ uchar AT24_NUM; //定义变量用来跳出循环应答检测

AT24_NUM=AT24_INQ; //赋值应答最大检测次数 避免无应答时程序死循环

while(AT24_NUM--) //循环判断应答

{ at24cxx_start(); //发送起始条件

at24cxx_com(I2C_IDRW); //写入芯片ID及读写选择位

at24cxx_ricom(); //调用应答公用检测函数

if(I2C_SDA==0) //应答成功

{break;} //退出循环

}

I2C_SCL=0; //应答结束拉低时钟线

_nop_(); //一个机器周期指令

I2C_SDA=1; //应答结束把数据线重新拉高

_nop_(); //一个机器周期指令

}

/*接收器拉低SDA线表示应答,应在应答脉冲器件保持稳定的低电平。当主器件做接收器时,必须发出数据传输结束的信号给发送器,

即它在最后一个字节之后的应答脉冲期间不会产生应噶信号(不拉低SDA)。这种情况下,发送器必须释放SDA线为高以便主器件产生停止条件*/

void at24cxx_response()//总线应答

{

at24cxx_ricom(); //调用应答公用检测函数

I2C_SCL=0; //应答结束拉低时钟线

_nop_(); //一个机器周期指令

I2C_SDA=1; //应答结束把数据线重新拉高

_nop_(); //一个机器周期指令

}

/*器件应答与总线应答公用函数 由于这部分代码相同 所以写成一个函数 以节省空间*/

void at24cxx_ricom() //器件应答与总线应答检测 公用函数

{

uchar AT24_NUM; //定义变量 用来无应答时跳出循环判断应答

I2C_SCL=0; //总线应答额外脉冲

_nop_(); //一个机器周期指令

I2C_SDA=1; //拉高数据线 以检测应答

_nop_(); //一个机器周期指令

I2C_SCL=1; //应答时钟脉冲

_nop_(); //一个机器周期指令

while(I2C_SDA) //判断应答

{

if(AT24_NUM255)//判断累加 总线应答检测最大时间(次数) 避免无应答时程序死循环

{AT24_NUM++;} //没有到则自+

else //否则

{break;} //退出循环判断应答

}

}

单片机读写AT24CXX的介绍就聊到这里吧,感谢您花时间阅读,谢谢。

本文标签:单片机读写AT24CXX

<