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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

STM32——EEPROM

發(fā)布時間:2023/12/20 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32——EEPROM 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

STM32——EEPROM


宗旨:技術(shù)的學(xué)習(xí)是有限的,分享的精神是無限的。


一、I2C接口讀寫EEPROMAT24C02

?????? ——主模式,分別用作主發(fā)送器和主接收器。通過查詢事件的方式來確保正常通信。

1I 2C接口初始化

? ? ? ? 與其他對GPIO 復(fù)用的外設(shè)一樣,它先調(diào)用了用戶函數(shù)I2C_GPIO_Confi g() 配置好 I 2 C 所用的 I/O端口,然后再調(diào)用用戶函數(shù) I2C_Mode_Confi gu() 設(shè)置 I 2 C 的工作模式,并使能相關(guān)外設(shè)的時鐘。

void I2C_EE_Init(void) {I2C_GPIO_Config();I2C_Mode_Config();/* 根據(jù)頭文件 i2c_ee. 14 h 中的定義來選擇 EEPROM 要寫入的地址 */ #ifdef EEPROM_Block0_ADDRESS /* 選擇 EEPROM Block0 來寫入 */EEPROM_ADDRESS = EEPROM_Block0_ADDRESS; #endif #ifdef EEPROM_Block1_ADDRESS /* 選擇 EEPROM Block1 來寫入 */EEPROM_ADDRESS = EEPROM_Block1_ADDRESS; #endif #ifdef EEPROM_Block2_ADDRESS /* 選擇 EEPROM Block2 來寫入 */EEPROM_ADDRESS = EEPROM_Block2_ADDRESS; #endif #ifdef EEPROM_Block3_ADDRESS /* 選擇 EEPROM Block3 來寫入 */EEPROM_ADDRESS = EEPROM_Block3_ADDRESS; #endif }

1)EEPROM地址

? ? ? ? AT24C02:256字節(jié),高四位硬性規(guī)定,最低位是R/W(傳輸方向選擇位),在制作硬件時,我們可以根據(jù)需要改變的是地址位中的 A2、A1、A0 位。原理圖上面全接地,所以它的地址為 :0xA0 或 0xA1。

2GPIO端口初始化

static void I2C_GPIO_Config(void) {GPIO_InitTypeDef GPIO_InitStructure;/* 使能與 I2C1 有關(guān)的時鐘 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);/* 配置SCL SDA引腳速率輸出方式 */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 開漏輸出GPIO_Init(GPIOB, &GPIO_InitStructure); }


3I2C模式初始化

typedef struct {uint32_t I2C_ClockSpeed;uint16_t I2C_Mode;uint16_t I2C_DutyCycle;uint16_t I2C_OwnAddress1;uint16_t I2C_Ack;uint16_t I2C_AcknowledgedAddress; } I2C_InitTypeDef;

1I2C_Mode本成員是選擇 I 2 C 的使用方式,有 I 2 C 模式(I2C_Mode_I2C)和SMBus 模式。(I2C_Mode_SMBusDevice、I2C_Mode_SMBusHost)

2I2C_DutyCycle設(shè)置的是 I 2 C 的 SCL 線時鐘的占空比。在 STM32 的 I 2 C 占空比配置中有兩個選擇,分別為高電平時間和低電平時間之比為16 :9 (I2C_DutyCycle_16_9)和 2 :1( I2C_DutyCycle_2)。

3I2C_OwnAddress1本 成 員 配 置 的 是 STM32 的 I 2 C 設(shè) 備 自 己 的 地 址, 每個 連 接 到 I 2 C 總線上的設(shè)備都要有一個自己的地址,作為主機(jī)也不例外。這個地址可以被配置為 7 位和 10 位地址。我們把這個地址設(shè)置為 0x0A (自定義宏I2C1_OWN_ADDRESS7 的值)。

4I2C_Ack_Enable本成員關(guān)于 I 2 C 應(yīng)答設(shè)置,設(shè)置為使能則每接收到一個字節(jié)就返回一個應(yīng)答信號。配置為允許應(yīng)答(I2C_Ack_Enable),這是絕大多數(shù)遵循 I 2 C標(biāo)準(zhǔn)的設(shè)備通信的要求,改為禁止應(yīng)答 (I2C_Ack_Disable)往往會導(dǎo)致通信錯誤。

5I2C_AcknowledgeAddress本成員選擇 I 2 C 的尋址模式是 7 位還是 10 位地址。這需要根據(jù)實(shí)際連接到 I 2C 總線上設(shè)備的地址進(jìn)行選擇。與 EEPROM 進(jìn)行通信,使用的為 7 位尋址模式(I2C_AcknowledgedAddress_7bit)。

6I2C_ClockSpeed本成員設(shè)置的是 I 2 C 的傳輸速率,在調(diào)用初始化函數(shù)時,函數(shù)會根據(jù)我們輸入的數(shù)值經(jīng)過運(yùn)算后把分頻值寫入到 I 2 C 的時鐘控制寄存器。而我們寫入的這個參數(shù)值不得高于 400 kHz。——400000

對結(jié)構(gòu)體成員賦值完成后,我們調(diào)用庫函數(shù) I2C_Init() 根據(jù)我們的配置對 I 2 C 進(jìn)行初始化, 并調(diào)用庫函數(shù) I2C_Cmd() 使能I 2 C 外設(shè)。?

static void I2C_Mode_Configu(void) {I2C_InitTypeDef I2C_InitStructure;I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; /* I2C 配置 */I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; /* 高電平數(shù)據(jù)穩(wěn)定,低電平數(shù)據(jù)變化 SCL 時鐘線的占空比 */I2C_InitStructure.I2C_OwnAddress1 = I2C1_OWN_ADDRESS7;I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; /* I2C 的尋址模式 */I2C_InitStructure.I2C_ClockSpeed = I2C_Speed; /* 通信速率 */I2C_Init(I2C1, &I2C_InitStructure); /* I2C1 初始化 */I2C_Cmd(I2C1, ENABLE); /* 使能 I2C1 */ }

二、對EEPROM的讀寫操作

void I2C_Test(void) {u16 i;printf("寫入的數(shù)據(jù)\n\r");for ( i = 0; i <= 255; i++ ) //填充緩沖{I2c_Buf_Write[i] = i;printf("0x%02X ", I2c_Buf_Write[i]);if (i % 16 == 15){printf("\n\r");}}I2C_EE_BufferWrite( I2c_Buf_Write, EEP_Firstpage, 256); //將 I2c_Buf_Write 中順序遞增的數(shù)據(jù)寫入 EERPOM 中printf("\n\r 寫成功\n\r");printf("\n\r 讀出的數(shù)據(jù)\n\r");I2C_EE_BufferRead(I2c_Buf_Read, EEP_Firstpage, 256); //將 EEPROM 讀出數(shù)據(jù)順序保持到 I2c_Buf_Read 中//將 I2c_Buf_Read 中的數(shù)據(jù)通過串口打印for (i = 0; i < 256; i++){if (I2c_Buf_Read[i] != I2c_Buf_Write[i]){printf("0x%02X ", I2c_Buf_Read[i]);printf("錯誤:I2C EEPROM 寫入與讀出的數(shù)據(jù)不一致\n\r");return;}printf("0x%02X ", I2c_Buf_Read[i]);if (i % 16 == 15){printf("\n\r");}}printf("I2C(AT24C02)讀寫測試成功\n\r"); }

? ? ? ? 功能是把數(shù)值 0 ~ 255 按順序填入緩沖區(qū)數(shù)組,并通過串口打印到終端,接著通過用戶函數(shù)I2C_EE_BufferWrite()把緩沖區(qū)的數(shù)據(jù)寫入EEPROM。寫入成功之后,利用用戶函數(shù) I2C_EE_BufferRead() 把數(shù)據(jù)讀取出來,進(jìn)行校驗(yàn),判斷數(shù)據(jù)是否被正確寫入。?

void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr, u16 NumByteToWrite) {u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;Addr = WriteAddr % I2C_PageSize;count = I2C_PageSize - Addr;NumOfPage = NumByteToWrite / I2C_PageSize;NumOfSingle = NumByteToWrite % I2C_PageSize;/* If WriteAddr is I2C_PageSize aligned */if (Addr == 0){/* If NumByteToWrite < I2C_PageSize */if (NumOfPage == 0){I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);I2C_EE_WaitEepromStandbyState();}/* If NumByteToWrite > I2C_PageSize */else{while (NumOfPage--){I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);I2C_EE_WaitEepromStandbyState();WriteAddr += I2C_PageSize;pBuffer += I2C_PageSize;}if (NumOfSingle != 0){I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);I2C_EE_WaitEepromStandbyState();}}}/* If WriteAddr is not I2C_PageSize aligned */else{/* If NumByteToWrite < I2C_PageSize */if (NumOfPage == 0){I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);I2C_EE_WaitEepromStandbyState();}/* If NumByteToWrite > I2C_PageSize */else{NumByteToWrite -= count;NumOfPage = NumByteToWrite / I2C_PageSize;NumOfSingle = NumByteToWrite % I2C_PageSize;if (count != 0){I2C_EE_PageWrite(pBuffer, WriteAddr, count);I2C_EE_WaitEepromStandbyState();WriteAddr += count;pBuffer += count;}while (NumOfPage--){I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);I2C_EE_WaitEepromStandbyState();WriteAddr += I2C_PageSize;pBuffer += I2C_PageSize;}if (NumOfSingle != 0){I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);I2C_EE_WaitEepromStandbyState();}}} }

? ? ? ? AT24C02 的 EEPROM 分為 32 頁,每頁可存儲8個字節(jié)的數(shù)據(jù),若在同一頁寫入超過 8 字節(jié),則超過的部分會被寫在該頁的起始地址,這樣部分?jǐn)?shù)據(jù)會被覆蓋。為了把連續(xù)的緩沖區(qū)數(shù)組按頁寫入 EEPROM,就需要對緩沖區(qū)進(jìn)入分頁處理。I2C_EE_BufferWrite() 函數(shù)根據(jù)我們輸入的緩沖區(qū)大小參數(shù) NumByteToWrite,計(jì)算出我們需要寫入多少頁,并計(jì)算寫入位置。分頁處理好之后,調(diào)用 I2C_EE_PageWrite() 函數(shù),這個函數(shù)是與 EEPROM 進(jìn)行 I 2 C通信的最底層函數(shù),它與 STM32 的 I 2 C 庫函數(shù)使用密切相關(guān)。

void I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite) {while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));I2C_GenerateSTART(I2C1, ENABLE); /* Send START condition */while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); /* Test on EV5 and clear it */I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter); /* Send EEPROM address for write */while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); /* Test on EV6 and clear it */I2C_SendData(I2C1, WriteAddr); /* Send the EEPROM's internal address to write to */while (! I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); /* Test on EV8 and clear it */while (NumByteToWrite--) /* While there is data to be written */{I2C_SendData(I2C1, *pBuffer); /* Send the current byte */pBuffer++; /* Point to the next byte to be written */while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) ); /* Test on EV8 and clear it */}I2C_GenerateSTOP(I2C1, ENABLE); /* Send STOP condition */ }

1EEPROM頁寫入時序

這個頁寫入的函數(shù)是根據(jù) EEPROM 的頁寫入時序來編寫的。

調(diào)用庫函數(shù)I2C_Generate START() 產(chǎn)生 I 2 C 的通信起始信號 S。

調(diào)用庫函數(shù)I2C_Send7bitAddress() 把前面條件編譯中賦值的變量EEPROM_ADDRESS 地 址 通 過 I 2 C1接口發(fā)送出去,數(shù)據(jù)傳輸方向?yàn)镾TM32的I2 C發(fā)送數(shù)據(jù)(I2C_Direction_Transmitter)。

調(diào) 用 庫 函 數(shù)I2C_SendData() , 請 注 意 這 個 庫 函 數(shù) 的 輸 入 參 數(shù) 為WriteAddr,根據(jù) EEPROM 的頁寫入時序,發(fā)送完 I 2 C 的地址后的第一個數(shù)據(jù)并不就是要寫入 EEPROM 的數(shù)據(jù), EEPROM 對這個數(shù)據(jù)解釋為將要對存儲矩陣寫入的地址,這個參數(shù) WriteAddr 是在我們調(diào)用 I2C_EE_PageWrite() 函數(shù)時作為參數(shù)輸入的。這個庫函數(shù)實(shí)際上是把數(shù)據(jù)傳輸?shù)綌?shù)據(jù)寄存器,再由 I 2 C 模塊根據(jù) I 2 C 協(xié)議發(fā)送出
去。

調(diào)用I2C_SendData() 函數(shù),向 EEPROM 發(fā)送要寫入的數(shù)據(jù),根據(jù)EEPROM 的頁寫入時序,這些數(shù)據(jù)將會被寫入到前面發(fā)送的頁地址中,若連續(xù)寫入超過一頁的最大字節(jié)數(shù)(8個),則多出來的數(shù)據(jù)會重新從該頁的起始地址連續(xù)寫入,覆蓋前面的數(shù)據(jù)。

調(diào)用庫函數(shù)I2C_Generate STOP() 產(chǎn)生 I 2 C 傳輸結(jié)束信號,完成一次 I2 C 通信。

?

2I2C事件檢測

? ? ? ? 在 I 2 C的通信過程中,會產(chǎn)生一系列的事件,出現(xiàn)事件后在相應(yīng)的寄存器中會產(chǎn)生標(biāo)志位。

? ? ? ? ?若發(fā)出了起始信號,會產(chǎn)生事件 5(EV5),即 STM32 的 I 2 C成為主機(jī)模式;繼續(xù)發(fā)送完 I 2C 設(shè)備尋址并得到應(yīng)答后,會產(chǎn)生 EV6,即 STM32 的 I 2C 成為數(shù)據(jù)發(fā)送端;之后發(fā)送數(shù)據(jù)完成會產(chǎn)生 EV8 等。我們在做出 I 2 C 通信操作時,可以通過循環(huán)調(diào)用庫函數(shù)I2C_CheckEvent()進(jìn)行事件查詢,以確保上一操作完成后才進(jìn)行下一操作。

?

3、等到EEPROM內(nèi)部寫入完成

void I2C_EE_WaitEepromStandbyState(void) {vu16 SR1_Tmp = 0;do{I2C_GenerateSTART(I2C1, ENABLE); /* Send START condition */SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1); /* Read I2C1 SR1 register */I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter); /* Send EEPROM address for write */}while (!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));I2C_ClearFlag(I2C1, I2C_FLAG_AF); /* Clear AF flag */I2C_GenerateSTOP(I2C1, ENABLE); /* STOP condition */ }

? ? ? ? 利用了 EEPROM 在接收完數(shù)據(jù)后,啟動內(nèi)部周期寫入數(shù)據(jù)的時間內(nèi)不會對主機(jī)的請求做出應(yīng)答的特性。所以利用這個函數(shù)循環(huán)發(fā)送起始信號,若檢測到 EEPROM 的應(yīng)答,則說明 EEPROM 已經(jīng)完成上一步的數(shù)據(jù)寫入,進(jìn)入 Standby 狀態(tài),可以進(jìn)行下一步的操作了。

?

?三、EEPROM讀

void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead) { //*((u8 *)0x4001080c) |=0x80;while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); // Added by Najoua/* Send START condition */I2C_GenerateSTART(I2C1, ENABLE); //*((u8 *)0x4001080c) &=~0x80;/* Test on EV5 and clear it */while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/* Send EEPROM address for write */I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);/* Test on EV6 and clear it */while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));/* Clear EV6 by setting again the PE bit */I2C_Cmd(I2C1, ENABLE);/* Send the EEPROM's internal address to write to */I2C_SendData(I2C1, ReadAddr);/* Test on EV8 and clear it */while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));/* Send STRAT condition a second time */I2C_GenerateSTART(I2C1, ENABLE);/* Test on EV5 and clear it */while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/* Send EEPROM address for read */I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Receiver);/* Test on EV6 and clear it */while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));/* While there is data to be read */while (NumByteToRead){if (NumByteToRead == 1){/* Disable Acknowledgement */I2C_AcknowledgeConfig(I2C1, DISABLE);/* Send STOP Condition */I2C_GenerateSTOP(I2C1, ENABLE);}/* Test on EV7 and clear it */if (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)){/* Read a byte from the EEPROM */*pBuffer = I2C_ReceiveData(I2C1);/* Point to the next location where the byte read will besaved */pBuffer++;/* Decrement the read bytes counter */NumByteToRead--;}}/* Enable Acknowledgement to be ready for another reception */I2C_AcknowledgeConfig(I2C1, ENABLE); }

四、使用 I2 C讀寫EEPROM流程總結(jié)

(1)配置 I/O 端口,確定并配置 I 2 C 的模式,使能 GPIO 和 I 2 C 時鐘。

(2)寫 :

① 檢測 SDA 是否空閑。

② 按 I 2 C 協(xié)議發(fā)出起始信號。

③ 發(fā)出 7 位器件地址和寫模式。

④ 要寫入的存儲區(qū)首地址。

⑤ 用頁寫入方式或字節(jié)寫入方式寫入數(shù)據(jù)。

⑥ 發(fā)送 I 2 C 通信結(jié)束信號。

每個操作之后要檢測“事件”是否成功。寫完后檢測 EEPROM 是否進(jìn)入Standby狀態(tài)。

(3)讀 :

① 檢測 SDA 是否空閑。

② 按 I 2 C 協(xié)議發(fā)出起始信號。

③ 發(fā)出 7 位器件地址和寫模式(偽寫)。

④ 發(fā)出要讀取的存儲區(qū)首地址。

⑤ 重發(fā)起始信號。

⑥ 發(fā)出 7 位器件地址和讀模式。

⑦ 接收數(shù)據(jù)。

類似寫操作,每個操作之后要檢測“事件”是否成功。

?

總結(jié)

以上是生活随笔為你收集整理的STM32——EEPROM的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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