AT24C02EEPROM读写程序
- 格式:doc
- 大小:31.00 KB
- 文档页数:5
24c02读写程序大全2C总线的应用(24C02子程序)// 对24C02的读、写// extern void DelayMs(unsigned int);// extern void Read24c02(unsigned char *RamAddress,unsigned char Ro mAddress,unsigned char bytes);// extern void Write24c02(unsigned char *RamAddress,unsigned char Ro mAddress,unsigned char bytes);/***************************************************************************/#define WriteDeviceAddress 0xa0#define ReadDviceAddress 0xa1#include <reg52.h>#include <stdio.h>#include <absacc.h>/***************************************************************************/sbit SCL=P2^7;sbit SDA=P2^6;bit DOG;/***************************************************************************/void DelayMs(unsigned int number) {unsigned char temp;for(;number!=0;number--,DOG=!DOG) {for(temp=112;temp!=0;temp--) {}}}/***************************************************************************/void Start() {SDA=1;SCL=1;SDA=0;SCL=0;}/***************************************************************************/void Stop() {SCL=0;SDA=0;SDA=1;}/***************************************************************************/void Ack() {SDA=0;SCL=1;SCL=0;SDA=1;}/***************************************************************************/void NoAck() {SDA=1;SCL=1;SCL=0;}/***************************************************************************/bit TestAck() {bit ErrorBit;SDA=1;SCL=1;ErrorBit=SDA;SCL=0;return(ErrorBit);}/***************************************************************************/void Write8Bit(unsigned char input) {unsigned char temp;for(temp=8;temp!=0;temp--) {SDA=(bit)(input&0x80);SCL=1;SCL=0;input=input<<1;}}/***************************************************************************/void Write24c02(unsigned char *Wdata,unsigned char RomAddress,unsign ed char number) {Write8Bit(WriteDeviceAddress);TestAck();Write8Bit(RomAddress);TestAck();for(;number!=0;number--) {Write8Bit(*Wdata);TestAck();Wdata++;}Stop();DelayMs(10);}/***************************************************************************/ unsigned char Read8Bit() {unsigned char temp,rbyte=0;for(temp=8;temp!=0;temp--) {SCL=1;rbyte=rbyte<<1;rbyte=rbyte|((unsigned char)(SDA));SCL=0;}return(rbyte);}/***************************************************************************/void Read24c02(unsigned char *RamAddress,unsigned char RomAddress, unsigned char bytes) {//unsigned char temp,rbyte;Start();Write8Bit(WriteDeviceAddress);TestAck();Write8Bit(RomAddress);TestAck();Start();Write8Bit(ReadDviceAddress);TestAck();while(bytes!=1) {*RamAddress=Read8Bit();RamAddress++;bytes--;}*RamAddress=Read8Bit();NoAck();Stop();}[单片机应用]24c02的读写程序电子工匠发表于2007-1-4 22:33:07;---------------从24C02整组读数据RD_INI: LCALL DELAYRD_AREA: LCALL DELAYLCALL STARTLCALL DELAYLCALL WRITE ;24C02信息的读入LCALL DELAYLCALL ACKLCALL DELAYJC RD_AREAMOV R2, #8CLR P1.7 ;起始地址为00 ADDR_0: LCALL DELAYLCALL DELAYSETB P1.6LCALL DELAYLCALL DELAYCLR P1.6LCALL DELAYDJNZ R2, ADDR_0LCALL ACKLCALL DELAYJC RD_AREALCALL DELAYLCALL STARTMOV R0, #SAVE0MOV R3, #8 ;6个字节LCALL DELAYLCALL READLCALL DELAYLCALL ACKJC RD_AREARD_R_0: LCALL DELAYLCALL DELAYLCALL RD_INFOLCALL DELAYINC R0DJNZ R3, RD_R_1lcall ack_2lcall delayLCALL STOPRETrd_r_1: lcall ack_1sjmp rd_r_0;---------------向24C02整组写数据WR_INI: LCALL DELAYLCALL STARTLCALL DELAYLCALL WRITELCALL DELAYLCALL ACKLCALL DELAYJC WR_INICLR P1.7MOV R2, #8WR_W_0: LCALL DELAY ;写地址SETB P1.6LCALL DELAYLCALL DELAYCLR P1.6LCALL DELAYDJNZ R2, WR_W_0LCALL DELAYLCALL ACKLCALL DELAYJC WR_INIMOV R0, #SAVE0MOV R3, #8 ;6个字节WR_W_1: LCALL WR_INFOLCALL DELAYLCALL ACKLCALL DELAYJC WR_INIINC R0DJNZ R3, WR_W_1LCALL DELAYLCALL STOPRET;---------------24C02启动START: SETB P1.7SETB P1.6LCALL DELAYCLR P1.7LCALL DELAYCLR P1.6RET;---------------24C02读命令字;片选为"00";---------------------------- READ: MOV A, #10100001B MOV R2, #8RD1: RLC AMOV P1.7, CSETB P1.6LCALL DELAYCLR P1.6LCALL DELAYDJNZ R2, RD1RET;---------------24C02写命令字;片选为"00";---------------------------- WRITE: MOV A, #10100000B MOV R2, #8WR1: RLC AMOV P1.7, CSETB P1.6LCALL DELAYCLR P1.6CLR P1.7LCALL DELAYDJNZ R2, WR1RET;---------------24C02结束命令字STOP: CLR P1.7LCALL DELAYSETB P1.6LCALL DELAYSETB P1.7LCALL DELAYCLR P1.6RET;---------------24C02的应答信息ACK: SETB P1.7SETB P1.6LCALL DELAYmov a, p1MOV C, a.7LCALL DELAYCLR P1.6RETack_1: CLR P1.7 ;应答SETB P1.6lcall delayCLR P1.6lcall delaySETB P1.7lcall delayRETack_2: SETB P1.7 ;非应答SETB P1.6lcall delayCLR P1.6CLR P1.7lcall delayRET;---------------24C02的读;R0:数据的存储地址;-------------------------------- RD_INFO: SETB P1.7LCALL DELAYMOV R2, #8MOV R7, #0MOV A, #0RD_I_0: SETB P1.6LCALL DELAYMOV A, P1MOV C, A.7LCALL DELAYCLR P1.6MOV A, R7RLC AMOV R7, ALCALL DELAYDJNZ R2, RD_I_0MOV @R0, ARET;---------------24C02的写;R0:数据的写数据地址;-----------------------------------WR_INFO: MOV A, @R0MOV R2, #8WR_O_0: RLC AMOV P1.7, CLCALL DELAYSETB P1.6LCALL DELAYLCALL DELAYCLR P1.6LCALL DELAYDJNZ R2, WR_O_0RET24Cxx I2C EEPROM字节读写驱动程序,芯片A0-A1-A2要接GND(24C65接VCC,具体看DataSheet)。
C51_AT24C02读写程序:/*void start() //开始信号void stop() //停止信号void Ack() //发确认信号void NoAck() //发无确认信号void init()//初始化信号,拉高SDA和SCL两条总线bit write_byte(uchar date)//写一字节,将date 写入AT24C02 中uchar read_byte()//读一字节,从AT24C02 中读一字节bit busy() //应答查询,stop()后,启动A T24C02内部写周期,启动查询//初始化EEPROM子程序内容为0XFF,nPage(0~31)void Init_Flash(uchar nPage) //8 bytes/1 page init 0xFFvoid write_add(uchar address,uchar date)//向AT24C02 中写数据//从AT24C02中给定的地址nAddr起,将存放在以指针nContent开头的存储空间中的nLen 个字节数据,连续写入AT24C02void write_flash(uchar *nContent,uchar nAddr, uchar nLen)uchar read_add(uchar address)//从AT24C02 中读出数据//从AT24C02中给定的地址nAddr起,读取nLen个字节数据存放在以指针nContent开头的存储空间。
void read_flash(uchar *nContent,uchar nAddr, uchar nLen)*//*单片机P2口接74HC138(三八译码器)P2.3--74HC138:/EI、P2.2--74HC138:A2、P2.1--74HC138:A1、P2.0--74HC138:A0译码器输出Y0,Y1、Y2、Y3、Y4、Y5、Y6、Y7均低电平有效,分别选通1~8个数码管。
AT24C02串行E2PROM的工作原理与读写串行EEPROM中,较为典型的有ATMEL公司的AT24CXX系列和AT93CXX等系列产品。
简称I2C总线式串行器件。
串行器件不仅占用很少的资源和I/O线,而且体积大大缩小,同时具有工作电源宽、抗干扰能力强、功耗低、数据不易丢失和支持在线编程等特点。
I2C总线是一种用于IC器件之间连接的二线制总线。
它通过SDA(串行数据线)及SCL (串行时钟线)两根线在连到总线上的器件之间传送信息,并根据地址识别每个器件:不管是单片机、存储器、LCD驱动器还是键盘接口。
1.I2C总线的基本结构:采用I2C总线标准的单片机或IC器件,其内部不仅有I2C接口电路,而且将内部各单元电路按功能划分为若干相对独立的模块,通过软件寻址实现片选,减少了器件片选线的连接。
CPU不仅能通过指令将某个功能单元电路挂靠或摘离总线,还可对该单元的工作状况进行检测,从而实现对硬件系统的既简单又灵活的扩展与控制。
I2C总线接口电路结构如图1所示。
从图中可以看出:对于时钟及数据传送,串行数据I/O端SDA一般需要用外部上拉电阻将其电平拉高。
2.双向传输的接口特性:传统的单片机串行接口的发送和接收一般都分别用一条线,如MCS51系列的TXD和RXD,而I2C总线则根据器件的功能通过软件程序使其可工作于发送或接收方式。
当某个器件向总线上发送信息时,它就是发送器(也叫主器件),而当其从总线上接收信息时,又成为接收器(也叫从器件)。
主器件用于启动总线上传送数据并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件。
I2C总线的控制完全由挂接在总线上的主器件送出的地址和数据决定。
总线上主和从(即发送和接收)的关系不是一成不变的,而是取决于此时数据传送的方向。
SDA和SCL均为双向I/O线,通过上拉电阻接正电源。
当总线空闲时,两根线都是高电平。
连接总线的器件的输出级必须是集电极或漏极开路,以具有线“与”功能。
E2PROM芯片24C02的读写程序一、实验目的:给24C02的内部RAM写入一组数据,数据从24C02内部RAM的01h开始存放。
然后再把这组数据读出来,检验写入和读出是否正确。
在这里我们给24C02中写入0、1、2的段码,然后把它读出来,送到数码管显示。
二、理论知识准备:上面两个实验主要学习的是利用单片机的串口进行通讯,本实验要介绍的是基于I2C总线的串行通讯方法,下面我们先介绍一下I2C总线的相关理论知识。
(一)、I2C总线概念I2C总线是一种双向二线制总线,它的结构简单,可靠性和抗干扰性能好。
目前很多公司都推出了基于I2C总线的外围器件,例如我们学习板上的24C02芯片,就是一个带有I2C总线接口的E2PROM存储器,具有掉电记忆的功能,方便进行数据的长期保存。
(二)、I2C总线结构I2C总线结构很简单,只有两条线,包括一条数据线(SDA)和一条串行时钟线(SCL)。
具有I2C接口的器件可以通过这两根线接到总线上,进行相互之间的信息传递。
连接到总线的器件具有不同的地址,CPU根据不同的地址进行识别,从而实现对硬件系统简单灵活的控制。
一个典型的I2C总线应用系统的组成结构如下图所示(假设图中的微控制器、LCD驱动、E2PROM、ADC各器件都是具有I2C总线接口的器件):我们知道单片机串行通讯的发送和接收一般都各用一条线TXD和RXD,而I2C总线的数据线既可以发送也可以接受,工作方式可以通过软件设置。
所以,I2C总线结构的硬件结构非常简洁。
当某器件向总线上发送信息时,它就是发送器,而当其从总线上接收信息时,又成为接收器。
(三)、I2C总线上的数据传送下面我们看看I2C总线是如何进行数据传送的。
我们知道,在一根数据线上传送数据时必须一位一位的进行,所以我们首先研究位传送。
1、位传输I2C总线每传送一位数据必须有一个时钟脉冲。
被传送的数据在时钟SCL的高电平期间保持稳定,只有在SCL低电平期间才能够改变,示意图如下图所示,在标准模式下,高低电平宽度必须不小于4.7us。
按下4×4键盘任意一个键,记下数码管显示的值。
复位单片机后数码管显示刚才显示的值学习IIC接口的EEPROM读写:IIC接口的时序比较复杂,对初学者难度较大,要对照at24c02资料的时序图认真研究才明白*/#include<reg51.h>sbit speaker=P3^7;sbit led_k=P1^4;/////////////////键盘sbit v1=P2^0;sbit v2=P2^1;sbit v3=P2^2;sbit v4=P2^3;sbit h1=P2^4;sbit h2=P2^5;sbit h3=P2^6;sbit h4=P2^7;/////////////////显示sbit shu1=P1^3;/*第1位数码管共阴端*/sbit shu2=P1^2;/*第2位数码管共阴端*/sbit shu3=P1^1;/*第3位数码管共阴端*/sbit shu4=P1^0;/*第4位数码管共阴端*/////////////////24c02sbit sda=P1^6;sbit scl=P1^5;void start();void delay1();unsigned int read(unsigned int word_address);void write(unsigned int word_address,da);void delayms(unsigned int i);unsigned char yima[]={0xeb,0x88,0xb3,0xba,0xd8,0x7a,0x7b,0xa8,0xfb,0xfa};/*译码表,此表数据和硬件相关*/unsigned int b=0;/*要显示的数据*/unsigned int b_count=0;/*扫描次数*/void delayms(unsigned int i);unsigned char keyboar();void t0()interrupt 1 using 1 /*中断程序负责显示b的值*/{unsigned char a1=0,a2=0,a3=0,a4=0;static int k=0;/*数码管扫描显示*/a1=b/1000;/*取b的千位*/a2=b%1000/100;/*取b的百位*/a3=b%100/10;/*取b的十位*/a4=b%10;/*取b的个位*/if(k==0){shu4=1;shu1=0;shu2=0;shu3=0;P0=yima[a1];}else if(k==1){shu4=0;shu1=1;shu2=0;shu3=0;P0=yima[a4];}else if(k==2){shu4=0;shu1=0;shu2=1;shu3=0;P0=yima[a3];}else if(k==3){shu4=0;shu1=0;shu2=0;shu3=1;P0=yima[a2];}k++;if(k>3)k=0;TH0=240;}main(){//write(1,60);unsigned char b_tem;b=read(1); //读取eeprom地址为1的数据并赋值给b,定时中断程序把b显示在数码管speaker=0;/*关闭蜂鸣器电源,否则蜂鸣器会发热*/led_k=0;//关闭ledEA=1;/*开全局中断*/TR0=1;/*定时器0开始计数*/ET0=1;/*定时器0开中断*/TMOD=0X01;/*定时器0工作在方式1:16位计数模式*/while(0){}while(1){b_tem=keyboar();/*把按键的代表的值给b */if(b_tem<17){if(b!=b_tem) //当按下的按键与上次按下的不同时,执行写EERPOM。
/*EEPROM24C02,程序将对存储器进行读和写,因此涉及到键盘程序,比较复杂,耐心学,例子读取24C02内部数据,在数码管上显示,可通过按键来进行不同地址数据的读取和保存*/#include <reg51.h>#include <intrins.h>#define W24C02 0xA0 //存储器的写地址#define R24C02 0xA1 //存储器的读地址#define MSB 0x80 //8位二进制最高位置1#define LSB 0x01 //8位二进制最低位置1/********************/sbit SDA=P3^6; //A T24C02串行数据5脚sbit SCL=P3^7; //A T24C02串行时钟6脚sbit SPK=P3^4; //蜂鸣器,按键用时蜂鸣void I2C_write(unsigned char tmp); //向I2C总线写数据unsigned char I2C_read(); //向I2C总线读数据void I2C_ACK(bit tmp); //ACK应答void I2C_start(void); //I2C传送数据的开始void I2C_stop(void); //I2C传送数据的结束void _24c02menu(void); //当我们按下按键进入处理I2C数据时用的函数void _24c02wdate(unsigned char tmp); //当我们对24C02存储器进行写数据用到的函数void display(unsigned char *lp,unsigned char lc);//显示,在键盘程序里用过void displaystr(unsigned char *lp,unsigned char lc);//字符的显示函数,同上void delay();//延时子函数void ReadKey(void); //扫描键盘获取键值unsigned char l_key=0xFF; //定义变量,存放键值unsigned char l_keyold=0; //做为按键松开否的凭证code unsigned char l_24C02[5]={0x5b,0x66,0x39,0x3f,0x5b};//定义数组常量在数码管上显示24C02unsigned char l_address=0; //读24C02的地址变量unsigned char l_tmpdate[6]={0,0,0x10,0,0,0}; //数组变量code unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40};//共阴数码管0-9 a-f - 表code unsigned char key_tab[17]={0xed,0x7e,0x7d,0x7b,0xbe,0xbd,0xbb,0xde,0xdd,0xdb,0x77,0xb7,0xee,0xd7,0xeb,0xe7,0XFF};//========================此数组为键盘编码,// 1 2 3 a// 4 5 6 b// 7 8 9 e// * 0 # fvoid main(void) //入口函数{TMOD=0x01; //设置定时器0为模式1方式,TH0=0XD1; //设置初值,为12毫秒TL0=0X20;EA=1; //开启总中断ET0=1; //开启定时器中断0EX0=1; //开启外部中断0IT0=1; // 设置成下降沿触发方式P0=0xf0; //while(1){displaystr(l_24C02,5); //用这个函数显示5个字符if(l_key==0x0e){l_key=0xff; //按下#键调用_24c02menu(); //此函数}}}//以下一部份在键盘程序里有说明,此处不在讲述void key_scan() interrupt 0 //外部中断0 0的优先级最高{EX0=0;TH0=0XD1;TL0=0X20;TR0=1;}void timer0_isr(void) interrupt 1 //定时器0的中断函数{TR0=0;ReadKey();}void ReadKey(void){unsigned char i,j,key;j=0xfe;key=0xff;for (i=0;i<4;i++){P0=j;if ((P0&0xf0)!=0xf0){key=P0;break;}j=_crol_(j,1);}if (key==0xff){l_keyold=0xff;P0=0xf0;SPK=1;EX0=1;return;}else{TH0=0X2E;TL0=0X20;TR0=1;SPK=0;}if(l_keyold!=key){l_keyold=key;for(i=0;i<17;i++){if (key==key_tab[i]){l_key=i;break;}}}}void display(unsigned char *lp,unsigned char lc)//显示{unsigned char i;P2=0;P1=P1&0xF8;for(i=0;i<lc;i++){P2=table[lp[i]];P2=0;if(i==7)break;P1++;}}void displaystr(unsigned char *lp,unsigned char lc)//显示{unsigned char i;P2=0;P1=P1&0xF8;for(i=0;i<lc;i++){P2=lp[i];delay();P2=0;if(i==7)break;P1++;}}void delay(void) //{unsigned char i=10;while(i)i--;}void _24c02menu(void) //处理I2C数据时用的函数{unsigned char tmp,tmp2;P2=0; //数码管显示清0l_key=0xfe; //进入存储器处理程序先读取0地址的数据while (1){if(l_key==0x0c){ //如果按下*号键退出循环,即退出回到主函数l_key=0xff;break;}switch(l_key){ //扫描键盘做相应处理case 0x0a: //按下0X0A键,我们可将它理解为上翻键l_key=0xff;if(l_address>0){l_address--; //将地址减1l_key=0xfe; //读取数据break;case 0x0b: //按下0X0A键,我们可将它理解为下翻键l_key=0xff;if(l_address<255){l_address++; //将地址加1l_key=0xfe; ////读取数据}break;case 0x0e: //如果按下#号键,调用写存储器函数l_key=0xff;_24c02wdate(tmp);l_key=0xfe;break;case 0xfe: //此按值是在键盘是没有的,我们有内部给他增加做为读数据处理l_key=0xff;I2C_start(); //I2C读数据的开始,到下面的结束是读一地址的整个过程,I2C_write(W24C02); //向I2C总线发出读取24C02的地址I2C_ACK(0); //下面就得你们自己结合I2C串口协议进行,先看看24C02数据手册是怎么讲I2C协议的I2C_write(l_address);//先写入地址,I2C_ACK(1);I2C_stop();I2C_start(); //再开始读取数据I2C_write(R24C02);I2C_ACK(0);tmp=I2C_read();I2C_ACK(1);I2C_stop(); //读取一个地址的数据结束l_tmpdate[0]=l_address/16; //数码管前两位显示地址(以16进制显示)l_tmpdate[1]=l_address%16; //将地址变量分开用两位数据l_tmpdate[3]=tmp/100; //后面用10进制数显示数据,中间用"-"隔开,数组l_tmpdate[2]tmp2=tmp%100; //8位二进制最大十进制为255,所以我们也将它分开三位显示l_tmpdate[4]=tmp2/10;l_tmpdate[5]=tmp2%10;break;}display(l_tmpdate,6);}}void _24c02wdate(unsigned char tmp)//对24C02的写数据处理函数{unsigned char tmp2=0;while(1){if (l_key==0x0c){ //如果按下*号键退出循环,即退出回到上一极函数l_key=0xff;break;}if(l_key==0x0e){ //如果按下#号键,将更改的数据写入24C02存储器l_key=0xff;I2C_start(); //下面是写一地址数据的过程I2C_write(W24C02); //先向总线发出写24C02的地址I2C_ACK(0);I2C_write(l_address); //写入地址I2C_ACK(0);I2C_write(tmp); //然后写入数据I2C_ACK(1);I2C_stop();break;}switch(l_key){ //下面是对数据的处理case 0x01: //如果按下1键,数据百位加1l_key=0xff;if(tmp<155)tmp+=100;break;case 0x02: //如果按下2键,数据十位加1l_key=0xff;if(tmp<245)tmp+=10;break;case 0x03: //如果按下3键,数据个位加1l_key=0xff;if(tmp<255)tmp++;break;case 0x04: //如果按下4键,数据百位减1l_key=0xff;if(tmp>=100)tmp-=100;break;case 0x05: //如果按下5键,数据十位减1l_key=0xff;if(tmp>=10)tmp-=10;break;case 0x06: //如果按下6键,数据个位减1l_key=0xff;if(tmp>0)tmp--;break;}l_tmpdate[3]=tmp/100; //地址不变我们不用修改,更改数据显示即可tmp2=tmp%100;l_tmpdate[4]=tmp2/10;l_tmpdate[5]=tmp2%10;display(l_tmpdate,6);}}void I2C_write(unsigned char tmp)//I2C写入一个8位二进制数,高位在前低位在后{unsigned char i;for(i=0;i<8;i++){SCL=0;_nop_();_nop_();_nop_();SDA=(bit)(tmp&0x80);tmp<<=1;_nop_();_nop_();_nop_();_nop_();_nop_();SCL=1;_nop_();_nop_();_nop_();_nop_();_nop_();}SCL=0;}unsigned char I2C_read(void)////I2C读取一个8位二进制数,也是高位在前低位在后{unsigned char i,tmp;tmp=0;for(i=0;i<8;i++){SCL=0;_nop_();_nop_();_nop_(); //加入空指令增加稳定性,这关系到频率问题SDA=1;_nop_();_nop_();_nop_();_nop_();_nop_();SCL=1;_nop_();_nop_();_nop_();_nop_();_nop_();tmp<<=1;if(SDA==1)tmp++;}SCL=0;return tmp;}void I2C_ACK(bit tmp) //根据tmp的1、0来决定应答信号{SDA=tmp;_nop_();_nop_();_nop_();_nop_();_nop_();SCL=1;_nop_();_nop_();_nop_();_nop_();_nop_();SCL=0;}void I2C_start(void) //看看I2C开始的波形,再对应SDA、SCL的输出{SDA=1;_nop_();SCL=1;_nop_();SDA=0;_nop_();SCL=0;_nop_();}/*********/void I2C_stop(void) //I2C结束{SDA=0;_nop_();SCL=1;_nop_();SDA=1;_nop_();SCL=0;_nop_();}。
;--------------------------------------------------------------------------------------------------------------------- ;本程序是针对AT89S52单片机编制的EEPROM读写程序(2013.8.4测试通过);本程序在4MHZ、12MHZ和24MHZ分别测试通过;AT24C02的A0、A1、A2均接GND,设备地址高7位为(1010)000;WP接GND,充许对EEPROM正常读写;本程序仅作学习交流之用。
;--------------------------------------------------------------------------------------------------------------------- SCl equ P2.0 ;SCL接A T89S52的P2.0端口,作为EEPROM的串行输入时钟SDA equ P2.1 ;SDA接AT89S52的P2.1端口,作为主机与EEPROM之间信息串行传输总线WRITEDATA equ 08H;拟写入EEPROM的数据在主机中的存贮单元地址READDATA equ 09H ;从EEPROM读取的数据存放到主机存贮单元地址EPROMADDRESS equ 0AH;拟随机读写EEPROM的存贮单元地址;------------------------------------------------ORG 00HLJMP MAIN;------------------------------------------------ORG 50HMAIN: MOV SP,#20H;防止堆栈影响已用内存数据;以下为写EEPROM过程mov EPROMADDRESS,#09H;该地址可以随意输入(00H~FFH),但读和写的地址须相同MOV WRITEDA TA,#01010010B;该数字可以随意输入,并将读和写的数据进行比较;如读数正确则按将读出数据在P1口输出,可在P1口各位分别接LED灯直观显示出来。
LCALL WRITEEEPROMR;以下为读EEPROM过程mov EPROMADDRESS,#09H;该地址可以随意输入(00H~FFH),但读和写的地址须相同LCALL READEEPROMR;以下为EEPROM读写操作验证MOV A,WRITEdataMOV B,AMOV A,READDATACJNE A,B,MAIN1MOV P1,READDATA;写入数和读出数相等时,读出的数据在P1口输出并按位分别控制LED灯直观显示sJMP $MAIN1: MOV P1,#00H;写入数和读出数相等时,LED灯全亮;以下可接其它主程序,此处暂为死循环SJMP $;--------------------------------------------------------------------------------------------------------------------- ;WRITEEEPROMR是随机写EEPROM(AT24C02)子程序;入口1:EEPROMADRESS(拟读写EEPROM存贮单元地址,00~FFH);入口2:WRITEDATA(拟写入EEPROM的字节数据在主机的存放地址);--------------------------------------------------------------------------------------------------------------------- WRITEEEPROMR:;第1步,启动EEPROM读写操作lcall startEEPROM;调用启动子程序;第2步,输入设备号和功能选择码即10100000BMOV A,#10100000B;1010是规定的,000是设备地址,最低位0表示拟执行写操作LCALL SENDDA TA;调用串行发送字节数据子程序;第3步查询EEPROM应答信号情况LCALL WAITACK;调用应答响应子程序;第四步,传送数据拟贮存地址给EEPROM的地址指针MOV A,EPROMADDRESS;将拟贮存数据的EEPROM贮存单元地址送入SENDDATA子程序的入口ALCALL SENDDA TA;第五步,查询EEPROM应答信号情况LCALL WAITACK;调用应答响应子程序;第六步,传送8位数据到EEPROM缓存区,该循环完成第二个8时序(时序1~8)MOV A,writedataLCALL SENDDA TA;第七步,查询EEPROM应信号情况,完成第三个应答时序(时序9)LCALL WAITACK;调用应答响应子程序;第五步,主器件产生一个停止信号,即在scl高位时SDA由低到高跳变信号;让EEPROM自主启动内部写周期,将EERPOM缓存区数据写入EEPROMclr sdasetb SCL;该两句有两个作用,一方面是本次EEPROM操作的停止命令,让EEPROM 启动写周期;SETB SDA;另一方面,为下一次EEPROM读写操作作好了准备,只等启动命令到来。
;第六步,延迟等待写周期完成,否则影响下一次的读写EEPROM操作。
;应根据晶振频率调整下列的延迟时间MOV R0,#0FFHDELAYLOOP: NOPNOPNOPNOPNOPNOPNOPDJNZ R0,DELAYLOOPRET;----------------------------------------------------------------------------------------------------;随机读EEPROM(A T24C02)子程序;入口:EEPROMADRESS(拟读EEPROM存贮单元地址,00~FFH);出口:READDATA(读出字节数据在主机的存放地址);---------------------------------------------------------------------------------------------------- READEEPROMR:;第1步,启动EEPROM读写操作(时序0)lcall startEEPROM;调用启动子程序(时序1~8)?;第2步,输入设备号和功能选择码即10100000BMOV A,#10100000B;1010是规定的,000是设备地址,最低位0表示拟执行写操作LCALL SENDDA TA;调用串行发送字节数据子程序;第3步查询EEPROM应答信号情况(时序9)LCALL WAITACK;调用应答响应子程序;第四步,传送数据拟贮存地址给EEPROM的地址指针(时序1~8)MOV A,EPROMADDRESS;将拟贮存数据的EEPROM贮存单元地址送入SENDDATA子程序的入口ALCALL SENDDA TA;第五步,查询EEPROM应答信号情况(时序9)LCALL WAITACK;调用应答响应子程序;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ;以上五步均属于伪写操作。
;因未实际输入输出数据和写周期,其内部数据地址指针不作变化,仍指向刚输入的地址;以下实际就是立即读操作,读出数据指针所指的地址单元内容,分六个步骤:;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;(1)启动EEPROM读写操作(时序0)?lcall startEEPROM;调用启动子程序;(2)输入设备号和功能选择码即10100001B;此处R/W位(最低一位)取1,表明读操作;使用了8个SCL时钟时序(时序1~8)MOV A,#10100001BLCALL SENDDA TA;(3)查询EEPROM应答信号情况(时序9)?LCALL WAITACK;(4)EEPROM输出一个8位数据到SDA总线上,主机作接收处理,使用8个SCL 时钟时序(时序1~8)lcall receivedataMOV READDATA,A;(5)不产生应答信号,但应保留应答时序SETB sclCLR scl;(6)主机发出停止信号clr sdasetb SCL;该两句是结束时序SETB SDARET;--------------------------------------------------------------------------------------------------------------------- ;STARTEEPROM子程序:向EEPROM发出读写操作的开始信号,在一个SCL时钟时序内完成(时序0);--------------------------------------------------------------------------------------------------------------------- STARTEEPROM:SETB SCLSETB SDA;停止EEPROM操作,为下一次写作准备CLR SDA;在SCL为高电平时,SDA由高变低,发出启动信号clr scl;完成一个时钟时序RET;---------------------------------------------------------------------------------------------------------------------;SENDDATA子程序:主机向EEPROM串行发送1个字节数据;入口:约定需发送的字节数据存在A中;使用资源:A、CY、R0;--------------------------------------------------------------------------------------------------------------------- SENDDATA: ;使用8个完整的SCL时钟时序(时序0~8)MOV R0,#08HSENDDATALOOP:RLC A;带CY的A内容循环左移位,先高位后低位MOV SDA,C;将位信息送到SDA线Setb scl;在SCL上升沿将SDA信息送入EEPROM缓存区Clr sclDJNZ R0,SENDDA TALOOPRLC A;让A和CY内容恢复为入口前状态,在某些情况上很有必要。