打印
[51单片机]

I2C仿真问题,请高手赐教

[复制链接]
1924|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
用proteus仿真51单片机读写at24c04
I2C程序一开始始终走不通,

后来发现在start()增加一行SCL=0;

仿真就正常了。

想不明白为什么加这一行,请高手们指点一下,谢谢

代码如下:


#include<reg51.h>
#include<intrins.h>        
#define uchar unsigned char
#define uint unsigned int
#define NOP4() {_nop_();_nop_();_nop_();_nop_();}
sbit SCL=P1^0;
sbit SDA=P1^1;
sbit SPK=P3^0;
sbit P20=P2^0;


code a[]={0x40,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x00,0x10};
void Delayms(int ms)
{        
        int i;
        while(ms--)
                for(i=0;i<125;i++);
}
//-----------初始化
void Init()
{
        SDA=1;
        NOP4();
        SCL=1;
        NOP4();
}


//-------------开始        
void Start()
{
        SDA=1;
        SCL=1;
        NOP4();
        SDA=0;
        NOP4();
        SCL=0;         //==========不明白为什么这一行命令不加的话,仿真就不成功,I2C协议上没有规定,scl最后要拉低啊??
}
//==============停止
void Stop()
{
        SDA=0;
        NOP4();
        SCL=1;
        NOP4();
        SDA=1;
}

//==============应答
void Ask()
{        
        uchar i;
        SCL=1;
        NOP4();
        while((SDA==1)&&(i<250))
                i++;
        SCL=0;
        NOP4();
}

//--------------无响应
void NO_ACK()
{
        SDA=1;
        SCL=1;
        NOP4();
        SCL=0;
        SDA=0;
}

//--------------------写一个字节
void Writebyte(uchar b)
{
        uchar i;
        for(i=0;i<8;i++)
        {
                b<<=1;
                SDA=CY;
                _nop_();
                SCL=1;
                NOP4();
                SCL=0;
        }
//RACK();
        Ask();
}


//----------------------向指定地址写数据

void Writedat(uchar add, uchar dat)
{
        start();   
        Writebyte(0xa0);
        
        Writebyte(add);      
        
        Writebyte(dat);      
        
        stop();
        Delayms(10);
}                                                               

//----------------------读字节
uchar Read_B()
{
        uchar i,b;
        for(i=0;i<8;i++)
        {
                SCL=1;
                b<<=1;
                b|=SDA;
                SCL=0;
        }
        return b;
}

//===========================指定地址读数据
uchar Read_add(uchar addr)
{ uchar dat;
        Start();
        Writebyte(0xa0);
        Writebyte(addr);
        Start();
        Writebyte(0xa1);
        dat=Read_B();
        Stop();
        return dat;
}


void main()
{
        Init();

        Writedat(2,4);
        
        P2=a[Read_add(2)];
        Delayms(10000);
}

相关帖子

沙发
ayb_ice| | 2016-8-23 16:17 | 只看该作者
scl为高,sda不能变化,否则不是开始就是停止,开始信号后,设置scl为低是标准的为后面的发送做准备,不然后面的数据发送又变成开始了

使用特权

评论回复
评分
参与人数 1威望 +3 收起 理由
tony0727 + 3 找到问题了,谢谢
板凳
ayb_ice| | 2016-8-23 16:20 | 只看该作者
应该是变停止了,不是开始

使用特权

评论回复
地板
tony0727|  楼主 | 2016-8-23 16:31 | 只看该作者
ayb_ice 发表于 2016-8-23 16:20
应该是变停止了,不是开始

I2C协议中:在 SCL 线是高电平时 SDA 线从高电平向低电平切换 表示起始条件
                        SCL 是高电平时 SDA 线由低电平向高电平切换 表示停止条件
                 貌似我写的也没错啊,看网上分享的源代码也有不加SCL=0这语句就能仿真的,请赐教

使用特权

评论回复
5
suntechnology| | 2016-8-23 16:32 | 只看该作者
这是为后面单片机向AT24C04发送命令或数据做准备,SDA只有在SCL=0时才能发生变化,反之,单片机发送的命令不是开始就是结束。

使用特权

评论回复
6
NE5532| | 2016-8-23 16:41 | 只看该作者
是因为你I2C协议不熟,除了启动位和停止位,SDA只能在SCL为低的时候变化,所以你这里不拉低,SDA怎么送数据出去?另外你对协议的理解也比较奇怪,协议里讲解启动时序本来就是SDA和SCL两个下降沿组成的,为啥你只写一个?

使用特权

评论回复
7
tony0727|  楼主 | 2016-8-23 16:47 | 只看该作者
NE5532 发表于 2016-8-23 16:41
是因为你I2C协议不熟,除了启动位和停止位,SDA只能在SCL为低的时候变化,所以你这里不拉低,SDA怎么送数据 ...

我看网上的I2C协议中,时序图都是一个下降沿或上升沿啊,没有说是两个啊?您看的是英文版的么?

使用特权

评论回复
8
tony0727|  楼主 | 2016-8-23 16:48 | 只看该作者
suntechnology 发表于 2016-8-23 16:32
这是为后面单片机向AT24C04发送命令或数据做准备,SDA只有在SCL=0时才能发生变化,反之,单片机发送的命令 ...

我说的这个就是开始的函数啊,貌似不加这一句就不正常,看仿真效果像是I2C协议没有执行

使用特权

评论回复
9
NE5532| | 2016-8-23 16:58 | 只看该作者
tony0727 发表于 2016-8-23 16:47
我看网上的I2C协议中,时序图都是一个下降沿或上升沿啊,没有说是两个啊?您看的是英文版的么? ...

是啊,你看这个时序图呢,我都不知道启动以后SCL不拉低怎么传数据了。

使用特权

评论回复
评分
参与人数 1威望 +3 收起 理由
tony0727 + 3
10
tony0727|  楼主 | 2016-8-23 17:01 | 只看该作者
NE5532 发表于 2016-8-23 16:58
是啊,你看这个时序图呢,我都不知道启动以后SCL不拉低怎么传数据了。

...

我仿佛明白了,开始函数不加这一行应该没问题,问题应该是我后面写字节的时候,没有先将SCL电平拉低,导致数据写不进去,谢谢,我再重写一下后端程序!

使用特权

评论回复
11
suntechnology| | 2016-8-23 17:03 | 只看该作者
tony0727 发表于 2016-8-23 16:48
我说的这个就是开始的函数啊,貌似不加这一句就不正常,看仿真效果像是I2C协议没有执行 ...

那确实是开始函数,只是不加SCL=0的话,后面就没办法发送数据了。
看看我这里的中文资料吧。

IIC.jpg (286.19 KB )

IIC.jpg

使用特权

评论回复
评分
参与人数 1威望 +3 收起 理由
tony0727 + 3
12
NE5532| | 2016-8-23 17:04 | 只看该作者
反正是软件写时序,写在哪里不重要,逗出来就行了。I2C函数之间的接口,最好就直接是SCL拉低的状态。如果有多个主机,这样接口也不会失去总线的仲裁权,各个模块也好编写。

使用特权

评论回复
评分
参与人数 1威望 +3 收起 理由
tony0727 + 3
13
tony0727|  楼主 | 2016-8-23 17:08 | 只看该作者
NE5532 发表于 2016-8-23 17:04
反正是软件写时序,写在哪里不重要,逗出来就行了。I2C函数之间的接口,最好就直接是SCL拉低的状态。如果有 ...

多谢指教,恍然大悟啊

使用特权

评论回复
14
tony0727|  楼主 | 2016-8-23 17:10 | 只看该作者
suntechnology 发表于 2016-8-23 17:03
那确实是开始函数,只是不加SCL=0的话,后面就没办法发送数据了。
看看我这里的中文资料吧。
...

嗯,现在明白问题出在那了,谢谢

使用特权

评论回复
15
cngogjtu| | 2016-8-24 07:28 | 只看该作者
多谢指教,恍然大悟

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
tony0727 + 1
16
heishe1989| | 2016-8-24 14:50 | 只看该作者
大神多啊,学习学习

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

24

主题

249

帖子

1

粉丝