搜索
bottom↓
回复: 18

谁有ATMEGA128读取AT24C128的完整程序,我调试一个星期也未成功

[复制链接]

出0入0汤圆

发表于 2008-5-13 20:07:44 | 显示全部楼层 |阅读模式
谁有ATMEGA128读取AT24C128的完整程序,我调试一个星期也未成功

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2008-5-13 20:10:00 | 显示全部楼层
先说说你确定你明白M128如何使用I2C,以及I2C接口EEPROM的操作协议了没?

出0入0汤圆

 楼主| 发表于 2008-5-13 20:59:41 | 显示全部楼层
是这样的,我把128的说明书看了,参考别人的例子子并结合自己的写.发现程序并无错误,但就是写不进去.急死了.帮我分析一下吧,拜托,谢谢!
II.C////////////////////////////////////////////////////////////////////////////////

//-------------------------------以下为其它I2总线器件可调用的函数--------------------------

//总线上起动开始条件
void i2cstart(void)
{
        TWCR= BIT(TWINT) | BIT(TWSTA) | BIT(TWEN);
           while (!(TWCR & BIT(TWINT)));
}

//把一个字节数据输入器件, 返回TWI状态
uchar i2cwt(uchar a)
{
        TWDR = a;
           TWCR = BIT(TWINT) | BIT(TWEN);
           while (!(TWCR & BIT(TWINT)));
           _NOP();
           return(TWSR&0b11111000);
}

//i2c读要调用的函数
//从器件读出一个字节
uchar i2crd(void)
{
           TWCR= BIT(TWINT) | BIT(TWEA) | BIT(TWEN);
           while (!(TWCR & BIT(TWINT)));
           return(TWDR);
}


//总线上起动停止条件
void i2cstop(void)
{
   TWCR = BIT(TWINT) | BIT(TWSTO) | BIT(TWEN);
}

/*16M晶振时钟*/
/*微秒级延时1~65535us*/
void tus(uint t)
{   uint m=t/2;
        m--;        
        asm("nop");        asm("nop");
        for(;m!=0;m--)        
        {
                asm("nop");        asm("nop");        asm("nop");
                asm("nop");        asm("nop");        asm("nop");
                asm("nop");        asm("nop");        asm("nop");
        }
}

/*16M晶振时钟*/
/*毫秒级延时1~65535ms*/
void tms(uint t)
{    uint m=t/2;
        for(;m!=0;m--)        
                tus(1000);
}

void twi_init(void)
{
TWCR= 0X00; //disable twi
TWBR= 0x64; //set bit rate
TWSR= 0x00; //set prescale
TWAR= 0x00; //set slave address
TWCR= 0x04; //enable twi
}
void wt24c(uchar *p_rsc, uint ad_dst, uint num)
{   uint n;

    n=ad_dst/PAGE_SIZE;                //确定地址与块地址的差
        if(n) n=(ulong)PAGE_SIZE*(n+1)-ad_dst;       
        else n=PAGE_SIZE-ad_dst;
               
    if(n>=num)                //如果ad_dst所在的数据块的末尾地址 >= ad_dst + num, 就直接写入num个数据
    {        wt24c_fc(p_rsc, ad_dst, num);
            if(syserr!=0) return;
    }
    else                        //如果ad_dst所在的数据块末尾地址 < ad_dst + num, 就先写入ad_dst所在的数据块末尾地址与 ad_dst 之差个数据
    {   p_rsc=wt24c_fc(p_rsc, ad_dst, n);
            if(syserr!=0) return;
               
                num-=n;     //更新剩下数据个数
        ad_dst+=n;        //更新剩下数据的起始地址

        //把剩下数据写入器件
        while(num>=PAGE_SIZE)        //先按PAGE_SIZE为长度一页一页的写入
        {        p_rsc=wt24c_fc(p_rsc, ad_dst, PAGE_SIZE);
                if(syserr!=0) return;
               
            num-=PAGE_SIZE;                //更新剩余数据个数
                ad_dst+=PAGE_SIZE;        //更新剩下数据的起始地址
                }
        
                if(num)                        //把最后剩下的小于一个PAGE_SIZE长度的数据写入器件
                        wt24c_fc(p_rsc, ad_dst, num);
    }
}


//从24cxx读出数据
//参数: *p_dst要读入数据的主机内存地址指针; ad_rsc要输出数据的i2c的地址(整形); num数据个数(整形)
//参数条件:  ad_dst+(num-1)不能大于器件的最高地址; num必须>0;
void rd24c(uchar *p_dst, uint ad_rsc, uint num)
{   uchar t=0;

        #if e2prom<32
        t=ad_rsc>>8;
        t<<=1;
        #endif
               
        i2cstart();                                        //发送起始信号
               
        if(i2cwt(W_ADD_COM+t)==SLAW)//发送SLA_W, 写字节命令及器件地址
        {       
                #if e2prom>16
                i2cwt(ad_rsc>>8);                //ad_rsc的高位,  发送要读出数据的地址
                #endif
                i2cwt(ad_rsc);                        //ad_rsc的低位
                               
                i2cstart();                                //再发送起始信号
                i2cwt(R_ADD_COM+t);                //发送SLA_R, 读命令字节及器件地址
                               
                for(;num>0;num--)
                {   *p_dst=i2crd();                //从器件读出一个字节
                        p_dst++;
                }
        }
        else syserr=ERR_SLAW;                //写字节命令及器件地址错或对方无应答
               
        i2cstop();

}



//向24Cxx写入数据wt24c_h()所要调用的函数
//返回写入n个字节后的主机内存指针
uchar * wt24c_fc(uchar *p, uint ad, uchar n)
{        uchar t=0;

        #if e2prom<32
        t=ad>>8;
        t<<=1;
        #endif
       
        i2cstart();                                        //发送起始信号
               
        if(i2cwt(W_ADD_COM+t)==SLAW)//发送SLA_W, 写字节命令及器件地址
        {       
                #if e2prom>16
                i2cwt(ad>>8);                        //ad_dst的高位到器件
                #endif
                i2cwt(ad);                                //ad_dst的低位到器件
                       
                for(;n>0;n--)                        //发送要写入的数据
                {   i2cwt(*p);
                        p++;
                }
        }
        else syserr=ERR_SLAW;                //写字节命令及器件地址错
       
        i2cstop();
    tms(16);                                                //延时6ms
       
        return(p);
}



////////////////////////////////////////////////////////////////////////
IIC.H

#define ulong        unsigned long
#define uint        unsigned int
#define uchar        unsigned char

#define ERR_10 10
#define e2prom 128                // <---在此设定芯片型号, 1代表24C01; 16代表24C16; 512代表24C512

#if e2prom==1
        #define PAGE_SIZE 8
        #define SIZE 0x007f
#elif e2prom==2
        #define PAGE_SIZE 8
        #define SIZE 0x00ff
#elif e2prom==4
        #define PAGE_SIZE 16
        #define SIZE 0x01ff
#elif e2prom==8
        #define PAGE_SIZE 16
        #define SIZE 0x03ff
#elif e2prom==16
        #define PAGE_SIZE 16
        #define SIZE 0x07ff
#elif e2prom==32
        #define PAGE_SIZE 32
        #define SIZE 0x0fff
#elif e2prom==64
        #define PAGE_SIZE 32
        #define SIZE 0x1fff
#elif e2prom==128
        #define PAGE_SIZE 64
        #define SIZE 0x3fff
#elif e2prom==256
        #define PAGE_SIZE 64
        #define SIZE 0x7fff
#elif e2prom==512
        #define PAGE_SIZE 128
        #define SIZE 0xffff
#endif
//--------------------------

//--------在此设定芯片地址-------
#define W_ADD_COM 0xa0        //写字节命令及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 0
#define R_ADD_COM 0xa1        //读命令字节及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 1
//-------------------------------



#define SLAW        0x18        //SLA_W 已正常发送代码,判断器件是否正常应答的常量.

//-----在此改变预置错误号-----
#define ERR_SLAW        ERR_10        //写字节命令及器件地址错, 在此也就是读写器件错!!
//---------------------------



//-----------4个I2总线公用函数, 可供其它I2总线器件的程序调用--------------
void i2cstart(void);        //总线上起动开始条件
uchar i2cwt(uchar a);        //把一个字节数据输入器件, 返回TWI状态
uchar i2crd(void);                //i2c读要调用的函数
void i2cstop(void);                //总线上起动停止条件
//------------------------------------------------------------------------
//向24Cxx写入数据
//参数: *p_rsc要输出数据的主机内存地址指针; ad_dst要写入数据的i2c的地址(双字节); num数据个数
//参数条件: ad_dst: ad_dst+(num-1)不能大于器件的最高地址; num必须>0;
void wt24c(uchar *p_rsc, uint ad_dst, uint num);

//从24cxx读出数据
//参数: *p_dst要读入数据的主机内存地址指针; ad_rsc要输出数据的i2c的地址(整形); num数据个数(整形)
//参数条件:  ad_dst+(num-1)不能大于器件的最高地址; num必须>0;
void rd24c(uchar *p_dst, uint ad_rsc, uint num);

//向24Cxx写入数据wt24c_h()所要调用的函数
//返回写入n个字节后的主机内存指针
uchar * wt24c_fc(uchar *p, uint ad, uchar n);

/*微秒级延时1~65535us*/
void tus(uint t) ;

/*毫秒级延时1~65535ms*/
void tms(uint t);
uchar * wt24c_fc(uchar *p, uint ad, uchar n);
void rd24c(uchar *p_dst, uint ad_rsc, uint num);
void wt24c(uchar *p_rsc, uint ad_dst, uint num);

////////////////////////////////////////////////////////////
MAIN.C

uchar syserr;   
uchar r_buf[8];//读缓冲
uchar w_buf[8]= {2,2,2,2,2,2,2,2};//写缓冲
main()
{
uchar u,i;
     uchar *r;
     uint b;
     uint c;
        uchar *w;
        uint x;
        uint y;

       
        CLI();
    tms(10000);
    twi_init();
        MCUCR |=BIT(SRE);//启动128三总线结构
    //SEI();
       
     r=r_buf;        //读参数
     b=0x20;
     c=8;

     w=w_buf;        //写参数
     x=0x20;
     y=8;
         
         wt24c(w,x,y);        //写
         rd24c(r,b,c);        //读
         for(i=0;i<8;i++)                //清主机读和写缓存区
         time_buf=r_buf;
}

发现写不进去?

出0入0汤圆

发表于 2008-5-13 22:32:42 | 显示全部楼层
建议你还是找我编写的书参考一下.在I2C部分有使用多种方法的多个例程可供参考学习.

如果你"参考"的是51的例子,多数要不成功的.

出0入0汤圆

 楼主| 发表于 2008-5-14 07:49:56 | 显示全部楼层
我试了,也不成功.快绝望了

出0入0汤圆

 楼主| 发表于 2008-5-14 08:10:32 | 显示全部楼层
请教马老师
我参考的就是本网站http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=544794&bbs_page_no=1&sub_kind_id=2065&bbs_id=1000
M16读写24系列的程序呀,不是51的.
拜托指教一下

出0入0汤圆

发表于 2008-5-14 13:25:57 | 显示全部楼层
似乎是寻址格式有问题
如果你参照的是24C06的话寻址格式是8位的
128的应该是16位
如果还按06的程序操作是读写无效的

出0入0汤圆

发表于 2008-5-14 13:39:15 | 显示全部楼层
什么是"参考"别人的程序?连基本的知识都不明白就照搬!这样的参考,还是不参考的好.

出0入0汤圆

 楼主| 发表于 2008-5-14 19:15:16 | 显示全部楼层
程序中不是有8位和16位寻址之分吗?
#if e2prom>16
                i2cwt(ad>>8);                        //ad_dst的高位到器件
                #endif
                i2cwt(ad);                                //ad_dst的低位到器件
                        
我把程序按TWI的过程一步一步调试.发现应答ACK信号有变化(不同的几次).
请教马老师:我需要明白的知识在哪一点?多谢

出0入0汤圆

发表于 2008-5-15 13:27:24 | 显示全部楼层
1.I2C通信规程
2.24C128的命令和操作方式.

如果你是使用CVAVR的话,先使用它提供的I2C函数,实现对24C128的操作,然后尝试使用TWI的硬件.建议认真阅读我书中的相关章节内容,并参考相关的例程.

出0入0汤圆

 楼主| 发表于 2008-5-15 15:23:42 | 显示全部楼层
马老师您好;
我参考你书中的例子了,改为读24C256.程序如下;
/////////////////////////////////////////////////////////////////
                      I2C.H
///////////////////////////////////////////////////////////////


#define ulong        unsigned long
#define uint        unsigned int
#define uchar        unsigned char

#define ERR_10 10
#define e2prom 256                // <---在此设定芯片型号, 1代表24C01; 16代表24C16; 512代表24C512

#if e2prom==1
        #define page_size 8
        #define SIZE 0x007f
#elif e2prom==2
        #define page_size 8
        #define SIZE 0x00ff
#elif e2prom==4
        #define page_size 16
        #define SIZE 0x01ff
#elif e2prom==8
        #define page_size 16
        #define SIZE 0x03ff
#elif e2prom==16
        #define page_size 16
        #define SIZE 0x07ff
#elif e2prom==32
        #define page_size 32
        #define SIZE 0x0fff
#elif e2prom==64
        #define page_size 32
        #define SIZE 0x1fff
#elif e2prom==128
        #define page_size 64
        #define SIZE 0x3fff
#elif e2prom==256
        #define page_size 64
        #define SIZE 0x7fff
        #define page_mask page_size-1
#elif e2prom==512
        #define PAGE_SIZE 128
        #define SIZE 0xffff
#endif
//--------------------------

//--------在此设定芯片地址-------
#define EEPROM_BUS_ADDRESS 0xa0        //写字节命令及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 0
#define R_ADD_COM 0xa1        //读命令字节及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 1

//-------------------------------


#define TW_START                        0x08
#define TW_REP_START                0x10
#define TW_MT_SLA_ACK        0x18
#define TW_MT_SLA_NACK        0x20
#define TW_MT_DATA_ACK                0x28
#define TW_MT_DATA_NACK        0x30

#define TW_MT_ARB_LOST                0x38
#define TW_MR_ARB_LOST        0x38
#define TW_MR_SLA_ACK                0x40
#define TW_MR_SLA_NACK        0x48
#define TW_MR_DATA_ACK                0x50
#define TW_MR_DATA_NACK        0x58


char I2C_start(void);        //总线上起动开始条件
void I2C_stop(void);                //总线上起动停止条件

uchar I2C_write(uchar c);
uchar I2C_read(uchar ack);
uchar eeprom_read(uint address);
void eeprom_write(uint address,uchar data);
void EEProm_page_write(uint addr,uchar n,uchar *arr);
void EEProm_write(uint addr,uchar n,uchar *arr);
void EEProm_read(uint addr,uchar n,uchar *arr);

/*16M晶振时钟*/
/*微秒级延时1~65535us*/
void tus(uint t) ;
/*16M晶振时钟*/
/*毫秒级延时1~65535ms*/
void tms(uint t);
void I2C_init(void);


/////////////////////////////////////////////////////////////////////////
                      I2C.C
uchar eeprom_read(uint address)
{uchar data;
I2C_start();
I2C_write(EEPROM_BUS_ADDRESS);
I2C_write(address>>8);
I2C_write(address);
I2C_start();
I2C_write(EEPROM_BUS_ADDRESS|1);
data=I2C_read(0);
I2C_stop();
return data;
}
//////////////////////////////
void eeprom_write(uint address,uchar data)
{
I2C_start();
I2C_write(EEPROM_BUS_ADDRESS);
I2C_write(address>>8);
I2C_write(address);
I2C_write(data);
I2C_stop();
tms(100);
}
/////////////////////////////
void EEProm_page_write(uint addr,uchar n,uchar *arr)
{uchar i;
I2C_start();
I2C_write(EEPROM_BUS_ADDRESS);
I2C_write(addr>>8);
I2C_write(addr);
for(i=1;i<=n;i++)
{I2C_write(*arr);
arr++;
}
I2C_stop();
tms(100);
}

///////////////////////////////
void EEProm_write(uint addr,uchar n,uchar *arr)
{uchar n_tmp;
n_tmp=page_size-(uchar)(addr&page_mask);
if((n>n_tmp)&&(n_tmp!=0))
{EEProm_page_write(addr,n_tmp,arr);
addr+=n_tmp;
n-=n_tmp;
arr+=n_tmp;
}
while(n>=page_size)
{EEProm_page_write(addr,page_size,arr);
addr+=page_size;
n-=page_size;
arr+=page_size;
}
if(n!=0)
EEProm_page_write(addr,n,arr);
}

/////////////////////////////////////

void EEProm_read(uint addr,uchar n,uchar *arr)
{
uchar i;
I2C_start();
I2C_write(EEPROM_BUS_ADDRESS);
I2C_write(addr>>8);
I2C_write(addr);
I2C_start();
I2C_write(EEPROM_BUS_ADDRESS|1);

for(i=1;i<=n-1;i++)
{*arr=I2C_read(1);
arr++;
}
*arr=I2C_read(0);
I2C_stop();
}



//总线上起动开始条件
char I2C_start(void)
{ TWCR= BIT(TWINT) | BIT(TWSTA) | BIT(TWEN);
  while (!(TWCR & BIT(TWINT))){};
  return 1;
}
//把一个字节数据输入器件
uchar I2C_write(uchar c)
{ uchar ack=1;
  TWDR = c;
    TWCR = BIT(TWINT) | BIT(TWEN);
    while (!(TWCR & BIT(TWINT))){};
    if((TWSR&0xF8)!=TW_MT_SLA_ACK)
        ack=0;
        return ack;
}
//i2c读要调用的函数
//从器件读出一个字节
uchar I2C_read(uchar ack)
{   if(ack)
    TWCR= BIT(TWINT) | BIT(TWEA) | BIT(TWEN);
        else
        TWCR= BIT(TWINT)| BIT(TWEN);
    while (!(TWCR & BIT(TWINT))){};
    return(TWDR);
}

//总线上起动停止条件
void I2C_stop(void)         
{
   TWCR = BIT(TWINT) | BIT(TWSTO) | BIT(TWEN);
}
/**************TWI初始化*****************/
void I2C_init(void)
{
TWCR= 0x00; //disable twi
TWBR= 0x0A; //set bit rate
TWSR= 0x00; //set prescale
TWAR= 0x00; //set slave address
TWCR= 0x44; //enable twi

}

/*16M晶振时钟*/
/*微秒级延时1~65535us*/
void tus(uint t)
{   uint m=t/2;
        m--;        
        asm("nop");        asm("nop");
        for(;m!=0;m--)        
        {
                asm("nop");        asm("nop");        asm("nop");
                asm("nop");        asm("nop");        asm("nop");
                asm("nop");        asm("nop");        asm("nop");
        }
}

/*16M晶振时钟*/
/*毫秒级延时1~65535ms*/
void tms(uint t)
{    uint m=t/2;
        for(;m!=0;m--)        
                tus(1000);
}


/////////////////////////////////////////////////////////////////////////  
                 main.c

uchar r_buf[8];//读缓冲
uchar w_buf[8]= {0x00,0x08,0x05,0x13,0x22,0x50,0x20,0x08};
r=r_buf;        //读参数
     b=0x00;
     c=8;

     w=w_buf;        //写参数
     x=0x00;
     y=8;
         tms(10000);
    I2C_init();
         
         EEProm_write(0x0aa,8,w);
         EEProm_read(0x0aa,8,r)


结果还是不出来呀
快崩溃了
求马老师指点一下
谢谢

出0入0汤圆

发表于 2008-5-15 16:16:07 | 显示全部楼层
查查硬件吧

出0入0汤圆

 楼主| 发表于 2008-5-15 19:07:23 | 显示全部楼层
我的硬件是A0,A1,NC,WP接地呀.线路都是通的

出0入0汤圆

发表于 2008-7-23 18:04:26 | 显示全部楼层
我从AT24C128英文datasheet上得知,对其read和控制字节后,并不需要再次用Start和写入地址的呀?
为什么会有2次Start操作呢?

出0入0汤圆

发表于 2008-7-23 18:04:26 | 显示全部楼层
我从AT24C128英文datasheet上得知,对其read和控制字节后,并不需要再次用Start和写入地址的呀?
为什么会有2次Start操作呢?

出0入0汤圆

发表于 2008-7-23 18:33:37 | 显示全部楼层
唉,ICC的库里有I2C的程序,你调用就可以了,方便省事,如果近的点话,给我帮你搞,一天时间可以搞定,都是基础的东西。

出0入0汤圆

发表于 2008-7-23 20:09:26 | 显示全部楼层
踏实,认真。

你就按我书中的例子,一步一步前进。

先写一个字节,然后读出来看对不对。一个字节如果都不行,后面也别下去了。
1。采用平台自带的函数,使用I/O模拟
2。自己编写底层函数,使用I/O模拟
3。自己编写底层函数,使用TWI硬件接口

每次都自己弄明白,这样你才能真正掌握。

出0入0汤圆

发表于 2008-7-24 08:55:42 | 显示全部楼层
我觉得LZ还是先搞清楚I2C的控制原理,这样就
只需要看一下数据手册就可以了,而且换任何一
款单片机都是一样自己能做,要不然,每次都
只有参考别人的!

出0入0汤圆

发表于 2008-7-24 09:16:43 | 显示全部楼层
顶起来
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-29 11:24

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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