找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2234|回复: 11
打印 上一主题 下一主题
收起左侧

刚学I2c总线,有点问题不懂,求各位前辈指点

[复制链接]
跳转到指定楼层
楼主
向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);

}
}


IMG_20191030_231315.jpg (3.69 MB, 下载次数: 40)

IMG_20191030_231315.jpg
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:616759 发表于 2019-10-31 08:48 | 只看该作者

向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循环里也没有在写入之前先擦除,而且一般也不会每显示一次都往扇区里写入值,这样多了个过程,当然练习就当我没说,咋写都成。
回复

使用道具 举报

板凳
ID:616759 发表于 2019-10-31 10:19 | 只看该作者
我去,咋复制了这么一大坨,我记得就复制了一个for循环啊
回复

使用道具 举报

地板
ID:627807 发表于 2019-10-31 11:57 | 只看该作者
bai_yun_123 发表于 2019-10-31 08:48
向epprom写入数值2,读取之后数码管显示,再把数值加1,重复写入读取,显示这个步骤,一直加到99,为什么 ...

2就是epprom里面的第二个地址,就是往第二个地址里面写入k的值,然后从第二个地址里面读出来然后用数码管显示
这个就是练习用的,不过怎么擦除呢,难道不是直接写入就可以了嘛?
回复

使用道具 举报

5#
ID:627807 发表于 2019-10-31 12:05 | 只看该作者
额,2就是epprom里面的第二个地址,就是向第二个地址里面写入k的值,然后从第二个地址读出来,用数码管显示,
然而是怎样擦出的呢,我看的例程里面没有这个过程,不怎么懂,应该是怎样的呢
这个就是做练习用的,不停重复此过程,
回复

使用道具 举报

6#
ID:606366 发表于 2019-10-31 14:13 | 只看该作者
我也是刚学,一起研究一下。
我没用过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);
}
回复

使用道具 举报

7#
ID:318452 发表于 2019-10-31 16:21 | 只看该作者
I2C顶多是延时问题,直接示波器看波形就知道通信有没错了,如果有回复信号就看逻辑错误了
回复

使用道具 举报

8#
ID:627807 发表于 2019-10-31 16:25 | 只看该作者
无敌的UUZ大人 发表于 2019-10-31 14:13
我也是刚学,一起研究一下。
我没用过eeprom,但我知道你这么写应该没错:
for(k=2;k

但是好像就是这个地方出问题了
回复

使用道具 举报

9#
ID:525511 发表于 2019-10-31 17:31 | 只看该作者
读写时序有问题吧,太乱了,看得人发晕,自己先梳理一下吧
回复

使用道具 举报

10#
ID:616759 发表于 2019-11-1 09:31 | 只看该作者
无良的鱼 发表于 2019-10-31 12:05
额,2就是epprom里面的第二个地址,就是向第二个地址里面写入k的值,然后从第二个地址读出来,用数码管显示 ...

好吧,习惯用16进制表示地址了,乍一看这个10进制的不太舒服,给你百度了下哈,以下是原话:
与单片机有关。
比如STC的单片机,在向片内EEPROM写入数据前必须执行擦除操作,并且擦除是按照扇区进行的,并不能逐字节进行。
而STM8单片机,在向片内EEPROM写入数据时不需要用户在程序中进行擦除,单片机会自动擦除对应字节的数据。
所以你这个每次for循环都是直接写入时肯定有问题的,IIC这个协议我用过很多次了都没有问题,EEPROM的操作也有两次,都没有问题哈,你去网上重新搜一个IIC的协议程序再试试,记得写入前要先擦除哈,这个真的很重要。
回复

使用道具 举报

11#
ID:616759 发表于 2019-11-1 10:06 | 只看该作者
无良的鱼 发表于 2019-10-31 12:05
额,2就是epprom里面的第二个地址,就是向第二个地址里面写入k的值,然后从第二个地址读出来,用数码管显示 ...

你的第一个数字2写进去了,所以IIC协议程序应该没问题,所以问题就出在eeprom的擦除上,帮你百度了下,发现擦除还挺麻烦的,定义sfr地址啥的,没记错的话单片机的EEPROM起始地址应该是0x02000,也就是说0x02000可以写进一个unsigned int型的数字,只要你的这个2定义的是uint型,那你完全可以每循环一次,写入地址加1,然后读取的地址也加1,即循环里addr++,而不是写死成2,当然,这个0x02000这个扇区地址是有上限的,上限多少忘了,自己查。这个扇区只要不超过地址范围就可以一直加。然后要注意的是,如果不执行擦除这一操作的话,数据应该是写不进去的,eeprom是掉电可存储,断电数据不会丢失,如果这一地址里有数据,那么你的操作无效,值应该是不会变的,所以最好还是研究一下怎么擦除扇区,百度一下就出来了。
回复

使用道具 举报

12#
ID:616759 发表于 2019-11-1 10:24 | 只看该作者
无良的鱼 发表于 2019-10-31 12:05
额,2就是epprom里面的第二个地址,就是向第二个地址里面写入k的值,然后从第二个地址读出来,用数码管显示 ...

官网查了下,起始地址是0x2000,记错了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表