日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CC2541对AT24CXX系列存储器的支持

發(fā)布時(shí)間:2025/4/16 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CC2541对AT24CXX系列存储器的支持 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.



????前陣子,網(wǎng)上看到有人提問CC2541的I2C是否支持AT24CXX系列的存儲(chǔ)器。正好項(xiàng)目需要,所以買了兩塊AT24C256進(jìn)行?測(cè)試了下。毫無疑問,當(dāng)然是可以支持的。?????

?首先,需要強(qiáng)調(diào)的是CC2541具有I2C外設(shè),而CC2540不具備,這也是它們的區(qū)別之一。所以,CC2451可以完美驅(qū)動(dòng)帶I2C的設(shè)備。

?如果CC2541的程序是跑OSAL架構(gòu)的,那么可以可以將它提供的i2c的源碼直接拿來用,而不需做任何修改。下面就是基于OSAL架構(gòu)的來講的。

?支持i2c的代碼可以在BLE協(xié)議棧安裝目錄下的BLE-CC254x-1.3.2\Components\hal\target\CC2541ST目錄下找到。在這個(gè)目錄下,找到hal_i2c.c、hal_i2c.h、hal_sensor.c和hal_sensor.h這4個(gè)文件,拷貝到你的工程目錄下,然后天添加到工程中。其中hal_i2c.c與hal_i2c.h兩個(gè)文件支持了CC2541的i2c的基本實(shí)現(xiàn)函數(shù),hal_sensor.c與hal_sensor.h這兩個(gè)文件則是為具體的i2c設(shè)備提供了讀寫接口。下面就來仔細(xì)講講。


1、hal_i2c.c與hal_i2c.h的代碼實(shí)現(xiàn)

?要想使用i2c,當(dāng)然要對(duì)i2c協(xié)議有一定的了解。如下圖說所示,可以總結(jié)出來i2c必須要的幾部分是:起始信號(hào)、設(shè)備地址、讀寫選擇位,應(yīng)答信號(hào),以及停止位。

?在使用i2c之前,當(dāng)然需要先配置下i2c。在hal_i2c.c下,有?HalI2CInit()函數(shù),用來配置CC2541的i2c,代碼如下:?????

static?uint8?i2cAddr;

void?HalI2CInit(uint8?address,?i2cClock_t?clockRate)
{
?i2cAddr?=?address?<<?1;

?I2C_WRAPPER_DISABLE();
?I2CADDR?=?0;?//?no?multi?master?support?at?this?time
?I2C_CLOCK_RATE(clockRate);
?I2C_ENABLE();
}

上面代碼中看起來像函數(shù)的語句其實(shí)是宏定義,用來配置相關(guān)的寄存器,他們?cè)趆al_i2c.c的最開始就宏定義過,這里就不細(xì)講,自己看代碼。這里定義了一個(gè)i2cAddr變量,用于保存i2c設(shè)備的地址。I2C_WRAPPER_DISABLE()關(guān)閉寫保護(hù),這樣的話就可以支持讀寫操作了,I2C_CLOCK_RATE()則設(shè)置i2c的時(shí)鐘速率,最后I2C_ENABLE()使能i2c。這樣的話,i2c就初始化完成了。

?i2c的起始信號(hào)和停止信號(hào)以及讀寫數(shù)據(jù)都是通過操作寄存器操作的。hal_i2c.c中給出了他們的宏定義:

#define?I2C_STRT()?st?(?\
?I2CCFG?&=?~I2C_SI;?\
?I2CCFG?|=?I2C_STA;?\
?while?((I2CCFG?&?I2C_SI)?==?0);?\
?I2CCFG?&=?~I2C_STA;?\
)

//?Must?set?STO?before?clearing?SI.
#define?I2C_STOP()?st?(?\
?I2CCFG?|=?I2C_STO;?\
?I2CCFG?&=?~I2C_SI;?\
?while?((I2CCFG?&?I2C_STO)?!=?0);?\
)

//?Stop?clock-stretching?and?then?read?when?it?arrives.
#define?I2C_READ(_X_)?st?(?\
?I2CCFG?&=?~I2C_SI;?\
?while?((I2CCFG?&?I2C_SI)?==?0);?\
?(_X_)?=?I2CDATA;?\
)

//?First?write?new?data?and?then?stop?clock-stretching.
#define?I2C_WRITE(_X_)?st?(?\
?I2CDATA?=?(_X_);?\
?I2CCFG?&=?~I2C_SI;?\
?while?((I2CCFG?&?I2C_SI)?==?0);?\
)

起始信號(hào)的產(chǎn)生需要操作I2CCFG寄存器下的STA位來產(chǎn)生起始信號(hào);停止信號(hào)通過操作I2CCFG下的STO位來產(chǎn)生停止信號(hào);而讀寫操作只要讀取I2CDATA數(shù)據(jù)和向I2CDATA寫入數(shù)據(jù)就可以實(shí)現(xiàn)了。?????

?hal_i2c.c中還給出了發(fā)送起始信號(hào)與設(shè)備地址以及控制讀寫的函數(shù):i2cMstStrt(),如下:

static?uint8?i2cMstStrt(uint8?RD_WRn)
{
?I2C_STRT();

?if?(I2CSTAT?==?mstStarted)?/*?A?start?condition?has?been?transmitted?*/
?{
?I2C_WRITE(i2cAddr?|?RD_WRn);
?}

?return?I2CSTAT;
}

它有一個(gè)參數(shù):RD_WRn,用來決定數(shù)據(jù)的讀寫,RD_WRn=1表示從i2c總線讀取數(shù)據(jù),RD_WRn=0則從i2c總線上寫數(shù)據(jù)。?????

?為了從i2c總線上讀取數(shù)據(jù),hal_i2c.c中給出了HalI2CRead()函數(shù),代碼如下:

uint8?HalI2CRead(uint8?len,?uint8?*pBuf)
{
?uint8?cnt?=?0;

?if?(i2cMstStrt(I2C_MST_RD_BIT)?!=?mstAddrAckR)
?{
?len?=?0;
?}
?if?(len?>?1)
?{
?I2C_SET_ACK();
?}
?while?(len?>?0)
?{
?//?slave?devices?require?NACK?to?be?sent?after?reading?last?byte
?if?(len?==?1)
?{
?I2C_SET_NACK();
?}

?//?read?a?byte?from?the?I2C?interface
?I2C_READ(*pBuf++);
?cnt++;
?len--;

?if?(I2CSTAT?!=?mstDataAckR)
?{
?if?(I2CSTAT?!=?mstDataNackR)
?{
?//?something?went?wrong,?so?don't?count?last?byte
?cnt--;
?}
?break;
?}
?}
?I2C_STOP();

?return?cnt;
}

這個(gè)函數(shù)帶兩個(gè)參數(shù):len和pbuf。len是要讀取的數(shù)據(jù)長(zhǎng)度,而pbuf則用于保存在讀取到的數(shù)據(jù)。先要調(diào)用i2cMstStrt(I2C_MST_RD_BIT)函數(shù),發(fā)送起始信號(hào)以及設(shè)備地址,控制讀寫位為讀。然后在while(1)中,調(diào)用I2C_READ()讀取指定數(shù)量的字節(jié)。最后再發(fā)送一個(gè)停止信號(hào)。?????

?為了向i2c總線上寫數(shù)據(jù),hal_i2c.c給出了HalI2CWrite()函數(shù),代碼如下:

uint8?HalI2CWrite(uint8?len,?uint8?*pBuf)
{
?if?(i2cMstStrt(0)?!=?mstAddrAckW)
?{
?len?=?0;
?}
?for?(uint8?cnt?=?0;?cnt?<?len;?cnt++)
?{
?I2C_WRITE(*pBuf++);

?if?(I2CSTAT?!=?mstDataAckW)
?{
?if?(I2CSTAT?==?mstDataNackW)
?{
?len?=?cnt?+?1;
?}
?else
?{
?len?=?cnt;
?}
?break;
?}
?}
?I2C_STOP();
?return?len;
}

這個(gè)函數(shù)帶兩個(gè)參數(shù):lne和pBuf。len是要寫的數(shù)據(jù)長(zhǎng)度,pBuf則是要寫的數(shù)據(jù)指針。跟HalI2CRead()函數(shù)差不多,先調(diào)用i2cMstStrt(I2C_MST_RD_BIT)函數(shù)發(fā)送起始信號(hào)以設(shè)備地址,選擇讀寫位為寫操作。然后在while()中調(diào)用I2C_WRITE()寫入指定長(zhǎng)度的數(shù)據(jù)。最后在發(fā)送一位停止信號(hào)。?????


2、hal_sensor.c與hal_sensor.h文件

?如果對(duì)于AT24CXX系列中的AT2401、AT2402、AT2404、AT2408、AT2416這幾種存儲(chǔ)器,hal_sensor.c和hal_sensor.h可以不做任何修改就可以完全支持。但是如果對(duì)于大于16K的AT24CXX些列存儲(chǔ)器則需要對(duì)這兩個(gè)文件進(jìn)行修改。為什么會(huì)存在這樣的差別呢?原因在于他們的片內(nèi)地址的范圍。對(duì)于1K位,2K位,4K位,8K位,16K位芯片采用一個(gè)8位長(zhǎng)的字節(jié)地址碼,對(duì)于32K位以上的采用2個(gè)8位長(zhǎng)的字節(jié)地址碼直接尋址,而4K位,8K位,16K位配合頁面地址來尋址的。hal_sensor給出的代碼用的就是支持8為地址的。所以對(duì)于16k以上的存儲(chǔ)器需要將hal_sensor的代碼修改成支持2個(gè)8位地址。下面就分成上面兩種情況進(jìn)行說明。

?對(duì)于AT2401、AT2402、AT2404、AT2408、AT2416這幾種存儲(chǔ)器,hal_sensor的代碼可以不做任何修改,但是可以將除了HalSensorReadReg()和HalSensorWriteReg()這兩個(gè)函數(shù)之外的其他函數(shù)全部去掉,因?yàn)槎际遣幌嚓P(guān)的代碼。HalSensorReadReg()與HalSensorWriteReg()分別用向AT24CXX存儲(chǔ)器指定的地址上讀寫指定的數(shù)數(shù)據(jù)。代碼如下:

bool?HalSensorReadReg(uint8?addr,?uint8?*pBuf,?uint8?nBytes)
{
?uint8?i?=?0;

?/*?Send?address?we're?reading?from?*/
?if?(HalI2CWrite(1,&addr)?==?1)
?{
?/*?Now?read?data?*/
?i?=?HalI2CRead(nBytes,pBuf);
?}

?return?i?==?nBytes;
}


bool?HalSensorWriteReg(uint8?addr,?uint8?*pBuf,?uint8?nBytes)
{
?uint8?i;
?uint8?*p?=?buffer;

?/*?Copy?address?and?data?to?local?buffer?for?burst?write?*/
?*p++?=?addr;
?for?(i?=?0;?i?<?nBytes;?i++)
?{
?*p++?=?*pBuf++;
?}
?nBytes++;

?/*?Send?address?and?data?*/
?i?=?HalI2CWrite(nBytes,?buffer);
?if?(?i!=?nBytes)
?HAL_TOGGLE_LED2();

?return?(i?==?nBytes);
}

可以發(fā)現(xiàn),這兩個(gè)函數(shù)的參數(shù)中的addr的類型是uint8,對(duì)應(yīng)的1個(gè)字節(jié)的地址。它們的讀寫過程如下:?????

?對(duì)于AT2432、AT2464、AT24128、AT24256這幾種存在器的片內(nèi)地址需要2個(gè)8為字節(jié)的數(shù)據(jù)需要將上面給出的HalSensorReadReg()與HalSensorWriteReg()修改成支持16為地址,代碼如下:

bool?HalSensorReadReg(uint16?addr,?uint8?*pBuf,?uint8?nBytes)
{
?uint8?i?=?0;
?uint8?addrH,?addrL;
?
?addrL?=?addr?&?0xff;
?addrH?=?addr?>>?8;

?/*?Send?address?we're?reading?from?*/
?if?(HalI2CWrite(1,?&addrH)?==?1)
?if?(HalI2CWrite(1,?&addrL)?==?1)
?{
?/*?Now?read?data?*/
?i?=?HalI2CRead(nBytes,pBuf);
?}

?return?i?==?nBytes;
}


bool?HalSensorWriteReg(uint16?addr,?uint8?*pBuf,?uint8?nBytes)
{
?uint8?i;
?uint8?*p?=?buffer;
?uint8?addrL?=?0,?addrH?=?0;
?
?addrL?=?(uint8)(addr?&?0xff);
?addrH?=?(uint8)(addr?>>?8);

?/*?Copy?address?and?data?to?local?buffer?for?burst?write?*/
?*p++?=?addrH;
?*p++?=?addrL;
?for?(i?=?0;?i?<?nBytes;?i++)
?{
?*p++?=?*pBuf++;
?}
?nBytes?+=?2;

?/*?Send?address?and?data?*/
?i?=?HalI2CWrite(nBytes,?buffer);
?if?(?i!=?nBytes)
?HAL_TOGGLE_LED2();

?return?(i?==?nBytes);
}

需要注意的是,上面的這兩函數(shù)的參數(shù)addr的數(shù)據(jù)類型改成了uint16,所以需要在這兩個(gè)函數(shù)的代碼中將這16位的地址拆成高8為地址與低8為地址,分別定義addrH和addrL保存。在發(fā)送2個(gè)8位地址時(shí),高8位地址在前,低8為地址在后。它們的讀寫過程如下:?????

??建議再在hal_sensor.c中編寫一個(gè)halSensorInit()函數(shù),調(diào)用hal_i2c.c中的HalI2CInit(),配置CC2541的i2c,代碼如下:?????

void?halSensorInit(void)
{
?HalI2CInit(0x50,?i2cClock_533KHZ);?
}

其中0x50指得是i2c設(shè)備的地址。對(duì)于AT24CXX系列對(duì)于AT24C01~AT24C16來說它們的設(shè)備地址如下:?????

?對(duì)于AT24C32及以上的存儲(chǔ)器來說,它的設(shè)備地址如下:?????

?可以發(fā)現(xiàn),不同AT24CXX的地址需要根據(jù)上面的bit1~bit3決定,bit4~bit7都固定為0b1010。bit1~bit3跟存儲(chǔ)器的硬件接線相關(guān),對(duì)于我買的AT24C256模塊,A0與A1引腳全部接地,則它的地址為:0b1010000,即0x50。?????


3、AT24CXX的讀寫

?在應(yīng)用代碼中,調(diào)用上面給出的halSensorInit()函數(shù)初始化CC2541的i2c外設(shè),然后調(diào)用HalSensorWriteReg()指定地址寫入數(shù)據(jù),然后再調(diào)用HalSensorReadReg()函數(shù)將該地址數(shù)據(jù)的上的值讀取出來,實(shí)例代碼如下:

static?uint8?buffer[32]?=?{0};

halSensorinit();//初始化CC2541的i2c

halWriteReg(0x0000,?"abcdefghij",?10);//向AT24C256的0x0000地址處寫入數(shù)據(jù)

halReadReg(0x0000,?buffer,?10);//從AT24C256的0x0000地址處讀取10個(gè)字節(jié)數(shù)據(jù)

HalLcdWriteString(buffer,?HAL_LCD_LINE_4);//將讀取到的數(shù)據(jù)顯示在LCD上


  • 轉(zhuǎn)載自 http://ziye334.lofter.com/post/2435a3_2a2e1b4

    總結(jié)

    以上是生活随笔為你收集整理的CC2541对AT24CXX系列存储器的支持的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。