标题: 单片机+I2C通讯应答信号异常 [打印本页]
作者: 忆1709 时间: 2020-12-30 17:07
标题: 单片机+I2C通讯应答信号异常
使用Proteus来进行89C52与24C02的I2C通讯仿真,实现将写入24C02的数据读出来点亮由P1控制的LED灯;
写数据后,应答信号SDA波形如图;仿真图如图。
目前问题是在proteus里面LED灯不能正常按照写入的数据来点亮,而下载到开发板却是正常的。
有如下疑问:
① 根据图示应答波形发现,SDA在SCL的下降沿期间发生了变化(拉高),这个是否正常?按照I2C应答时序图,应该是SCL拉低后一段时间SDA才能发生变化。看波形应该是24c02正常产生了应答,但是在SCL拉低时,SDA提早被释放了。
② 调试代码,将如下应答信号内的 while((sda==1)&&(i<250))i++; 这段延时给注释掉后,仿真可以正常点亮LED灯(但应答波形依旧),请问这段代码为什么会导致异常?
感谢!
void respons() //应答
{
uchar i;
scl=1;
delay();
// while((sda==1)&&(i<250))i++; // 注释掉此行代码后正常。
scl=0;
delay();
}
完整IIC代码:
***************************************************
#include<reg52.h>
#define uchar unsigned char
sbit sda=P2^0;
sbit scl=P2^1;
uchar a;
void delay()
{ ;; }
void start() //开始信号
{
sda=1;
delay();
scl=1;
delay();
sda=0;
delay();
scl=0;
delay();
}
void stop() //停止
{
sda=0;
delay();
scl=1;
delay();
sda=1;
delay();
// scl=0;
// delay();
}
void respons() //应答
{
uchar i;
scl=1;
delay();
while((sda==1)&&(i<250))i++;
scl=0;
delay();
}
//void Send_respons() //发送应答信号,即给从机发0,如果不应答要发1,主程序中就不加这段程
序即可。
//{
// sda=0;
// delay();
// scl=1;
// delay();
// scl=0;
// delay();
//}
void init()
{
sda=1;
delay();
scl=1;
delay();
}
void write_byte(uchar date)
{
uchar i,temp;
temp=date;
for(i=0;i<8;i++)
{
temp=temp<<1;
delay();
sda=CY;
delay();
scl=1;
delay();
scl=0;
}
delay();
sda=1;
delay();
}
uchar read_byte()
{
uchar i,k;
scl=0;
delay();
sda=1;
delay();
for(i=0;i<8;i++)
{
scl=1;
delay();
k=(k<<1)|sda;
scl=0;
delay();
}
return k;
}
void delay1(uchar x)
{
uchar a,b;
for(a=x;a>0;a--)
for(b=100;b>0;b--);
}
void write_add(uchar address,uchar date)
{
start();
write_byte(0xa0);
respons();
write_byte(address);
respons();
write_byte(date);
respons();
stop();
}
uchar read_add(uchar address)
{
uchar date;
start();
write_byte(0xa0);
respons();
write_byte(address);
respons();
delay1(100);
start();
write_byte(0xa1);
respons();
date=read_byte();
stop();
return date;
}
void main()
{
init();
write_add(23,0xaa);
delay1(100);
P1=read_add(23);
while(1);
}
-
ack异常.png
(6.7 KB, 下载次数: 57)
-
仿真图.png
(140.64 KB, 下载次数: 66)
作者: 忆1709 时间: 2020-12-31 20:42
求大神指点,感激不尽!
作者: 人人学会单片机 时间: 2021-1-1 13:11
void IIC_Delay()
{
_nop_();_nop_();_nop_();_nop_();_nop_();
}
void IIC_Init()
{
P2M0&=0x3f;
P2M1&=0x3f;
SDA_GPIO=1;
SCL_GPIO=1;
}
void IIC_Start()//IIC启动信号
{
SDA_GPIO=1;
SCL_GPIO=1;
IIC_Delay();
SDA_GPIO=0;
IIC_Delay();
SCL_GPIO=0;
IIC_Delay();
}
void IIC_Stop()//IIC停止信号
{
SDA_GPIO=0;
SCL_GPIO=1;
SDA_GPIO=1;
IIC_Delay();
}
void IIC_Write_Byte(u8 IIC_Byte)//向总线发送一个字节
{
u8 i;
SCL_GPIO=0;
SDA_GPIO=1;
for(i=0;i<8;i++)
{
SDA_GPIO=(bit)(IIC_Byte&0x80);
IIC_Byte<<=1;
IIC_Delay();
SCL_GPIO=1;
IIC_Delay();
SCL_GPIO=0;
IIC_Delay();
}
}
u8 IIC_Read_Byte()
{
u8 i,Value;
SCL_GPIO=0;
SDA_GPIO=1;
for(i=0;i<8;i++)
{
Value=(Value<<1)|SDA_GPIO;
IIC_Delay();
SCL_GPIO=1;
IIC_Delay();
SCL_GPIO=0;
IIC_Delay();
}
return Value;
}
u8 IIC_Read_Ack()//单片机检测IIC从机发来的应答信号
{
u8 ack=1,i=0;
SCL_GPIO=1;
IIC_Delay();
while((ack)&&(i<5))
{
ack=SDA_GPIO;
i++;
}
SCL_GPIO=0;
return ack;
}
void IIC_Write_Ack(bit ack)//单片机发送应答给从机
{
SDA_GPIO=ack;
IIC_Delay();
SCL_GPIO=1;
IIC_Delay();
SCL_GPIO=0;
IIC_Delay();
SDA_GPIO=1;
IIC_Delay();
}
作者: TTQ001 时间: 2021-1-2 01:34
感谢分享信息,非常有帮助。 看来时钟频率设置需要更改以匹配硬件规格。
作者: 忆1709 时间: 2021-1-6 11:52
分别抓取了注释while语句跟没有注释while语句的I2C调试数据与波形图,可以发现,前者正常执行了stop,后者没有,也就是说增加 while((sda==1)&&(i<250))i++; 之后,stop缺失,导致24c02没有进入写周期,数据也就没有写进去。
问题是为何while((sda==1)&&(i<250))i++;这条语句会导致stop缺失,没搞明白。这只是一条判断语句,sda也产生了应答的,那么while为假,所以执行这条语句也就是1个指令周期的时间,相当于延时了一个指令周期,为什么会有影响呢?
如下是对比图:
-
时序图-0x80异常(注释while).png
(173.05 KB, 下载次数: 65)
-
时序图-0x80异常(没注释while).png
(197.28 KB, 下载次数: 75)
欢迎光临 (http://www.51hei.com/bbs/) |
Powered by Discuz! X3.1 |