這個程序我檢測過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
|