淺談如果通過程序讀取AT24系列芯片型號(hào)
對(duì)于以上問題,我們想大家都有不同的看法,但是,不知道您是否真正嘗試過呢?能正確讀取AT24C01到AT24C1024之間的各種型號(hào)嗎?
為了解決這個(gè)問題,本人思考了好幾天,以通過多種實(shí)驗(yàn)去驗(yàn)證,今天終于獲取結(jié)果了,不過本人先聲明,我這里只有3中類型的卡(C02, C16, C64),每種類型有2張或以上,驗(yàn)證都是正確的。如果你有其他類型的卡不妨也試試,如果嘗試了,請(qǐng)把結(jié)果告訴本人,在下先謝了。
下面我們先談?wù)勥@類芯片的一些基礎(chǔ)知識(shí),得到這些基礎(chǔ)知識(shí)后,看您能否想出解決這個(gè)問題的方法,再看看方法是否和我一樣的。
對(duì)于24C系列的IC卡來說,其讀寫操作完全和24C系列芯片的讀寫操作一致,所有,下面我們就以此系列芯片為基礎(chǔ)進(jìn)行介紹。對(duì)于這系列芯片的資料特別多而且也非常詳細(xì),下面我們就借《嵌入式實(shí)時(shí)操作系統(tǒng)Small RTOS51原理及應(yīng)用》中的第20章串行E2PROM芯片Cat24WCxx驅(qū)動(dòng)程序的內(nèi)容來描述。 雖然這一章中講的芯片不是ATMEL的,但是和這一系列完全兼容。 1. 參數(shù)表 2. 器件地址表 3. 數(shù)據(jù)地址表 3.png(92.89 KB, 下載次數(shù): 0) 本文引用地址:http://www.biyoush.com/article/201611/317396.htm下載附件保存到相冊(cè) 2013-10-25 07:58 上傳 4. 操作時(shí)序 |
1. 不同型號(hào)其容量不同;
2. 不同型號(hào)的頁寫入不同;
3. 不同型號(hào)的擴(kuò)展數(shù)量不同。
還可以看出,對(duì)于24C01/02/04/08/16的數(shù)據(jù)地址只有1字節(jié),而24C32/64/128/256等的數(shù)據(jù)地址為兩字節(jié)。我們仔細(xì)想想發(fā)現(xiàn),1字節(jié)的數(shù)據(jù)地址對(duì)于24C01/02剛好夠用,而對(duì)于24C04/08/16來說卻不夠用,所以,還必須配合器件地址實(shí)現(xiàn)讀寫操作。
至此,您是否想出分別型號(hào)的方法?
想法1:通過訪問器件的最高地址實(shí)現(xiàn).
我們知道AT24C01的最大容量為1Kbit,以就是128字節(jié),如果我們讀寫128以后的地址不正確,我們就可以確定這個(gè)芯片的型號(hào)就為AT24C01了。如果用同樣的方法,從大到小的訪問,應(yīng)該就可以區(qū)分這一系列芯片的不同型號(hào)了。
有了想法,那我們不妨試試吧。。。。。。。
結(jié)果如何呢?你是否猜到了?
。。。
通過驗(yàn)證我們可以獲得結(jié)論:不管是什么型號(hào)的芯片都可以正確讀寫,根本無法分辨這一系列。24C01/02以及24C32/64/128/256無法通過24C04/08/16的程序,但其他程序都可以操作。而24C04/08/16可以通過全部型號(hào)的讀寫操作。
也就是說:我們只能把這一系列芯片分為兩大類,而無法分辨其型號(hào)。
奇怪,這個(gè) 問題是怎樣產(chǎn)生的呢?
查看芯片資料我們不難發(fā)現(xiàn),如果讀寫操作超過芯片地址,它是不會(huì)返回錯(cuò)誤的,而是地址回卷,又從最小的地址開始,所以,就是你寫入地址超過芯片范圍也無法獲取錯(cuò)誤。
至于24C04/08/16能夠通過各個(gè)型號(hào)芯片的讀寫程序,是以為,這三個(gè)芯片的地址有特殊性。在讀寫超過8位地址的地方是通過與頁地址配合實(shí)現(xiàn)的,以就是說這三個(gè)芯片的地址是由:0xA* + 8Bit構(gòu)成;而24C01/02的地址是由0xA0 + 8位地址構(gòu)成;24C32/64/128/256的地址是由:0xA0 + 16位地址構(gòu)成。
由這三個(gè)地址可以看出,由于24C04/08/16支持0xA*地址,所以可以通過各種格式的讀取,而其他兩類不支持0xA0以外的地址,所以當(dāng)通過24C04/08/16程序讀寫這兩類芯片時(shí)就會(huì)出現(xiàn)錯(cuò)誤。當(dāng)然24C04/08/16這三個(gè)芯片的地址由有些區(qū)別,例如04的只有1位,08的有2位,16的有3位,我們可以通過程序進(jìn)一步區(qū)分這三個(gè)型號(hào)。
我們知道AT24C01的最大容量為1Kbit,以就是128字節(jié),如果我們讀寫128以后的地址不正確,我們就可以確定這個(gè)芯片的型號(hào)就為AT24C01了。如果用同樣的方法,從大到小的訪問,應(yīng)該就可以區(qū)分這一系列芯片的不同型號(hào)了。
有了想法,那我們不妨試試吧。。。。。。。
結(jié)果如何呢?你是否猜到了?
。。。
通過驗(yàn)證我們可以獲得結(jié)論:不管是什么型號(hào)的芯片都可以正確讀寫,根本無法分辨這一系列。24C01/02以及24C32/64/128/256無法通過24C04/08/16的程序,但其他程序都可以操作。而24C04/08/16可以通過全部型號(hào)的讀寫操作。
也就是說:我們只能把這一系列芯片分為兩大類,而無法分辨其型號(hào)。
奇怪,這個(gè) 問題是怎樣產(chǎn)生的呢?
查看芯片資料我們不難發(fā)現(xiàn),如果讀寫操作超過芯片地址,它是不會(huì)返回錯(cuò)誤的,而是地址回卷,又從最小的地址開始,所以,就是你寫入地址超過芯片范圍也無法獲取錯(cuò)誤。
至于24C04/08/16能夠通過各個(gè)型號(hào)芯片的讀寫程序,是以為,這三個(gè)芯片的地址有特殊性。在讀寫超過8位地址的地方是通過與頁地址配合實(shí)現(xiàn)的,以就是說這三個(gè)芯片的地址是由:0xA* + 8Bit構(gòu)成;而24C01/02的地址是由0xA0 + 8位地址構(gòu)成;24C32/64/128/256的地址是由:0xA0 + 16位地址構(gòu)成。
由這三個(gè)地址可以看出,由于24C04/08/16支持0xA*地址,所以可以通過各種格式的讀取,而其他兩類不支持0xA0以外的地址,所以當(dāng)通過24C04/08/16程序讀寫這兩類芯片時(shí)就會(huì)出現(xiàn)錯(cuò)誤。當(dāng)然24C04/08/16這三個(gè)芯片的地址由有些區(qū)別,例如04的只有1位,08的有2位,16的有3位,我們可以通過程序進(jìn)一步區(qū)分這三個(gè)型號(hào)。
想法2:通過頁讀寫操作實(shí)現(xiàn).
我們知道,不同型號(hào)其頁大小是有區(qū)別的,當(dāng)操作超過頁面時(shí),芯片或滾動(dòng)覆蓋,我們可以通過寫入最大頁面數(shù)據(jù),根據(jù)讀取的數(shù)據(jù)可以知道其滾動(dòng)狀態(tài),從而讀取芯片頁面大小。
但是,AT24C01的頁字節(jié)為8,AT24C02/04/08/16的頁字節(jié)為16,AT24C32/64的頁字節(jié)為32,AT24C128/256的頁字節(jié)為64,所以我們只能分出這4類芯片,還是無法實(shí)現(xiàn)所有型號(hào)的判別。
我們知道,不同型號(hào)其頁大小是有區(qū)別的,當(dāng)操作超過頁面時(shí),芯片或滾動(dòng)覆蓋,我們可以通過寫入最大頁面數(shù)據(jù),根據(jù)讀取的數(shù)據(jù)可以知道其滾動(dòng)狀態(tài),從而讀取芯片頁面大小。
但是,AT24C01的頁字節(jié)為8,AT24C02/04/08/16的頁字節(jié)為16,AT24C32/64的頁字節(jié)為32,AT24C128/256的頁字節(jié)為64,所以我們只能分出這4類芯片,還是無法實(shí)現(xiàn)所有型號(hào)的判別。
通過上面的想法和實(shí)際可以得出,以上兩種方法都很難實(shí)現(xiàn)對(duì)這一系列芯片的正確讀取。下面我們通過連續(xù)寫入多字節(jié)進(jìn)行試驗(yàn)。
例如:同時(shí)在芯片的最后幾個(gè)空間內(nèi)同時(shí)寫入4字節(jié)的數(shù)據(jù):復(fù)制代碼通過以上試驗(yàn)可以發(fā)現(xiàn),讀寫24C02和24C16已經(jīng)沒有問題,完全可以爭(zhēng)取的區(qū)分這兩類芯片。但還是不能讀取24C64之類的芯片。
進(jìn)一步修改代碼:
我們知道,由于芯片超地址時(shí)會(huì)出現(xiàn)覆蓋寫入,那么我們能不能把基礎(chǔ)可能會(huì)出現(xiàn)覆蓋的地方寫入不同值了,如果發(fā)現(xiàn)覆蓋就可以說明這個(gè)型號(hào)是錯(cuò)的,如果沒有覆蓋就說這個(gè)型號(hào)是對(duì)的:復(fù)制代碼通過上面的代碼驗(yàn)證獲得,現(xiàn)在可以區(qū)別出24C64了,但卻不能區(qū)別出24C02/16等。為什么會(huì)這樣呢?連續(xù)的讀寫可以區(qū)別24C02/16但不能區(qū)別24C64,現(xiàn)在雖然能區(qū)別24C64了,可其他的反而不行了,能否把這種方法和連續(xù)寫入多字節(jié)組合呢?復(fù)制代碼通過上面的代碼修改和試驗(yàn),我們現(xiàn)在可以區(qū)別這三種型號(hào)了,通過我的推算應(yīng)該是這種方法已經(jīng)可以讀取這一系列的各種型號(hào),不過由于本人手里只有這3種卡片,其他的沒有辦法試驗(yàn)。
至于為什么這樣寫可以實(shí)現(xiàn),本人也還沒有一個(gè)完整的理論依據(jù),大家不妨一起想想,如果你先想出來,請(qǐng)告訴我一下。
例如:同時(shí)在芯片的最后幾個(gè)空間內(nèi)同時(shí)寫入4字節(jié)的數(shù)據(jù):
- u8 tmpBuf[] = {0x00, 0x00, 0x00, 0x00};
- u8 tmpDat[] = {0xAA, 0x55, 0xFF, 0x00};
- ATReadDat(type, addr-3, tmpBuf, 4); // 數(shù)據(jù)暫存
- ATWriteDat(type, addr-3, tmpDat, 4); // 寫入驗(yàn)證數(shù)據(jù)
- memset(tmpDat, 0, 4);
- ATReadDat(type, addr-3, tmpDat, 4); // 讀取驗(yàn)證數(shù)據(jù)
- ATWriteDat(type, addr-3, tmpBuf, 4); // 恢復(fù)寫入前
- return ((memcmp(tmpDat, "xAAx55xFFx00", 4) == 0) ? 0x00 : 0x01);
進(jìn)一步修改代碼:
我們知道,由于芯片超地址時(shí)會(huì)出現(xiàn)覆蓋寫入,那么我們能不能把基礎(chǔ)可能會(huì)出現(xiàn)覆蓋的地方寫入不同值了,如果發(fā)現(xiàn)覆蓋就可以說明這個(gè)型號(hào)是錯(cuò)的,如果沒有覆蓋就說這個(gè)型號(hào)是對(duì)的:
- u8 tmpBuf[] = {0x00, 0x00};
- u8 tmpDat[] = {0xAA, 0x55};
- ATReadDat(type, ((addr+1)/2)-1, &tmpBuf[0], 1); // 數(shù)據(jù)暫存
- ATReadDat(type, addr, &tmpBuf[1], 1);
- ATWriteDat(type, ((addr+1)/2)-1, &tmpDat[0], 1);
- ATWriteDat(type, addr, &tmpDat[1], 1); // 寫入驗(yàn)證數(shù)據(jù)
- memset(tmpDat, 0, 2);
- ATReadDat(type, ((addr+1)/2)-1, &tmpDat[0], 1);
- ATReadDat(type, addr, &tmpDat[1], 1); // 讀取驗(yàn)證數(shù)據(jù)
- ATWriteDat(type, ((addr+1)/2)-1, &tmpBuf[0], 1); // 恢復(fù)寫入前
- ATWriteDat(type, addr, &tmpBuf[1], 1);
- return ((memcmp(tmpDat, "xAAx55", 2) == 0) ? 0x00 : 0x01);
- u8 tmpBuf[] = {0x00, 0x00, 0x00, 0x00};
- u8 tmpDat[] = {0xAA, 0x55, 0xFF, 0x00};
- ATReadDat(type, ((addr+1)/2)-2, &tmpBuf[0], 2); // 數(shù)據(jù)暫存
- ATReadDat(type, addr-1, &tmpBuf[2], 2);
- ATWriteDat(type, ((addr+1)/2)-2, &tmpDat[0], 2);
- ATWriteDat(type, addr-1, &tmpDat[2], 2); // 寫入驗(yàn)證數(shù)據(jù)
- memset(tmpDat, 0, 4);
- ATReadDat(type, ((addr+1)/2)-2, &tmpDat[0], 2);
- ATReadDat(type, addr-1, &tmpDat[2], 2); // 讀取驗(yàn)證數(shù)據(jù)
- ATWriteDat(type, ((addr+1)/2)-2, &tmpBuf[0], 2); // 恢復(fù)寫入前
- ATWriteDat(type, addr-1, &tmpBuf[2], 2);
- return ((memcmp(tmpDat, "xAAx55xFFx00", 4) == 0) ? 0x00 : 0x01);
至于為什么這樣寫可以實(shí)現(xiàn),本人也還沒有一個(gè)完整的理論依據(jù),大家不妨一起想想,如果你先想出來,請(qǐng)告訴我一下。
以上的程序卻是能夠?qū)崿F(xiàn)型號(hào)辨別,但一個(gè)新的問題出現(xiàn)了。例如:向24C02等單地址卡片里邊寫入雙地址數(shù)據(jù)時(shí),由于時(shí)序的不同,芯片處理時(shí),會(huì)把雙地址的第2字節(jié)作為數(shù)據(jù)寫入到單地址芯片中,由于我們的程序沒有考慮這一點(diǎn),所以,會(huì)導(dǎo)致其他地址的數(shù)據(jù)出現(xiàn)錯(cuò)誤。
下面我們舉例說明:
用上面的程序,我們判別型號(hào)的順序是256->128->64->32->16->08->04->02->01,寫入的地址是芯片的最大地址的最后兩個(gè)字節(jié)和芯片最大地址的一半的最后兩個(gè)字節(jié),這樣做的目的是試圖通過數(shù)據(jù)覆蓋來判斷型號(hào),例如,如果最大地址的最后兩個(gè)字節(jié)覆蓋了一半的最后兩個(gè)字節(jié),固然不是這個(gè)型號(hào)。
所以在按照24c256來想AT24C02寫入數(shù)據(jù)是,我們是通過在地址:16382(0x3FFE)寫入兩個(gè)字節(jié)(0xAA, 0x55),再在地址32766(7FFE)寫入兩個(gè)字節(jié)(0xFF, 0x00),通過讀取整片AT24C02芯片獲得:
[48] = 0xAA,
[49] = 0x55,
[63] = 0xFE,
[112] = 0xFF,
[113] = 0x00,
[127] = 0xFE,
通過仔細(xì)分析我們發(fā)現(xiàn),芯片處理時(shí),首先把地址16382(0x3FFE)分為2字節(jié)處理,高字節(jié)為地址即63(0x3F),低字節(jié)為數(shù)據(jù)0xFE,再加上AT24C02的頁面大小為16字節(jié),地址0x3F已經(jīng)是頁面的最高地址,后面再寫入數(shù)據(jù)時(shí)就會(huì)發(fā)生頁面翻轉(zhuǎn)現(xiàn)象,而頁面的起始地址正好是48(0x30),故而后面發(fā)生的兩字節(jié)數(shù)據(jù)就寫入了48和49.
后面兩個(gè)字節(jié)的數(shù)據(jù)也是完全一致的現(xiàn)象,所以,這個(gè)程序破壞來原始數(shù)據(jù)。
下面我們舉例說明:
用上面的程序,我們判別型號(hào)的順序是256->128->64->32->16->08->04->02->01,寫入的地址是芯片的最大地址的最后兩個(gè)字節(jié)和芯片最大地址的一半的最后兩個(gè)字節(jié),這樣做的目的是試圖通過數(shù)據(jù)覆蓋來判斷型號(hào),例如,如果最大地址的最后兩個(gè)字節(jié)覆蓋了一半的最后兩個(gè)字節(jié),固然不是這個(gè)型號(hào)。
所以在按照24c256來想AT24C02寫入數(shù)據(jù)是,我們是通過在地址:16382(0x3FFE)寫入兩個(gè)字節(jié)(0xAA, 0x55),再在地址32766(7FFE)寫入兩個(gè)字節(jié)(0xFF, 0x00),通過讀取整片AT24C02芯片獲得:
[48] = 0xAA,
[49] = 0x55,
[63] = 0xFE,
[112] = 0xFF,
[113] = 0x00,
[127] = 0xFE,
通過仔細(xì)分析我們發(fā)現(xiàn),芯片處理時(shí),首先把地址16382(0x3FFE)分為2字節(jié)處理,高字節(jié)為地址即63(0x3F),低字節(jié)為數(shù)據(jù)0xFE,再加上AT24C02的頁面大小為16字節(jié),地址0x3F已經(jīng)是頁面的最高地址,后面再寫入數(shù)據(jù)時(shí)就會(huì)發(fā)生頁面翻轉(zhuǎn)現(xiàn)象,而頁面的起始地址正好是48(0x30),故而后面發(fā)生的兩字節(jié)數(shù)據(jù)就寫入了48和49.
后面兩個(gè)字節(jié)的數(shù)據(jù)也是完全一致的現(xiàn)象,所以,這個(gè)程序破壞來原始數(shù)據(jù)。
判斷出卡片型號(hào)是必須的,但絕對(duì)不能破壞數(shù)據(jù),為此我們還必須想辦法解決這一問題:
下面我們談?wù)劻硗庖凰悸罚和ㄟ^頁和地址來實(shí)現(xiàn)。
我們知道AT24C01為8字節(jié)一頁, AT24C02/04/08/16為16字節(jié)一頁, AT24C32/64為32字節(jié)為一頁, AT24C128/256為64字節(jié)為一頁。我們完全可以通過寫頁數(shù)據(jù),通過判斷是否有數(shù)據(jù)被覆蓋實(shí)現(xiàn),過程如下:
寫入16字節(jié)數(shù)據(jù)->讀寫一致為AT24C02/04/08/16中一種,否則判斷8字節(jié)是否一致,一致為AT24C01,否則為其他->通過寫最大地址判斷是否覆蓋,來判斷究竟是AT24C02/04/08/16中的那一致。其他型號(hào)過程一致,代碼如下:復(fù)制代碼具體代碼不再分析,代碼確實(shí)能夠?qū)崿F(xiàn)型號(hào)識(shí)別,但是否破壞數(shù)據(jù),暫時(shí)還沒有發(fā)現(xiàn),大家不妨試試,如果破壞了數(shù)據(jù),我們?cè)僮鲞M(jìn)一步分析并改善。
下面我們談?wù)劻硗庖凰悸罚和ㄟ^頁和地址來實(shí)現(xiàn)。
我們知道AT24C01為8字節(jié)一頁, AT24C02/04/08/16為16字節(jié)一頁, AT24C32/64為32字節(jié)為一頁, AT24C128/256為64字節(jié)為一頁。我們完全可以通過寫頁數(shù)據(jù),通過判斷是否有數(shù)據(jù)被覆蓋實(shí)現(xiàn),過程如下:
寫入16字節(jié)數(shù)據(jù)->讀寫一致為AT24C02/04/08/16中一種,否則判斷8字節(jié)是否一致,一致為AT24C01,否則為其他->通過寫最大地址判斷是否覆蓋,來判斷究竟是AT24C02/04/08/16中的那一致。其他型號(hào)過程一致,代碼如下:
- ATC_TYP ATCReadType(void)
- {
- u8 i;
- u8 tmpBuf[64] = {0};
- u8 tmpDat[64] = {0};
- u8 cmpDat[64] = {0};
- //--------------------------------- 單地址判斷 -----------------------------
- for (i=0; i<16; i++) // 初始化
- {
- tmpDat[i] = i;
- cmpDat[i] = i;
- }
- // AT24C01的頁為8字節(jié),AT24C02/04/08/16的頁為16字節(jié)
- // 通過讀寫16來判斷頁大小,從而區(qū)分AT24C01
- ATCReadNByte(AT24C02, 0, tmpBuf, 16); // 數(shù)據(jù)暫存
- ATCWriteNByte(AT24C02, 0, tmpDat, 16); // 寫入驗(yàn)證數(shù)據(jù)
- memset(tmpDat, 0, 16);
- ATCReadNByte(AT24C02, 0, tmpDat, 16); // 讀驗(yàn)證數(shù)據(jù)
- if (memcmp(tmpDat, cmpDat, 16) == 0) // AT24C02/04/08/16
- {
- ATCWriteNByte(AT24C02, 0, tmpBuf, 16); // 恢復(fù)數(shù)據(jù)
- // AT24C02/04/08/16中,通過頁地址共同組成地址,故可以通過頁區(qū)別型號(hào)
- for (i=4; i>0; i--)
- {
- ATCReadByte((ATC_TYP)(i), ATC_Par[(ATC_TYP)(i)].MaxAddr, &tmpDat[0]);
- ATCWriteByte((ATC_TYP)(i), ATC_Par[(ATC_TYP)(i)].MaxAddr, 0xAA);
- ATCReadByte((ATC_TYP)(i), ATC_Par[(ATC_TYP)(i)].MaxAddr, &tmpDat[1]);
- if (tmpDat[1] == 0xAA)
- {
- ATCWriteByte((ATC_TYP)(i), ATC_Par[(ATC_TYP)(i)].MaxAddr, tmpDat[0]);
- return ((ATC_TYP)(i));
- }
- }
- }
- else
- {
- if (memcmp(&tmpDat[8], cmpDat, 8) == 0) // AT24C01
- {
- ATCWriteNByte(AT24C01, 0, tmpBuf, 8); // 恢復(fù)數(shù)據(jù)
- return AT24C01;
- }
- }
- //--------------------------------- 雙地址判斷 -----------------------------
- for (i=0; i<64; i++) // 初始化
- {
- tmpDat[i] = i;
- cmpDat[i] = i;
- }
- ATCReadNByte(AT24C128, 0, tmpBuf, 64); // 數(shù)據(jù)暫存
- ATCWriteNByte(AT24C128, 0, tmpDat, 64); // 寫入驗(yàn)證數(shù)據(jù)
- memset(tmpDat, 0, 64);
- ATCReadNByte(AT24C128, 0, tmpDat, 64); // 讀驗(yàn)證數(shù)據(jù)
- if (memcmp(tmpDat, cmpDat, 64) == 0) // AT24C128/256
- {
- ATCWriteNByte(AT24C128, 0, tmpBuf, 64); // 恢復(fù)數(shù)據(jù)
- ATCReadByte(AT24C256, 0, &tmpDat[0]);
- ATCReadByte(AT24C256, ATC_Par[AT24C128].Capacity, &tmpDat[1]);
- ATCWriteByte(AT24C256, 0, 0xAA);
- ATCWriteByte(AT24C256, ATC_Par[AT24C128].Capacity, 0x55);
- ATCReadByte(AT24C256, 0, &tmpDat[2]);
- ATCReadByte(AT24C256, ATC_Par[AT24C128].Capacity, &tmpDat[3]);
- if ((tmpDat[2] == 0xAA) && (tmpDat[3] == 0x55))
- {
- ATCWriteByte(AT24C256, 0, tmpDat[0]);
- ATCWriteByte(AT24C256, ATC_Par[AT24C128].Capacity, tmpDat[1]);
- return AT24C256;
- }
- else
- {
- ATCWriteByte(AT24C128, 0, tmpDat[0]);
- return AT24C128;
- }
- }
- else // AT24C128/256
- {
- if (memcmp(&tmpDat[32], cmpDat, 32) == 0)
- {
- ATCWriteNByte(AT24C64, 0, tmpBuf, 32);
- ATCReadByte(AT24C64, 0, &tmpDat[0]);
- ATCReadByte(AT24C64, ATC_Par[AT24C32].Capacity, &tmpDat[1]);
- ATCWriteByte(AT24C64, 0, 0xAA);
- ATCWriteByte(AT24C64, ATC_Par[AT24C32].Capacity, 0x55);
- ATCReadByte(AT24C64, 0, &tmpDat[2]);
- ATCReadByte(AT24C64, ATC_Par[AT24C32].Capacity, &tmpDat[3]);
- if ((tmpDat[2] == 0xAA) && (tmpDat[3] == 0x55))
- {
- ATCWriteByte(AT24C64, 0, tmpDat[0]);
- ATCWriteByte(AT24C64, ATC_Par[AT24C32].Capacity, tmpDat[1]);
- return AT24C64;
- }
- else
- {
- ATCWriteByte(AT24C32, 0, tmpDat[0]);
- return AT24C32;
- }
- }
- }
- return ATC_TYP_MAX;
- }
下面我們?cè)俳榻B一種比較簡(jiǎn)單,而且不會(huì)破壞數(shù)據(jù)的方法。
我們知道從AT24C01~256之間,由于容量和地址的區(qū)別,我們可以把這一系列分為三大類:
1. 單地址,直接8位地址操作:AT24C01/02
2. 單地址,8位地址加3位頁地址組合操作:AT24C04/08/16
3. 雙地址,直接16位地址操作:AT24C32/64/128/256
由上面的三大類我們可以看出,要區(qū)別型號(hào),可以通過先分類,再分別通過每一類中型號(hào)的差異進(jìn)行進(jìn)一步的區(qū)別。
首先我們可以看出,從地址上來分可以把以上芯片分為單地址和雙地址,從頁面組合上來分我們可以把他們分為有組合和無組合兩種,所以,我們可以通過這兩種方法先把這系列芯片分為2類,之后再進(jìn)行細(xì)分。例如:
從地址上來分->單地址為AT24C01/02/04/08/16,雙地址為AT24C32/64/128/256:
1. 單地址5種芯片,有頁組合的有3種,這三種中 AT24C16由3位組合,AT24C08由2位組合,AT24C04由一位組合,所以當(dāng)我們讀寫0xAE地址正確時(shí)一定是AT24C16,如果不正確,讀寫0xA6正確時(shí)一定是AT24C08,如果還不正確,讀寫0xA2正確時(shí)一定是AT24C04,如果還不正確那,一定是AT24C01/02中的一種,而對(duì)于AT24C01/02來說,不同的只是地址范圍,如果寫地址0和地址128,如果數(shù)據(jù)覆蓋,那一定是AT24C01,如果沒有覆蓋那一定是AT24C02.
2. 雙地址4種芯片,沒有也組合,而不同的只有地址范圍,這一定和AT24C01/02是完全一致的,所以,由于區(qū)別的方法也和這兩個(gè)芯片一樣,通過覆蓋可以輕松的判斷出芯片型號(hào)。復(fù)制代碼
我們知道從AT24C01~256之間,由于容量和地址的區(qū)別,我們可以把這一系列分為三大類:
1. 單地址,直接8位地址操作:AT24C01/02
2. 單地址,8位地址加3位頁地址組合操作:AT24C04/08/16
3. 雙地址,直接16位地址操作:AT24C32/64/128/256
由上面的三大類我們可以看出,要區(qū)別型號(hào),可以通過先分類,再分別通過每一類中型號(hào)的差異進(jìn)行進(jìn)一步的區(qū)別。
首先我們可以看出,從地址上來分可以把以上芯片分為單地址和雙地址,從頁面組合上來分我們可以把他們分為有組合和無組合兩種,所以,我們可以通過這兩種方法先把這系列芯片分為2類,之后再進(jìn)行細(xì)分。例如:
從地址上來分->單地址為AT24C01/02/04/08/16,雙地址為AT24C32/64/128/256:
1. 單地址5種芯片,有頁組合的有3種,這三種中 AT24C16由3位組合,AT24C08由2位組合,AT24C04由一位組合,所以當(dāng)我們讀寫0xAE地址正確時(shí)一定是AT24C16,如果不正確,讀寫0xA6正確時(shí)一定是AT24C08,如果還不正確,讀寫0xA2正確時(shí)一定是AT24C04,如果還不正確那,一定是AT24C01/02中的一種,而對(duì)于AT24C01/02來說,不同的只是地址范圍,如果寫地址0和地址128,如果數(shù)據(jù)覆蓋,那一定是AT24C01,如果沒有覆蓋那一定是AT24C02.
2. 雙地址4種芯片,沒有也組合,而不同的只有地址范圍,這一定和AT24C01/02是完全一致的,所以,由于區(qū)別的方法也和這兩個(gè)芯片一樣,通過覆蓋可以輕松的判斷出芯片型號(hào)。
- /**************************************************************************************
- * FunctionName : ATCReadType()
- * Description : 寫器件型號(hào)
- * EntryParameter : None
- * ReturnValue : None
- **************************************************************************************/
- u8 ATCReadType(void)
- {
- u8 i;
- u8 tmpBuf[3] = {0};
- u8 tmpDat[3] = {0};
- ATCReadNByte(AT24C32, 0, tmpBuf, 1); // 讀取雙地址0的一字節(jié)暫存
- ATCReadNByte(AT24C16, 0, &tmpBuf[1], 2); // 讀取單地址0的二字節(jié)暫存
- ATCWriteNByte(AT24C32, 0, "xA5", 1); // 按照雙地址格式寫入一字節(jié)數(shù)據(jù)
- ATCReadNByte(AT24C32, 0, tmpDat, 1); // 按照雙地址格式讀取一字節(jié)數(shù)據(jù)
- ATCReadNByte(AT24C16, 0, &tmpDat[1], 2); // 按照單地址格式讀取二字節(jié)數(shù)據(jù)
- if ((tmpDat[1] == 0x00) && (tmpDat[2] == 0xA5)) // 單地址芯片
- {
- ATCWriteNByte(AT24C16, 0, &tmpBuf[1], 2); // 恢復(fù)數(shù)據(jù)
- //-------------------------------- AT24c04/08/16 -----------------------
- for (i=AT24C16; i>AT24C02; i--) // AT24c04/08/16
- {
- ATCReadByte(i, ATC_Par[i].MaxAddr, &tmpBuf[0]);
- ATCWriteByte(i, ATC_Par[i].MaxAddr, 0xAA);
- ATCReadByte(i, ATC_Par[i].MaxAddr, &tmpDat[0]);
- ATCWriteByte(i, ATC_Par[i].MaxAddr, tmpBuf[0]);
- if (tmpDat[0] == 0xAA)
- {
- return i;
- }
- }
- //-------------------------------- AT24c01/02 --------------------------
- ATCReadByte(AT24C02, 0, &tmpBuf[0]);
- ATCReadByte(AT24C02, 128, &tmpBuf[1]);
- ATCWriteByte(AT24C02, 0, 0xAA);
- ATCWriteByte(AT24C02, 128, 0x55);
- ATCReadByte(AT24C02, 0, &tmpDat[0]);
- ATCReadByte(AT24C02, 128, &tmpDat[1]);
- ATCWriteByte(AT24C02, 0, tmpBuf[0]);
- ATCWriteByte(AT24C02, 128, tmpBuf[1]);
- return (tmpDat[0] == 0x55) ? AT24C01 : AT24C02;
- }
- else
- {
- if (tmpDat[0] == 0xA5) // 雙地址芯片
- {
- ATCWriteNByte(AT24C256, 0, &tmpBuf[0], 1); // 恢復(fù)數(shù)據(jù)
- //-------------------------------- AT24c32/64/128/256 --------------
- for (i=AT24C256; i>AT24C16; i--)
- {
- ATCReadByte(i, 0, &tmpBuf[0]);
- ATCReadByte(i, ATC_Par[i-1].Capacity, &tmpBuf[1]);
- ATCWriteByte(i, 0, 0xAA);
- ATCWriteByte(i, ATC_Par[i-1].Capacity, 0x55);
- ATCReadByte(i, 0, &tmpDat[0]);
- ATCReadByte(i, ATC_Par[i-1].Capacity, &tmpDat[1]);
- ATCWriteByte(i, 0, tmpBuf[0]);
- ATCWriteByte(i, ATC_Par[i-1].Capacity, tmpBuf[1]);
- if ((tmpDat[0] == 0xAA) && (tmpDat[1] == 0x55))
- {
- return i;
- }
- }
- return AT24C256;
- }
- else // 非AT系列芯片
- {
- return ATC_TYP_MAX;
- }
- }
- }
對(duì)于上面的程序需要注意,我們的方法是通過寫入數(shù)據(jù)之后讀取進(jìn)行判斷的,所以在寫入數(shù)據(jù)之前必須把要寫入的地址數(shù)據(jù)暫存,完成判斷后必須恢復(fù),絕對(duì)不能破壞芯片類的數(shù)據(jù)。
在單地址和雙地址的判斷中,我們按照兩種方法進(jìn)行數(shù)據(jù)暫存,因?yàn)槲覀儎傞_始并不知道卡片究竟是什么型號(hào),所以,在判斷出來后,按照單雙地址分別恢復(fù)也保證數(shù)據(jù)的正確性。
還有一點(diǎn)需要強(qiáng)調(diào),我們?cè)诎凑针p地址方式,在地址0的地方寫入0xA5數(shù)據(jù),如果芯片確實(shí)是雙地址,那么該數(shù)據(jù)一定寫入地址0,數(shù)據(jù)數(shù)據(jù)為0xA5,但是如果該芯片為單地址,那么地址的低8為就被作為數(shù)據(jù)一起寫入了,所以會(huì)導(dǎo)致,地址0開始寫入兩字節(jié)數(shù)據(jù),一字節(jié)為0(地址的低8位被當(dāng)做第一個(gè)數(shù)據(jù)了),一字節(jié)為0xA5(數(shù)據(jù)卻作為第2字節(jié)數(shù)據(jù)寫入了)。所以通過這兩字節(jié)數(shù)據(jù)可以輕松的判斷出究竟是單地址還是雙地址。
在單地址和雙地址的判斷中,我們按照兩種方法進(jìn)行數(shù)據(jù)暫存,因?yàn)槲覀儎傞_始并不知道卡片究竟是什么型號(hào),所以,在判斷出來后,按照單雙地址分別恢復(fù)也保證數(shù)據(jù)的正確性。
還有一點(diǎn)需要強(qiáng)調(diào),我們?cè)诎凑针p地址方式,在地址0的地方寫入0xA5數(shù)據(jù),如果芯片確實(shí)是雙地址,那么該數(shù)據(jù)一定寫入地址0,數(shù)據(jù)數(shù)據(jù)為0xA5,但是如果該芯片為單地址,那么地址的低8為就被作為數(shù)據(jù)一起寫入了,所以會(huì)導(dǎo)致,地址0開始寫入兩字節(jié)數(shù)據(jù),一字節(jié)為0(地址的低8位被當(dāng)做第一個(gè)數(shù)據(jù)了),一字節(jié)為0xA5(數(shù)據(jù)卻作為第2字節(jié)數(shù)據(jù)寫入了)。所以通過這兩字節(jié)數(shù)據(jù)可以輕松的判斷出究竟是單地址還是雙地址。
評(píng)論