C51IO口模擬I2C總線驅(qū)動(dòng)AT24C16 (EEPROM部分)
出處:eefocus 引用地址:http://www.eeworld.com.cn/mcu/2018/i 發(fā)布于:2018-07-21 13:57:54
名稱:C51IO口模擬I2C總線驅(qū)動(dòng)AT24C16
說明:關(guān)于EEPROM,即這里的AT24C16是一個(gè)特殊形式的FLASH存儲(chǔ)器,不過其容量一般較少。比較適合于存儲(chǔ)少量的數(shù)據(jù)。
AT24C16的通信接口是標(biāo)準(zhǔn)的I2C通信,即我們需要根據(jù)I2C通信協(xié)議來操縱EEPROM設(shè)備。 關(guān)于AT24C16的的各種操作,這里就不細(xì)講了,簡(jiǎn)單介紹一下。
?。?)、主機(jī)向AT24C16寫一個(gè)字節(jié):首先需要發(fā)送設(shè)備地址,然后發(fā)送需要訪問的存儲(chǔ)器地址。然后在發(fā)送要寫入的數(shù)據(jù)。這里省略了開始、結(jié)束和確認(rèn)等信號(hào)的產(chǎn)生。
?。?)、指定頁寫入n個(gè)字節(jié):和(1)的基本操作很類似。不同的是可以連續(xù)寫入n個(gè)數(shù)據(jù)。這里要小注意一點(diǎn)的就是,寫入的數(shù)據(jù)如果到達(dá)頁邊界(即n超過16字節(jié))就會(huì)產(chǎn)生回滾,也就是重新從頁的開始處寫入,這樣的話可能會(huì)覆蓋到原來的數(shù)據(jù)。 本程序的指定頁的實(shí)現(xiàn)是從頁開始處寫入的,當(dāng)然也可以從任何地址開始寫入數(shù)據(jù),不過還是要注意頁邊界的問題。
(3)、主機(jī)隨機(jī)從AT24C16讀一個(gè)字節(jié):這里的操作步驟先是主機(jī)向AT24C16寫入設(shè)備地址和要訪問的存儲(chǔ)器地址(這個(gè)也叫作啞寫操作:為了AT24C16裝載隨機(jī)的地址)。然后重新發(fā)起讀操作,從主機(jī)接收AT24C16傳送的指定地址上的數(shù)據(jù)
(4)、指定地址順序讀n個(gè)字節(jié):這里的操作和(3)中也是差不多,不同的是再讀出的時(shí)候可以同時(shí)讀出n個(gè)數(shù)據(jù)。
在這里需要注意一點(diǎn):在本人的實(shí)驗(yàn)中,連續(xù)讀出n個(gè)數(shù)據(jù)并不會(huì)產(chǎn)生到達(dá)頁邊界就會(huì)回滾的現(xiàn)象,這里的n可以大于頁大小。也就是說,連續(xù)讀操作地址會(huì)自動(dòng)跨越頁邊界。但是如果到達(dá)地址的邊界,應(yīng)該就會(huì)重新回滾了。(關(guān)于這點(diǎn)我也并不是很確定,一般的資料上顯示的是到達(dá)頁邊界也就產(chǎn)生回滾了,但是我的實(shí)驗(yàn)在連續(xù)讀時(shí)確實(shí)是沒有產(chǎn)生回滾)。
這里說一點(diǎn),AT24C16存儲(chǔ)器是128頁(頁面數(shù))*16字節(jié)(頁大?。?。所以其設(shè)備地址結(jié)構(gòu)中1-3位也作為頁面地址的高3位,然后存儲(chǔ)器地址的高4位作為頁面地址的低4位,合起來正好7位,可以訪問128個(gè)頁面。然后存儲(chǔ)器地址的低4位作為頁偏移,可以訪問16個(gè)字節(jié)的內(nèi)容。
*/
//AT24C16寫一個(gè)字節(jié)(keil中int是2個(gè)字節(jié),在這里只有11位有效數(shù)據(jù)位)
int AT24C16_ByteWrite(unsigned int addr,uchar _data)
{
bit ret_val = 0;
uchar high_addr = (uchar)(addr>>8); //高8位地址
uchar low_addr =(uchar)addr; //低8位地址
uchar dev_addr = 0xA0 | ((high_addr&0x0F)<<1); //組成設(shè)備地址,其中包括4-6位是頁面地址,
if(addr > ADDRMAX)
{
return OutOfAddr;
}
//開啟I2C通信
Start_I2C();
//發(fā)送設(shè)備地址
ret_val = SendByte_I2C(dev_addr);
if(ret_val != 0)
return AckError;
//發(fā)送要訪問的地址
ret_val = SendByte_I2C(low_addr);
if(ret_val != 0)
return AckError;
//發(fā)送要訪問的地址
ret_val = SendByte_I2C(_data);
if(ret_val != 0)
return AckError;
//停止總線
Stop_I2C();
delay_ms(10); //延時(shí)一段時(shí)間,等待寫操作完成
return Send_OK;
}
//指定頁寫入n個(gè)字節(jié)數(shù)據(jù)(n<16)
int AT24C16_PageWrite(uchar page,uchar* p,uchar n)
{
uchar dev_addr; //設(shè)備地址
uchar low_addr;
uchar high_addr;
uchar tmp = 0;
bit ret_val;
if((n > 16)|(page > 128)) //根據(jù)讀寫的設(shè)備而變更為適合的頁數(shù)和每頁字節(jié)數(shù)
{
return OutOfRang ;
}
high_addr = (page) >> 4; //得出頁首地址
low_addr = ((page & 0x0F)<<4) ; //得出后四位頁地址,組成存儲(chǔ)地址的高四位
dev_addr = 0xa0 | ((high_addr & 0x0F) << 1);
//開啟I2C通信
Start_I2C();
//發(fā)送設(shè)備地址
ret_val = SendByte_I2C(dev_addr);
if(ret_val != 0)
return AckError;
//發(fā)送存儲(chǔ)地址,從頁首開始
ret_val = SendByte_I2C(low_addr);
if(ret_val != 0)
return AckError;
delay_ms(10); //延時(shí)一段時(shí)間,等待寫操作完成
while(n--)
{
ret_val = SendByte_I2C(*p);
p++;
if(ret_val != 0)
return AckError;
delay_ms(10); //延時(shí)一段時(shí)間,等待寫操作完成
}
//停止I2C通信
Stop_I2C();
delay_ms(10); //延時(shí)一段時(shí)間,等待寫操作完成
return Send_OK;
}
//AT24C16隨機(jī)讀一個(gè)字節(jié)
uchar AT24C16_RandomRead(unsigned int addr)
{
uchar dev_addr; //設(shè)備地址
uchar low_addr;
uchar high_addr;
uchar tmp = 0;
bit ret_val = 0;
low_addr = (uchar)addr;
high_addr = (uchar)(addr>>8);
dev_addr = 0xA0 | ((high_addr&0x0F)<<1);
if(addr > ADDRMAX)
{
return OutOfAddr;
}
//開啟I2C通信
Start_I2C();
//發(fā)送設(shè)備地址
ret_val = SendByte_I2C(dev_addr);
if(ret_val != 0)
return AckError;
//發(fā)送存儲(chǔ)器地址
ret_val = SendByte_I2C(low_addr);
if(ret_val != 0)
return AckError;
//重新開啟I2C通信
Start_I2C();
dev_addr = 0xA1 | ((high_addr&0x0F)<<1); //重新生成設(shè)備地址,這次是讀操作
//發(fā)送設(shè)備地址
ret_val = SendByte_I2C(dev_addr);
if(ret_val != 0)
return AckError;
//從I2C讀取一個(gè)字節(jié)
tmp = RecByte_I2C();
Ack_I2C(1); //發(fā)送非應(yīng)答位
//發(fā)送停止位
Stop_I2C();
return tmp;
}
//指定地址順序讀出n個(gè)字節(jié):(注意可能會(huì)到達(dá)終的地址邊界,產(chǎn)生回滾)
int AT24C16_SequentialRead(unsigned int addr,int n,uchar * p)
{
uchar dev_addr; //設(shè)備地址
uchar low_addr;
uchar high_addr;
uchar tmp = 0;
bit ret_val = 0;
if((addr > ADDRMAX)) //根據(jù)讀寫的設(shè)備而變更為適合的頁數(shù)和每頁字節(jié)數(shù)
{
return OutOfAddr ;
}
high_addr = (uchar)(addr>>8); //高8位地址
low_addr =(uchar)addr; //低8位地址
dev_addr = 0xA0 | ((high_addr&0x0F)<<1); //組成設(shè)備地址,其中包括4-6位是頁面地址,
//開啟I2C通信
Start_I2C();
//啞寫操作,讓存儲(chǔ)器加載設(shè)備地址和存儲(chǔ)地址
//發(fā)送設(shè)備地址
ret_val = SendByte_I2C(dev_addr);
if(ret_val != 0)
return AckError;
//發(fā)送存儲(chǔ)地址,從頁首開始
ret_val = SendByte_I2C(low_addr);
if(ret_val != 0)
return AckError;
//重新開啟I2C通信
Start_I2C();
dev_addr = 0xA1 | ((high_addr&0x0F)<<1); //組成設(shè)備地址,其中包括4-6位是頁面地址,
//重新發(fā)送設(shè)備地址,這次的目的是讀操作
ret_val = SendByte_I2C(dev_addr);
if(ret_val != 0)
return AckError;
//開始讀操作
while(n--)
{
*p = RecByte_I2C();
p++;
if(n>0)
Ack_I2C(0); //數(shù)據(jù)沒接受完,發(fā)送應(yīng)答位
else
Ack_I2C(1); //數(shù)據(jù)接受完,發(fā)送非應(yīng)答位
}
Stop_I2C();
return Rev_OK;
}
版權(quán)與免責(zé)聲明
凡本網(wǎng)注明“出處:維庫電子市場(chǎng)網(wǎng)”的所有作品,版權(quán)均屬于維庫電子市場(chǎng)網(wǎng),轉(zhuǎn)載請(qǐng)必須注明維庫電子市場(chǎng)網(wǎng),http://m.58mhw.cn,違反者本網(wǎng)將追究相關(guān)法律責(zé)任。
本網(wǎng)轉(zhuǎn)載并注明自其它出處的作品,目的在于傳遞更多信息,并不代表本網(wǎng)贊同其觀點(diǎn)或證實(shí)其內(nèi)容的真實(shí)性,不承擔(dān)此類作品侵權(quán)行為的直接責(zé)任及連帶責(zé)任。其他媒體、網(wǎng)站或個(gè)人從本網(wǎng)轉(zhuǎn)載時(shí),必須保留本網(wǎng)注明的作品出處,并自負(fù)版權(quán)等法律責(zé)任。
如涉及作品內(nèi)容、版權(quán)等問題,請(qǐng)?jiān)谧髌钒l(fā)表之日起一周內(nèi)與本網(wǎng)聯(lián)系,否則視為放棄相關(guān)權(quán)利。
- USB-C接口全解析:協(xié)議兼容、快充原理與常見問題排查2025/12/16 9:50:42
- 簡(jiǎn)述計(jì)算機(jī)總線的分類2025/9/4 17:12:23
- 深度剖析三進(jìn)線兩母聯(lián)供電系統(tǒng)設(shè)計(jì)方案2025/9/3 10:37:39
- 匯流排是什么匯流排好還是線接好2025/8/28 17:13:00
- 安森美 USB - C 電池充電器解決方案2025/8/28 15:45:10









