cyradg 发表于 2021-2-16 17:24

请教各位I2C对24C02写完后无法立即读的问题

最近在学I2C读写24C02的东西,弄了几天了,搞不定。下面是代码截图,就是对24C02的读写操作,如果是先写后立即读,在Proteus里仿真是读出0xFF,在开发板里是读出0x00,总之读不出。但是,按照先写后立即读操作完,把写的那部分代码注释掉再去跑,Proteus和开发板里都会读出0xAF,请问各位是什么原因。感觉I2C比USART稀奇古怪多了,USART我看几小时就搞定了,I2C几天都搞不定,I2C协议早先我也没接触过什么。

                        代码图

    先写后立即读,读不出

只读,能读出

hellohello22 发表于 2021-2-16 18:22

本帖最后由 hellohello22 于 2021-2-16 18:24 编辑

i2c问题不是芯片坏(小概率)就是时序不对 没有例外我自己写的驱动就一直正常

cyradg 发表于 2021-2-16 18:46

hellohello22 发表于 2021-2-16 18:22
i2c问题不是芯片坏(小概率)就是时序不对 没有例外我自己写的驱动就一直正常 ...

Proteus 仿真也是不正常的。按先写后立即读先跑一遍,是读不出来的,看到网上解释是要给24C02写内存的一点时间,建议等待6ms,但是我都等待2000ms了,仍然读不出。但是然后按只读方式再跑一遍,原来写进去的就能读出来了。仿真和实际的开发板都是这样,应该不是芯片问题。先写后读,按照I2C的解释是两个不同模式的切换,即由写切换到读模式,说是RS(重启)方法切换,但是我不知道啥叫RS方法,我只能理解为先STOP,再START,不知道对不对。看24C02手册读取数据有不同模式,默认是按顺序读,也就是当前操作(无论读写)第N个地址,如果接下来发送读命令,它会去读取第N+1地址的内容,这显然不符合我的要求,不过我是按照手册的“任意地址读”的方式操作的,对于只读,还是能读出来的。

今日头条优惠 发表于 2021-2-16 18:54

{:5_639:}

hellohello22 发表于 2021-2-16 18:56

我写完马上读都可以 有示波器看下波形就知道

cyradg 发表于 2021-2-16 19:03

我用的开发平台是ATMEL STUDIO 7,ATMEGA16似乎有些古老了。{:5_604:}网上的代码似乎比我的更底层,还要根据接收和发送来设置什么SDA的输入输出方式,也就是I/O模式,但是AV Studio7似乎不鸟这些,也就是按照M16手册说明,语句里只要开了TWI功能,SDA,SCL这两个脚好像就不在是什么I/O口了,任凭你怎么设置PC0,PC1的输入输出方式,全然不鸟,语句也比网上的简单多了,网上也根本找不到相似的原因。

cyradg 发表于 2021-2-16 20:08

hellohello22 发表于 2021-2-16 18:56
我写完马上读都可以 有示波器看下波形就知道

上开发板用示波器看了,先写的过程完整被抓下来了,数据全正确都有,到了STOP,也执行了,但是后续的START之类的波形全没了,也就是没有执行读过程。虽然代码在执行,而且状态也符合,但是实际没有读的波形产生,很是奇怪。不知道I2C协议里的读写状态切换的RS信号是啥信号,不知道STOP之后,为什么延迟一段时间用START,实际不会开启。

拓荒牛 发表于 2021-2-16 20:34

上拉电阻那里,接了电压没?我只看到一个探针

hellohello22 发表于 2021-2-16 20:37

本帖最后由 hellohello22 于 2021-2-16 21:58 编辑

IO模拟,自己写一遍时序就搞定了,读写随便切换,闻所未闻乱七八糟的, 24c02前阵子刚读写过,没有任何问题, i2c是最简单的了

最近把spi翻了个遍, TF卡挂载FAT32也成功了,随便读写文件和电脑交换, 完全自己写的代码,包括FAT表项,目录项, 簇各种操作,简单高效

cyradg 发表于 2021-2-16 20:47

拓荒牛 发表于 2021-2-16 20:34
上拉电阻那里,接了电压没?我只看到一个探针

那个探针是激励源符号,是一个DC 5V电源,表示接一个5V电压。Proteus大概就是这么用电源的。你仔细看下M16,是没有VCC和GND引脚的,估计默认就是接到5V那去了,根本不让接电源。

cyradg 发表于 2021-2-16 20:58

hellohello22 发表于 2021-2-16 20:37
IO模拟,自己写一遍时序就搞定了,读写随便切换,闻所未闻乱七八糟的, 24c02前阵子刚读写过,没有任何问题 ...

I/O口模拟的话要写的就太多了,我也是刚学,很多C语言和指令都不熟。{:5_604:}M16本身就有TWI硬件相关指令,读写数据是按一个字节8位来操作的,写代码相对一位一位来操作要省事。据说用I/O口模拟要用一堆的delay延时,不好把握,用TWI硬件指令,访问TWI的中断标志就可以知道设备是否有ACK回应,根据不同回应代码就知道是什么类型的回应,相对方便些,也更高效些。I2C协议描述里,有S,P信号,也就是START和STOP信号,不过也是奇怪,发送P信号就是结束了,怎么下一次的START无效了,而且是代码正常执行,实际却没有波形。

hellohello22 发表于 2021-2-16 21:40

本帖最后由 hellohello22 于 2021-2-16 22:35 编辑

cyradg 发表于 2021-2-16 20:58
I/O口模拟的话要写的就太多了,我也是刚学,很多C语言和指令都不熟。M16本身就有TWI硬件相关指 ...
想学习原理,就得从底层开始,囫囵吞枣学不深,出了问题定位更难,我一直坚持自己写底层,收获甚大,细节一清二楚,为了读写tf和串行flash, 把中断+DMA摸熟,砍柴不误磨刀工{:5_604:}




dqp05 发表于 2021-2-16 21:55

我都是用汇编写,不喜欢用C,汇编写更有安全感

dqp05 发表于 2021-2-16 22:07

给楼主一个建议:用示波器看波形,时序要严格,误差不能太大;

mon51 发表于 2021-2-16 22:20

汇编-MS51:
rdee:
                call star_ee
        ;*************************      
                mov a,dph
        ;**************************2001.7.17
                rl a
                orl a,#slaw                     
        ;**************************2001.7.17
                call w1bt
                call cack
                jb f0,rdee_end
                mov a,dpl
                call w1bt
                call cack
                jb f0,rdee_end
                call star_ee
        ;*************************      
                mov a,dph
        ;**************************2001.7.17
                rl a
                orl a,#slar                     
        ;**************************2001.7.17
                call w1bt
                call cack
                jb f0,rdee_end
                call r1bt
                ;call mack
                call mnack
                call stop_ee
        ;***********************2001.7.22      
                clr ee_f
                ret
rdee_end:
                setb ee_f
                ;sjmp rdee
                ret

star_ee:
                setb sda
                setb scl
                nop
                nop
                clrsda
                nop
                nop
                clrscl
                ret
stop_ee:
                clrsda
                setb scl
                nop
                nop
                setb sda
                ret
mack:
                clrsda
                setb scl
                nop
                nop
                clrscl
                setb sda
                ret
mnack:
                setb sda
                setb scl
                nop
                nop
                clrscl
                clrsda
                ret
cack:
                setb sda
                setb scl
                nop
                nop
                clr f0
                jnb sda,cend
                setb f0
        cend:
                clr scl
                ret
w1bt:
                mov r7,#08d
        wlp:
                rlc a
                jc wr1
        wr0:
                clr sda
                setb scl
                nop
                nop
                clr scl;********
                jmp wlp1
        wr1:
                setb sda
                setb scl
                nop
                nop
                clr scl
                clr sda
        wlp1:
                nop
                djnz r7,wlp
                ret
r1bt:
                mov r7,#08d
        rlp:
                setb sda
                setb scl
                nop
                nop
                jnb sda ,rd0
        rd1:
                setb c
                rlc a
                clr scl
                jmp rlp1
        rd0:
                clr c
                rlc a
                clr scl
        rlp1:
                nop
                djnz r7,rlp
                ret
wree:
                call star_ee
        ;*************************      
                mov a,dph
        ;**************************2001.7.17
                rl a
                orl a,#slaw                     
        ;**************************2001.7.17
                call w1bt
                call cack
                jb f0,wree_end
                mov a,dpl
                call w1bt
                call cack
                jb f0,wree_end
                mov a,r4
                call w1bt
                call cack
                jb f0,wree_end
                call stop_ee                                                            
                ;call led
                push dph
                push dpl
                push 00h
                push 01h
                push a
                push b
                call led
                pop b
                pop a
                pop 01h
                pop 00h
                pop dpl
                pop dph
                clr ee_f
                ret
wree_end:
                setb ee_f      
                ret

mon51 发表于 2021-2-16 22:21

24C16:
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Nop_:
                nop
                nop
                nop
                nop
                ret

StarEe:
                setb sda
                call Nop_
                setb scl
                call Nop_
                clr sda
                call Nop_
                clr scl
                ret
               
StopEe:
                clr sda
                call Nop_
                setb Scl
                call Nop_
                setb sda
                call Nop_
                clr scl
                ret

Ack:
                Call Nop_
                setb scl
                call Nop_
                mov c,sda
                call Nop_
                clr scl
                ret

McuAck:
                clr sda
                call Ack
                setb Sda
                ret
               
McuNAck:
                setb sda
                setb Scl
                call NOp_
                clr Scl
                clr Sda
                ret
WrByte:
                mov b,#8
        Wr11:
                rlc a
                mov sda,c
                call Ack
                djnz b,Wr11
                setb Sda
                call Ack
                ret
RdByte:
                mov b,#08
        Rd11:
                call Ack
                rlc a
                djnz b,Rd11
                ret

MakeAdr:
                mov a,dph
                rl a
                orl a,#0a0h
                ret
               
;*********************************
;a=0 =>24c16;=>24c32...
;r1=Long;R0=Adr;Dptr=EeAdr
;*********************************
EeAll:
                call StarEe
                mov a,#0
                jz Ee24c16
                ;*************
                ;Ee24c32
                mov a,#0a0h
                call WrByte
                jc EeErr
                mov a,dph
                call WrByte
                jc EeErr
                sjmp EeDo
        Ee24c16:
                mov a,#dph
                call MakeAdr
                call WrByte
        EeDo:
                mov a,Dpl
                call WrByte
                jc EeErr
                ret
        EeErr:
                setb ee24
                ret
                                               
;)))))))))))))))))))))))))))))))))
WrEe:
                call EeAll
                jc eeerr
                ;***** Ok
        we1:
                mov a,r4
                call WrByte
                jc EeErr
                ;********** Delay
                call StopEe
                clr c
                mov ee24,c
                ret
RdEe:
                call EeAll
                jc EeErr
                ;********* Ok
                call StarEe
                mov a,#0a1H
                call WrByte
                jc Eeerr
                ;********** Ok
                call RdByte
                call McuNAck               
                call StopEe
                clr c
                mov ee24,c
                ret

mon51 发表于 2021-2-16 22:22

C51:
//定义EE24XX的管脚********************************
sbit        SCL        =P1^2;        //
sbit        SDA =P1^3;

/************************************************
延时程序
************************************************/
void nop_(void)
{
        unsigned char i=5;
        while (i--);       
}
/***********************************************
开始位
************************************************/
void Start_ee        (void)
{
        SDA=HIGH;
        nop_();
        SCL=HIGH;
        nop_();
        SDA=LOW;
        nop_();
        SCL=LOW;
        nop_();
}

/********************************
停止位
**********************************/
void Stop_ee        (void)
{
        SDA=LOW;
        nop_();
        SCL=HIGH;
        nop_();
        SDA=HIGH;
        nop_();
        SCL=LOW;
        nop_();
}

/*********************************
应答位,返回SDA信号
**********************************/
bit Ack(void)
{
        bit cy;
        SCL=HIGH;
        nop_();
        cy=SDA;
        SCL=LOW;
        nop_();
        return(cy);
}

/***********************************
主应答 返回SDA
************************************/
bit McuAck(void)
{
        bit cy;
        SDA=LOW;
        cy=Ack();
        SDA=HIGH;
        return(cy);
}

/************************************
不应答
*************************************/
void McuNAck(void)
{
        SDA=HIGH;
        SCL=HIGH;
        nop_();
        SCL=LOW;
        SDA=LOW;
}

/************************************
写入一个字节 ,返回成功标志
*************************************/
bit Wr_Byte(unsigned char Dat)
{
        unsigned char i;
        bit cy;
        for (i=0;i<8;i++)
        {
                if ((Dat & 0x80)==0x80) SDA=HIGH;
                        else        SDA=LOW;
                        cy=Ack();
                        Dat<<=1;
        }
        SDA=HIGH;
        return(Ack());
}

/**********************************
读取一个字节
***********************************/
unsigned char Rd_Byte(void)
{
                unsigned char i,j=0;
                for (i=0;i<8;i++)
                {
                        j<<=1;
                        if (Ack()) j++;
                }
                return j;
}

/*******************************************
EE24类型检测,返回标志位
********************************************/
unsigned char EeAll (unsigned int EeAdr)
{
        Start_ee();
        #if Ee_Type                                                        //1 EE24c32__
                   if (Wr_Byte(Wr_ee)) return 1;
                if (Wr_Byte((unsigned char)EeAdr>>8)) return 1;
                if (Wr_Byte((unsigned char)EeAdr)) return 1;
          #else
                   if (Wr_Byte((unsigned char)(EeAdr>>7 |Wr_ee))) return 1;                       
                if (Wr_Byte((unsigned char)EeAdr )) return 1;
   #endif
   return 0;
}

/****************************************************
连续写入字节,返回UINT8标志
*****************************************************/
unsigned char WriteEe24(unsigned int EeAdr,unsigned char *RamAdr,unsigned char Number)
{
        bit cy;
        if (EeAll(EeAdr)) return (0);
        while (Number--)
        {
                cy=Wr_Byte(*RamAdr++);       
        }
        Stop_ee();       
        Delay (10);

        return (1);                       
}

/****************************************************
连续读取,返回UINT8标志
*****************************************************/
unsigned char ReadEe24(unsigned int EeAdr,unsigned char *RamAdr,unsigned char Number)
{
        if (EeAll(EeAdr)) return (0);
        Start_ee();
        if (Wr_Byte(Rd_ee)) return (0);
        while (--Number)
        {
                *RamAdr++=Rd_Byte();
                McuAck();
        }
        *RamAdr=Rd_Byte();
        McuNAck();
        Stop_ee();
        return (1);
}
/**************************************************
每过10秒写入EE24
**************************************************/
void SaveEe24c512(void)
{
        unsigned char Buf,i;
        static unsigned char Flag=0;

        if ((UseData.Tm % WrSec) ==0)
        {
                if(Flag==0) //2004-7-9改FLAG
                {
                        Flag=1;        //写入标志

                        Buf=WorkData.Nu;
                        Buf=WorkData.Nu>>8;

                        i=WriteEe24(HeadAdr+2*Menu.Piont++,Buf,2);
               
                        if (Menu.Piont >= WrNumber)
                        {       
                                EndCount();                //溢出
                                UseData.ToBak=0;
                                UseData.To=0;
                                UseData.Tm=0;        //2004-4-18
                                Menu.Piont=0;
                                UseData.LedPower=Msg_Up;                //暂停放电
                        }
                }
        }
        else
        {
                Flag=0;
        }
}

mon51 发表于 2021-2-16 22:24

24C512:
                sda                bit p3.6
                scl                bit p3.7

                mov Sp,#50h
;*********************************************************
                type equ 0
   
;TYPE =0用EE24C01-EE24C16
;TYPE =1用EE24C32-EE24C512
;*********************************************************
;测试程序
;*********************************************************
tEST:
                mov a,#0eh
                call INput
               
                mov a,#type
                mov r0,#21h
                mov r1,#4
                call Wree
                call Delay
                call Delay

                mov a,#0h
                call INput

                mov a,#type
                mov r0,#21h
                mov r1,#8
                call Rdee               
                nop
                sjmp TEST
InPut:
                mov r7,#8
                mov r0,#21h
        lok1:
                mov @r0,a
                inc r0
                djnz r7,lok1
                ret
Delay:
                mov R7,#20
        de11:
                djnz b,$
                djnz R7,De11
                ret
               
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;子程序
;入口程序条件:
;A=0 用EE24C01-EE24C16
;A=1 用EE24C32-EE24C512
;DPTR =EE24XX的地址
;R0=MCU内部RAM的地址
;R1=读出(写入)数据的长度BYTE
;C=1操作失败
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Nop_:
                nop
                nop
                nop
                nop
                ret

StarEe:
                setb sda
                call Nop_
                setb scl
                call Nop_
                clr sda
                call Nop_
                clr scl
                ret
               
StopEe:
                clr sda
                call Nop_
                setb Scl
                call Nop_
                setb sda
                call Nop_
                clr scl
                ret

Ack:
                Call Nop_
                setb scl
                call Nop_
                mov c,sda
                call Nop_
                clr scl
                ret

McuAck:
                clr sda
                call Ack
                setb Sda
                ret
               
McuNAck:
                setb sda
                setb Scl
                call NOp_
                clr Scl
                clr Sda
                ret
               
WrByte:
                mov b,#8
        Wr11:
                rlc a
                mov sda,c
                call Ack
                djnz b,Wr11
                setb Sda
                call Ack
                ret
RdByte:
                mov b,#08
        Rd11:
                call Ack
                rlc a
                djnz b,Rd11
                ret

MakeAdr:
                mov a,dph
                rl a
                orl a,#0a0h
                ret
               
;*********************************
;a=0 =>24c16;=>24c32...
;r1=Long;R0=Adr;Dptr=EeAdr
;*********************************
EeAll:
                call StarEe
                jz Ee24c16
                ;*************
                ;Ee24c32
                mov a,#0a0h
                call WrByte
                jc EeErr
                mov a,dph
                call WrByte
                jc EeErr
                sjmp EeDo
        Ee24c16:
                mov a,#dph
                call MakeAdr
                call WrByte
        EeDo:
                mov a,Dpl
                call WrByte
                jc EeErr
                ret
        EeErr:
                nop
                ret
                                               
;)))))))))))))))))))))))))))))))))
WrEe: ;写子程序
                call EeAll
                jc eeerr
                ;***** Ok
        we1:
                mov a,@r0
                call WrByte
                jc EeErr
                ;********** Delay
                inc r0
                djnz r1,We1
                call StopEe
                clr c
                ret
RdEe:;读子程序
                call EeAll
                jc EeErr
                ;********* Ok
                call StarEe
                mov a,#0a1H
                call WrByte
                jc Eeerr
                ;********** Ok
                DEC R1
                mov a,r1
                jz Red11
        Red1:
                call RdByte
                call McuAck
                mov @r0,a
                inc r0
                djnz r1,Red1
        Red11:
                call RdByte
                MOV @R0,A
                call McuNAck               
                call StopEe
                clr c
                ret

mon51 发表于 2021-2-16 22:33

extern void Delay (unsigned int mS);
//void Wr_Ee24_Byte (unsigned int EeAdr,unsigned char Dat);
unsigned char ReadEe24(unsigned int EeAdr,unsigned char *RamAdr,unsigned char Number);
//定义EE24XX的管脚********************************
sbit        SCL        =P3^7;        // P3.7
sbit        SDA =P3^6;        //P3.6
/************************************************
延时程序
************************************************/
void nop_(void)
{
        unsigned char i=1;
        while (i--);       
}
/***********************************************
开始位
************************************************/
void Start_ee        (void)
{
        SDA=HIGH;
        nop_();
        SCL=HIGH;
        nop_();
        SDA=LOW;
        nop_();
        SCL=LOW;
        nop_();
}

/********************************
停止位
**********************************/
void Stop_ee        (void)
{
        SDA=LOW;
        nop_();
        SCL=HIGH;
        nop_();
        SDA=HIGH;
        nop_();
        SCL=LOW;
        nop_();
}

/*********************************
应答位,返回SDA信号
**********************************/
bit Ack(void)
{
        bit cy;
        SCL=HIGH;
        nop_();
        cy=SDA;
        SCL=LOW;
        nop_();
        return(cy);
}

/***********************************
主应答 返回SDA
************************************/
bit McuAck(void)
{
        bit cy;
        SDA=LOW;
        cy=Ack();
        SDA=HIGH;
        return(cy);
}

/************************************
不应答
*************************************/
void McuNAck(void)
{
        SDA=HIGH;
        SCL=HIGH;
        nop_();
        SCL=LOW;
        SDA=LOW;
}

/************************************
写入一个字节 ,返回成功标志
*************************************/
bit Wr_Byte(unsigned char Dat)
{
        unsigned char i;
        bit cy;
        for (i=0;i<8;i++)
        {
                if ((Dat & 0x80)==0x80) SDA=HIGH;
                        else        SDA=LOW;
                        cy=Ack();
                        Dat<<=1;
        }
        SDA=HIGH;
        return(Ack());
}

/**********************************
读取一个字节
***********************************/
unsigned char Rd_Byte(void)
{
                unsigned char i,j=0;
                for (i=0;i<8;i++)
                {
                        j<<=1;
                        if (Ack()) j++;
                }
                return j;
}

/*******************************************
EE24类型检测,返回标志位
********************************************/
unsigned char EeAll (unsigned int EeAdr)
{
        Start_ee();
        #if Ee_Type                                                        //1 EE24c32__
                   if (Wr_Byte(Wr_ee)) return 1;
                if (Wr_Byte((unsigned char)EeAdr>>8)) return 1;
                if (Wr_Byte((unsigned char)EeAdr)) return 1;
          #else
                   if (Wr_Byte(((unsigned char)EeAdr>>7) |Wr_ee )) return 1;                       
                if (Wr_Byte((unsigned char)EeAdr )) return 1;
   #endif
   return 0;
}

/****************************************************
连续写入字节,返回UINT8标志
*****************************************************/
unsigned char WriteEe24(unsigned int EeAdr,unsigned char *RamAdr,unsigned char Number){
        unsigned char i;
        ReadEe24(EeAdr,&i,Number);

        if(i==*RamAdr)        return 0;
        if (EeAll(EeAdr)) return 0;
        while (Number--)         {
                Wr_Byte(*RamAdr++);       
        }
        Stop_ee();       
        Delay (3500);
        return 1;                       
}

/****************************************************
连续读取,返回UINT8标志
*****************************************************/
unsigned char ReadEe24(unsigned int EeAdr,unsigned char *RamAdr,unsigned char Number){
        if (EeAll(EeAdr)) return 0;
        Start_ee();
        if (Wr_Byte(Rd_ee)) return 0;
        while (--Number)        {
                *RamAdr++=Rd_Byte();
                McuAck();
        }
        *RamAdr=Rd_Byte();
        McuNAck();
        Stop_ee();
        return 1;
}
//***********************************************************************************
//2006-11-28添加 比较写入数据是否相同!
/*
void Wr_Ee24_Byte (unsigned int EeAdr,unsigned char Dat){
        if (EeAll(EeAdr)) return;
        Wr_Byte(Dat);       
        Stop_ee();       
        Delay (6000);
}
*/


cyradg 发表于 2021-2-16 23:19

dqp05 发表于 2021-2-16 22:07
给楼主一个建议:用示波器看波形,时序要严格,误差不能太大;

不会汇编。{:5_604:}已经上示波器了,写进去看波形好像没问题,但是读被我修改的面目全非,看示波器,发出起始信号、片选信号以后,后续的内存地址,内存数据都发不出去,也不能STOP,原先都可以的,现在都不行了,好像也没改多少呀,哎,I2C真TMD啰嗦。
页: [1] 2
查看完整版本: 请教各位I2C对24C02写完后无法立即读的问题