无良的鱼 发表于 2019-10-31 12:05 官网查了下,起始地址是0x2000 ![]() |
无良的鱼 发表于 2019-10-31 12:05 你的第一个数字2写进去了,所以IIC协议程序应该没问题,所以问题就出在eeprom的擦除上,帮你百度了下,发现擦除还挺麻烦的,定义sfr地址啥的,没记错的话单片机的EEPROM起始地址应该是0x02000,也就是说0x02000可以写进一个unsigned int型的数字,只要你的这个2定义的是uint型,那你完全可以每循环一次,写入地址加1,然后读取的地址也加1,即循环里addr++,而不是写死成2,当然,这个0x02000这个扇区地址是有上限的,上限多少忘了,自己查。这个扇区只要不超过地址范围就可以一直加。然后要注意的是,如果不执行擦除这一操作的话,数据应该是写不进去的,eeprom是掉电可存储,断电数据不会丢失,如果这一地址里有数据,那么你的操作无效,值应该是不会变的,所以最好还是研究一下怎么擦除扇区,百度一下就出来了。 |
无良的鱼 发表于 2019-10-31 12:05 好吧,习惯用16进制表示地址了,乍一看这个10进制的不太舒服,给你百度了下哈,以下是原话: 与单片机有关。 比如STC的单片机,在向片内EEPROM写入数据前必须执行擦除操作,并且擦除是按照扇区进行的,并不能逐字节进行。 而STM8单片机,在向片内EEPROM写入数据时不需要用户在程序中进行擦除,单片机会自动擦除对应字节的数据。 所以你这个每次for循环都是直接写入时肯定有问题的,IIC这个协议我用过很多次了都没有问题,EEPROM的操作也有两次,都没有问题哈,你去网上重新搜一个IIC的协议程序再试试,记得写入前要先擦除哈,这个真的很重要。 |
读写时序有问题吧,太乱了,看得人发晕,自己先梳理一下吧![]() |
无敌的UUZ大人 发表于 2019-10-31 14:13 但是好像就是这个地方出问题了 |
I2C顶多是延时问题,直接示波器看波形就知道通信有没错了,如果有回复信号就看逻辑错误了 |
我也是刚学,一起研究一下。 我没用过eeprom,但我知道你这么写应该没错: for(k=2;k<100;k++) { Write(k,k); delay(1); num=Read(k); if(Ackflag) P1=0; else P1=0xff; display(num/10,num%10); } |
额,2就是epprom里面的第二个地址,就是向第二个地址里面写入k的值,然后从第二个地址读出来,用数码管显示, 然而是怎样擦出的呢,我看的例程里面没有这个过程,不怎么懂,应该是怎样的呢 这个就是做练习用的,不停重复此过程, |
bai_yun_123 发表于 2019-10-31 08:48 2就是epprom里面的第二个地址,就是往第二个地址里面写入k的值,然后从第二个地址里面读出来然后用数码管显示 这个就是练习用的,不过怎么擦除呢,难道不是直接写入就可以了嘛? |
我去,咋复制了这么一大坨,我记得就复制了一个for循环啊 |
向epprom写入数值2,读取之后数码管显示,再把数值加1,重复写入读取,显示这个步骤,一直加到99,为什么数码管却一直显示刚开始的数值 2,求各位前辈指点! 下面把代码附上: ———————————————————————————————————————————————————————— #include <reg52.h> #include <intrins.h> sbit SCL=P3^4; sbit SDA=P3^5; bit Ackflag; char k; char code duan[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; char code we[]={0xfe,0xfd}; void delay5us() { _nop_(); } void init() { SCL=1; delay5us(); SDA=1; delay5us(); } void I2c_start() { SCL=1; delay5us(); SDA=1; delay5us(); SDA=0; delay5us(); } void I2c_stop() { SCL=0; SDA=0; delay5us(); SCL=1; delay5us(); SDA=1; delay5us(); } bit Read_Ack() { SCL=0; SCL=1; delay5us(); if(SDA) { SCL=0; return 1; } else { SCL=0; return 0; } } void Send_Ack(bit i) { SCL=0; if(i) SDA=1; else SDA=0; SCL=1; delay5us(); SCL=0; SDA=1; } void I2c_sendbyte(char dat) { char i; for(i=0;i<8;i++) { SCL=0; if(dat&0x80) SDA=1; else SDA=0; SCL=1; dat=dat<<1; } SCL=0; SDA=1; } char I2c_readbyte() { char i,dat; for(i=0;i<8;i++) { dat<<=1; SCL=0; SCL=1; if(SDA) dat|=0x01; } return(dat); } void Write(char addr,char dat) { I2c_start(); I2c_sendbyte(0xa0);//send a byte address if(Read_Ack()) Ackflag=1; else Ackflag=0; I2c_sendbyte(addr); if(Read_Ack()) Ackflag=1; else Ackflag=0; I2c_sendbyte(dat); if(Read_Ack()) Ackflag=1; else Ackflag=0; I2c_stop(); } char Read(char addr) { char dat; I2c_start(); I2c_sendbyte(0xa0);//send a byte address if(Read_Ack()) Ackflag=1; else Ackflag=0; I2c_sendbyte(addr); Read_Ack(); I2c_start(); I2c_sendbyte(0xa1); //read 1 if(Read_Ack()) Ackflag=1; else Ackflag=0; dat=I2c_readbyte(); Send_Ack(1); I2c_stop(); return (dat); } void delay(char z) { char x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); } void display(char shi,char ge) { while(1) { P2=0xfd; P0=duan[ge]; delay(5); P2=0xfe; P0=duan[shi]; delay(5); } } void main() { char num; init(); TMOD=0x01; EA=1; ET0=1; TH0=(65536-46080)/256; TL0=(65536-46080)%256; TR0=1; for(k=2;k<100;k++) { Write(2,k); delay(1); num=Read(2); if(Ackflag) P1=0; else P1=0xff; display(num/10,num%10); } } 你这个write的第一个参数和read的参数都是address,这个是eeprom的扇区地址,不知道你写个2是啥意思,然后eeprom每次写入都需要擦除当前扇区里的东西,且每次操作的对象是当前整个扇区(一次擦除,整个扇区全部擦除,每个单片机的扇区数不一样,具体百度资料),看你的for循环里也没有在写入之前先擦除,而且一般也不会每显示一次都往扇区里写入值,这样多了个过程,当然练习就当我没说,咋写都成。 |