找回密码
 立即注册

QQ登录

只需一步,快速开始

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

[原创]51一个24C读写函数,支持检测器件型号

[复制链接]
跳转到指定楼层
楼主
ID:43499 发表于 2012-8-2 21:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
 

        这个程序我检测过24C02,24C16,24C04,24C64,24C32,均未出错。也没有毁损器件内部数据的问题。可靠性比较好。在我的编程器中已经使用。此程序write by 万致远,在sdcc v3.1.0中无错误/warning编译。死太惨89C52中通过。

上代码:


/* FILE 24C.C
Write by 万致远
*/
#include <hwconfig.h>
#include <type-def.h>
#include <delay.h>
#include <i2c.h>
#include <24c.h>
#define AT24C02_DeviceAdd_W 0xa0    //器件地址(写)
#define AT24C02_DeviceAdd_R 0xa1    //器件地址(读)
#define ADD_TYPE_8    0
#define ADD_TYPE_16    1
#define AT24C01        0
#define AT24C02        1
#define AT24C04        2
#define AT24C08        3
#define AT24C16        4
#define AT24C32        5
#define AT24C64        6
#define AT24C128    7
#define AT24C256    8
#define AT24C512    9
#define AT24C1024    10
#define SCAN_ERROR    0xFF
ULONG __code Length_Chip[11]={
0x7f,0xff,0x1ff,0x3ff,0xfff,0x7ff,0x1fff,0x3fff,0x7fff,0xffff,0x1ffff
};//各类ROM的容量表~    
BYTE __code TEST_DATA[2]={0xAA,0xBB};    //测试数据
#define W_DELAY 4   //4 ms DELAY         
//----------------------------------------------
//24C操作函数,页写。
//IIC_ADDR器件地址
//Address 16BIT地址
//TYPE    地址模式
//Data指针
//Len长度
//本函数不支持翻页,请自行翻页,控制IIC_Addr
BOOL RW24(BYTE IIC_Addr,UINT Address,BOOL Type,BYTE *Data,BYTE Len)
{
    BYTE i=0;
    //----------------------------选中芯片程序开始-----------
    I2C_Start();    // 启动I2C总线
    I2C_Write8Bit(IIC_Addr & 0xFE);                    // 发送器件地址(写)1111 1110
    if( I2C_Check_Ack() == 0 )                        // 检测从机应答
            {I2C_Stop();return 0;      }
    if (Type==ADD_TYPE_8)
    {//8位地址的话
        I2C_Write8Bit(Address);                   // 发送将要处理的数据的地址,8位
    }
    else
    {//16位地址的话
        I2C_Write8Bit(((Address & 0xFF00)>>8));            //发送高八位地址
        if( I2C_Check_Ack() == 0 )                        // 检测从机应答
            {I2C_Stop();return 0;      }
        I2C_Write8Bit((Address & 0xFF));    //低八位地址发送
    }
    if( I2C_Check_Ack() == 0 )                        // 检测从机应答
            {I2C_Stop();return 0;      }
    //---------------------------------结束-------------------
    if((IIC_Addr & 0x01)==1)
    {//是读操作
        *Data=0xFF;                                    //FF=NULL
        I2C_Start();                                 // 再次启动IIC总线
        I2C_Write8Bit(IIC_Addr);                    //发送读出地址
        if( I2C_Check_Ack() == 0 )                // 检测从机应答
            {I2C_Stop();return 0;      }
        *Data = I2C_Read8Bit();                        // 读取第一个数据
        Data++;
        for(i=1;i<Len;i++)
        {
            I2C_Send_Bit_0();//发送ACK
            *Data = I2C_Read8Bit();    //读取数据
            Data++;//指针加一
        }                    
        I2C_Send_Bit_1();                             // 产生NAK信号结束读取数据            
        I2C_Stop();    
        return 1;
    }
    else
    {//是写操作
        for(i=0;i<Len;i++)
        {
            I2C_Write8Bit(*Data);
            //I2C_Write8Bit(0xff);
            if(I2C_Check_Ack()==0) {I2C_Stop();return 0;}
            Data++;
        }
        I2C_Stop();
        Delay_ms(W_DELAY);//加延时啊……要不然写不进……型号也会判断错误……5~6MS
        return 1;
    }
}
//---------------------------------------------------------------------------------------
//测试24C系列8BIT地址的一页,检测24C02~24C16
BOOL Page_Test(BYTE Page)
{
    BYTE tmp[3];
    RW24(AT24C02_DeviceAdd_R,0x00,ADD_TYPE_8,&tmp[0],1);//读出原来数据
    RW24(AT24C02_DeviceAdd_R|Page,0x00,ADD_TYPE_8,&tmp[1],1);
    RW24(AT24C02_DeviceAdd_W,0x00,ADD_TYPE_8,&TEST_DATA[1],1);//修改数据写入00单元1页
    RW24(AT24C02_DeviceAdd_W|Page,0x00,ADD_TYPE_8,&TEST_DATA[0],1);//修改数据写入00单元2页
    RW24(AT24C02_DeviceAdd_R,0x00,ADD_TYPE_8,&tmp[2],1);//读入
    RW24(AT24C02_DeviceAdd_W,0x00,ADD_TYPE_8,&tmp[0],1);//写回数据
    if(tmp[2]==0xAA)
    {//24C02
        //RW24(AT24C02_DeviceAdd_W,0x00,ADD_TYPE_8,&tmp[0],1);//写回数据
        return TRUE;
    }
                //RW24(AT24C02_DeviceAdd_W,0x00,ADD_TYPE_8,&tmp[0],1);//写回数据
    RW24(AT24C02_DeviceAdd_W|Page,0x00,ADD_TYPE_8,&tmp[1],1);    
    return FALSE;
}
//------------------------------------------------------------------------------------------------------
//--检测24C32器件的地址溢出
//BOOL RW24(BYTE IIC_Addr,UINT Address,BOOL Type,BYTE *Data);
//ADDRESS 2为猜测的最高地址
BOOL Write_Test(UINT Address2,BOOL Add_Type)
{
    BYTE tmp[3];
    RW24(AT24C02_DeviceAdd_R,0,Add_Type,&tmp[0],1);//读出0x0000单元数据
    RW24(AT24C02_DeviceAdd_R,Address2,Add_Type,&tmp[1],1);//读出0x1000单元数据
    RW24(AT24C02_DeviceAdd_W,0,Add_Type,&TEST_DATA[1],1);//改变原有数据,避免干扰
    RW24(AT24C02_DeviceAdd_W,Address2,Add_Type,&TEST_DATA[0],1);//写入0xAA到单元去,产生地址溢出
    RW24(AT24C02_DeviceAdd_R,0,Add_Type,&tmp[2],1);//读出0000单元内容
    RW24(AT24C02_DeviceAdd_W,0,Add_Type,&tmp[0],1);//写回数据
    if(tmp[2]==0xAA)//先前改变的数据,如果产生溢出可以检测到
    {
                //RW24(AT24C02_DeviceAdd_W,0x0000,Add_Type,&tmp[0],1);//写回被(1)步骤更改的数据
                return TRUE;//返回正确
    }
            //RW24(AT24C02_DeviceAdd_W,0x0000,ADD_TYPE_16,&tmp[0],1);//写回数据
    RW24(AT24C02_DeviceAdd_W,Address2,Add_Type,&tmp[1],1);//写回数据
    return FALSE;
}
//------------调用此函数返回芯片类型
BYTE Test24()
{//测试24系列的容量
//24C16:Address=1010 P2 P1 P0 R/W

    BYTE tmp[3];
    //
     // read:
    //  8 Bit series: |start|address_w|address|start|address_r|data|stop|
     // 16 bit series:|start|address_w|address|address|start|address_r|data|stop|
    //  TEST:         |START|address_w|address|start|address_r|data|stop|
    //  write:
    //  8bit series:  |start|address_w|address|data|stop|
    //  16bit series: |start|address_w|address|address|data|stop|
     // 
     tmp[0]=0xff;
    if(RW24(AT24C02_DeviceAdd_R,0x00,ADD_TYPE_8,&tmp[0],1)==TRUE)//读出0单元
    {//判断是否是8bit series
        RW24(AT24C02_DeviceAdd_W,0x00,ADD_TYPE_8,&TEST_DATA[1],1);//写入AA
        RW24(AT24C02_DeviceAdd_R,0x00,ADD_TYPE_8,&tmp[1],1);//再次读出        
        if(tmp[1]==0xBB)
        {//8bit series无误
        //我发现我还是在实际上出错了%……实际上写页还是写的进可是只有一个页……
            RW24(AT24C02_DeviceAdd_W,0x00,ADD_TYPE_8,&tmp[0],1);//写回数据,RW搞错了
            //测试是否24C01
            //24C01的地址范围从0~127(0~7F),OK,向80H读出,然后写一个数据
            /*RW24(AT24C02_DeviceAdd_R,0x0000,ADD_TYPE_8,&tmp[0],1);//读出0x0000单元数据【0】
            RW24(AT24C02_DeviceAdd_R,0x0080,ADD_TYPE_8,&tmp[1],1);//读出0x80单元数据【1】
            RW24(AT24C02_DeviceAdd_W,0x0000,ADD_TYPE_8,&TEST_DATA[1],1);//写入0000单元防止原来数据干扰
            RW24(AT24C02_DeviceAdd_W,0x0080,ADD_TYPE_8,&TEST_DATA[0],1);//写入0000单元防止原来数据干扰
            RW24(AT24C02_DeviceAdd_R,0x0000,ADD_TYPE_8,&tmp[2],1);//写入0000单元防止原来数据干扰
            RW24(AT24C02_DeviceAdd_W,0x0000,ADD_TYPE_8,&tmp[0],1);//写回0单元数据
            if(tmp[2]==0xAA)
            {//24C01

                return AT24C01;
            }*/
            if(Write_Test(0x80,ADD_TYPE_8))
            {
                return AT24C01;
            }
                //这应该是24C02 etc……绝对不可能是24C01,除非器件的80H单元正好坏了
                //24C16:Address=1010 P2 P1 P0 R/W
                //RW24(AT24C02_DeviceAdd_W,0x00,ADD_TYPE_8,&tmp[0],1);//写回原来的数据到0x80
                //RW24(AT24C02_DeviceAdd_W,0x80,ADD_TYPE_8,&tmp[1],1);//写回原来的数据0x00
                //----------------------------------------------------------------
                //MAX——PAGE 02 04  08  16
                //         000 001 011 111
                //-------TEST 24C02
                if(Page_Test(0x02))
                {
                    return AT24C02;
                }
                if(Page_Test(0x06))
                {
                    return AT24C04;
                }
                if(Page_Test(0x0E))
                {
                    return AT24C08;
                }
                return AT24C16;    
        }
        else
        {//AT24C32的地址范围从0~4095(0xFFF)
        //AT24C64从0~8191(0x1FFF)
        //AT24C128从0~16383(0x3FFF)
        //AT24C256从0~32767(0x7FFF)
        //AT24C512从0~65535(0xFFFF)
        //AT24C1024从0~65535(0xFFFF),地址中多一个P1选择位
        //从小试到大
        //测试24C1024
        //1010 0010 = 0x02
        //就是产生传说中的地址溢出了……
        //-----24C1024
            if(RW24(AT24C02_DeviceAdd_R | 0x02,0xFFFF,ADD_TYPE_16,&tmp[0],1))//读出第二页的0xFFFE
            {//成功代表是24C1024
                return AT24C1024;
            }
        //优化算法
        //-----24C32
            if(Write_Test(0x1000,ADD_TYPE_16))
            {
                return AT24C32;
            }
        //24C64
            if(Write_Test(0x2000,ADD_TYPE_16))
            {
                return AT24C64;
            }
        //24C128
            if(Write_Test(0x4000,ADD_TYPE_16))
            {
                return AT24C128;
            }
        //24C256
            if(Write_Test(0x8000,ADD_TYPE_16))
            {
                return AT24C32;
            }
            //-------------24C512*/
            return  AT24C512;

        }
        
    }
    else
    {
        return SCAN_ERROR;
    }
}

万致远原创,转载注明出处:http://www.rwzy.co.cc

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

使用道具 举报

沙发
ID:43499 发表于 2012-8-2 21:40 | 只看该作者
 这个在我的编程器项目KMPROG中应用成功。
如果需要使用STC"1T"的单片机请适量加延时。
另外需要I2C.H
[此贴子已经被作者于2012-8-2 21:40:26编辑过]
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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