AT24C02写一个数据然后读取一个数据是正确的,但是当写入多个数据时,读出数据就不正确,求指教

AT24C02写一个数据然后读取一个数据是正确的,但是当写入多个数据时,读出数据就不正确,求指教,第1张

恩,这个问题困扰了两天,终于找到原因并且顺利解决了!原因是:单片机接收应答信号(向AT24C02写数据时)和发送应答信号(AT24C02向单片机发送数据)的代码是不一样的!

void ack()//acknowledge (单片机接收应答信号)

{

uchar i;

scl=1;

delay();

while((sda == 1)&&(i > 250))

i++;

scl=0;//注意此处,此处表示第九个时钟结束,不能不写

delay();

}

void ack2(bit response)//(单片机发送的应答信号,response=1时是非应答,response=0时是应答!)

{

sda=response;

scl=1;

delay();

scl=0;

delay();

}

//然后严格遵循datasheet的 *** 作时序

//读数据的代码是这样的()

void read_add(uchar address)

{

start();

write_byte(0xa0);

ack();

write_byte(address);

ack();//dummy write

start();

write_byte(0xa1);

ack();

P1=read_byte();

ack2(0);//这个应答才正确

// ack();这个应答不正确

P1=read_byte();

ack2(1);

delay();

stop();

}

//这里注意,我用郭天祥老师的TX-1C,给P1口赋值让lcd灯来检验我的应答信号是否正确

#ifndef __AT24C02_H__

#define __AT24C02_H__

#include<stc89h> //包含单片机寄存器的头文件

#include<intrinsh> //包含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_IDRW&0xfe); //写入芯片ID及读写选择位 0

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

at24cxx_inquires(I2C_IDRW&0xfe);//器件应答检测 并写入器件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_IDRW&0xfe); //写入芯片ID及读写选择位 0

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

at24cxx_inquires(I2C_IDRW&0xfe); //器件应答检测 并写入器件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_NUM<8;I2C_NUM++)

{ I2C_DAT=I2C_DAT<<1; //数据左移位

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_NUM<8;I2C_NUM++)

{

I2C_DAT=(I2C_DATA>>7);//获得数据最高位

I2C_DAT=I2C_DAT&0X01; //取数据的最高位数据

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

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

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

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

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

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

I2C_DATA=I2C_DATA<<1; //数据移位

}

}

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

void at24cxx_start()//AT24起始信号

{

I2C_SCL=1; //空闲总线

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

I2C_SDA=1; //空闲总线

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

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

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

}

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

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_NUM<255)//判断累加 总线应答检测最大时间(次数) 避免无应答时程序死循环

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

else //否则

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

}

}

以上就是关于AT24C02写一个数据然后读取一个数据是正确的,但是当写入多个数据时,读出数据就不正确,求指教全部的内容,包括:AT24C02写一个数据然后读取一个数据是正确的,但是当写入多个数据时,读出数据就不正确,求指教、单片机中,用c语言对at24c02进行 *** 作时,判断应答信号是否有效时,有效则return(0),返回0有什么用、等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zz/9292558.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-26
下一篇2023-04-26

发表评论

登录后才能评论

评论列表(0条)

    保存