中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

地方門戶網(wǎng)站建設要求福州百度分公司

地方門戶網(wǎng)站建設要求,福州百度分公司,做定制校服的網(wǎng)站,金融建設網(wǎng)站IIC簡介 物理層 連接多個devices 它是一個支持設備的總線?!翱偩€”指多個設備共用的信號線。在一個 I2C 通訊總線中,可連接多個 I2C 通訊設備,支持多個通訊主機及多個通訊從機。 兩根線 一個 I2C 總線只使用兩條總線線路,一條雙向串行數(shù)…

IIC簡介

物理層

在這里插入圖片描述

連接多個devices

它是一個支持設備的總線?!翱偩€”指多個設備共用的信號線。在一個 I2C 通訊總線中,可連接多個 I2C 通訊設備,支持多個通訊主機及多個通訊從機。

兩根線

一個 I2C 總線只使用兩條總線線路,一條雙向串行數(shù)據(jù)線(SDA)一條串行時鐘線(SCL)。數(shù)據(jù)線即用來表示數(shù)據(jù),時鐘線用于數(shù)據(jù)收發(fā)同步。

設備地址

每個連接到總線的設備都有一個獨立的地址,主機可以利用這個地址進行不同設備之間的訪問。

上拉電阻和高阻態(tài)

總線通過上拉電阻接到電源。當 I2C 設備空閑時,會輸出高阻態(tài),而當所有設備都空閑,都輸出高阻態(tài)時,由上拉電阻把總線拉成高電平。

仲裁

多個主機同時使用總線時,為了防止數(shù)據(jù)沖突,會利用仲裁方式?jīng)Q定由哪個設備占用總線。

三種速度模式

具有三種傳輸模式:標準模式傳輸速率為 100kbit/s ,快速模式為 400kbit/s ,高速模式下可達 3.4Mbit/s,但目前大多 I2C 設備尚不支持高速模式。

最大devices限制

連接到相同總線的 IC 數(shù)量受到總線的最大電容 400pF 限制 。

協(xié)議層

I2C 的協(xié)議定義了通訊的起始和停止信號、數(shù)據(jù)有效性、響應、仲裁、時鐘同步和地址廣播等環(huán)節(jié)。

I2C 基本讀寫過程

在這里插入圖片描述
主機寫數(shù)據(jù)到從機
在這里插入圖片描述
主機由從機中讀數(shù)據(jù)

在這里插入圖片描述
I2C 通訊復合格式

在這里插入圖片描述 數(shù)據(jù)由主機傳輸至從機
在這里插入圖片描述數(shù)據(jù)由從機傳輸至主機

S : 傳輸開始信號
R/W: 傳輸方向選擇位,1 為讀,0 為寫
A/ A: 應答(ACK)或非應答(NACK)信號
在這里插入圖片描述停止傳輸信號

1.S是起始信號,由主機產(chǎn)生,掛載在總線上的設備都會收到,準備接收主機下一個數(shù)據(jù)
2.設備聆聽地址信息,選擇從機: 起始信號之后,主機會廣播從機地址,在 I2C 總線上,每個設備的地址都是唯一的,當主機廣播的地址與某個設備地址相同時,這個設備就被選中了,沒被選中的設備將會忽略之后的數(shù)據(jù)信號。根據(jù) I2C 協(xié)議,這個從機地址可以是 7 位或 10 位。
3.傳輸方向:主機廣播傳輸方向,0是主機到從機(主機往從機寫),1為從機到主機(從機往主機寫)
4.從機應答:回復ack與nack,只有收到ack之后,主機繼續(xù)發(fā)送或者接收數(shù)據(jù)

寫數(shù)據(jù)

在這里插入圖片描述
主機首先在 IIC 總線上發(fā)送起始信號,那么這時總線上的從機都會等待接收由主機發(fā)出的數(shù)據(jù)。主機接著發(fā)送從機地+0(寫操作)組成的 8bit 數(shù)據(jù),所有從機接收到該 8bit 數(shù)據(jù)后,自行檢驗是否是自己的設備的地址,假如是自己的設備地址,那么從機就會發(fā)出應答信號。主機在總線上接收到有應答信號后,才能繼續(xù)向從機發(fā)送數(shù)據(jù)。注意:IIC 總線上傳送的數(shù)據(jù)信號是廣義的,既包括地址信號,又包括真正的數(shù)據(jù)信號。

讀數(shù)據(jù)

在這里插入圖片描述
若配置的方向傳輸位為“讀數(shù)據(jù)”方向,即第二幅圖的情況,廣播完地址,接收到應答信號后,從機開始向主機返回數(shù)據(jù)(DATA),數(shù)據(jù)包大小也為 8 位,從機每發(fā)送完一個數(shù)據(jù),都會等待主機的應答信號(ACK),重復這個過程,可以返回 N 個數(shù)據(jù),這個 N 也沒有大小限制。當主機希望停止接收數(shù)據(jù)時,就向從機返回一個非應答信號(NACK),則從機自動停止數(shù)據(jù)傳輸。

信號電平

起始 停止信號

在這里插入圖片描述
當 SCL 線是高電平時 SDA 線從高電平向低電平切換,這個情況表示通訊的起始。當 SCL 是高電平時 SDA 線由低電平向高電平切換,表示通訊的停止。起始和停止信號一般由主機產(chǎn)生。

數(shù)據(jù)有效性 SCL的高電平

在這里插入圖片描述

SCL為高電平的時候 SDA表示的數(shù)據(jù)有效,SCL為低電平時數(shù)據(jù)變換

地址及數(shù)據(jù)方向

I2C 總線上的每個設備都有自己的獨立地址,主機發(fā)起通訊時,通過 SDA 信號線發(fā)送設備地址(SLAVE_ADDRESS)來查找從機。I2C 協(xié)議規(guī)定設備地址可以是 7 位或 10 位,實際中 7 位的地址應用比較廣泛。緊跟設備地址的一個數(shù)據(jù)位用來表示數(shù)據(jù)傳輸方向。
讀數(shù)據(jù)方向時,主機會釋放對 SDA 信號線的控制,由從機控制 SDA 信號線,主機接收信號,寫數(shù)據(jù)方向時,SDA 由主機控制,從機接收信號。
在這里插入圖片描述
大端(高有效位存在低地址),波形高位先行

ACK NACK

主站發(fā)送起始信號,地址,讀寫信號之后釋放SDA控制權(quán),從站開始自動控制SDA信號發(fā)送ACK NACK

整體控制邏輯

整體控制邏輯負責協(xié)調(diào)整個 I2C 外設,控制邏輯的工作模式根據(jù)我們配置的“控制寄存器(CR1/CR2)”的參數(shù)而改變。在外設工作時,控制邏輯會根據(jù)外設的工作狀態(tài)修改“狀態(tài)寄存器(SR1 和 SR2)”,我們只要讀取這些寄存器相關(guān)的寄存器位,就可以了解 I2C的工作狀態(tài)。除此之外,控制邏輯還根據(jù)要求,負責控制產(chǎn)生 I2C 中斷信號、DMA 請求及各種 I2C 的通訊信號(起始、停止、響應信號等)。

IIC使用 讀寫EEPROM為例

要點

(1) 配置通訊使用的目標引腳為開漏模式;
(2) 使能 I2C 外設的時鐘;
(3) 配置 I2C 外設的模式、地址、速率等參數(shù)并使能 I2C 外設;
(4) 編寫基本 I2C 按字節(jié)收發(fā)的函數(shù);
(5) 編寫讀寫 EEPROM 存儲內(nèi)容的函數(shù);

硬件IIC

配置IIC復用的GPIO

#配置 GPIO 復用
GPIO_InitTypeDef GPIO_InitStructure;/* 使能與 I2C 有關(guān)的時鐘 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB)/* 配置GPIO為開漏輸出模式 */
//配置Gpio初始化結(jié)構(gòu)體略
GPIO_Init(GPIOB, &GPIO_InitStructure);

1.配置IIC模式

I2C_InitTypeDef I2C_InitStructure;/* I2C 配置 */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;/*!< 指定工作模式,可選 I2C 模式及 SMBUS 模式 *//* 高電平數(shù)據(jù)穩(wěn)定,低電平數(shù)據(jù)變化 SCL 時鐘線的占空比 */
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; /*指定時鐘占空比,可選 low/high = 2:1 及 16:9 模式*//*!< 指定自身的 I2C 設備地址 */
I2C_InitStructure.I2C_OwnAddress1 =I2Cx_OWN_ADDRESS7;/*!< 指定自身的 I2C 設備地址 */I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ; /*!< 使能或關(guān)閉響應(一般都要使能) *//* I2C 的尋址模式 */
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; /*!< 指定地址的長度,可為 7 位及 10 位 */I2C_InitStructure.I2C_ClockSpeed = I2C_Speed; /*!< 設置 SCL 時鐘頻率,此值要低于 400000*/I2C_Init(I2C1, &I2C_InitStructure);
I2C_Cmd(I2C1, ENABLE);

1.1作為主機端,進行數(shù)據(jù)發(fā)送

即作為 I2C 通訊的主機端時,對外部發(fā)送數(shù)據(jù)的過程

以寫一個E2ROM為例
在這里插入圖片描述
(1) 控制產(chǎn)生起始信號(S),當發(fā)生起始信號后,它產(chǎn)生事件“EV5”,并會對 SR1 寄存器的“SB”位置 1,表示起始信號已經(jīng)發(fā)送;

(2) 緊接著發(fā)送設備地址并等待應答信號,若有從機應答,則產(chǎn)生事件“EV6”及“EV8”,這時 SR1 寄存器的“ADDR”位及“TXE”位被置 1,ADDR 為 1 表示地址已經(jīng)發(fā)送,TXE 為 1 表示數(shù)據(jù)寄存器為空;

(3) 以上步驟正常執(zhí)行并對 ADDR 位清零后,我們往 I2C 的“數(shù)據(jù)寄存器 DR”寫入要發(fā)送的數(shù)據(jù),這時TXE位會被重置0,表示數(shù)據(jù)寄存器非空,I2C外設通過SDA信號線一位位把數(shù)據(jù)發(fā)送出去后,又會產(chǎn)生“EV8”事件,即 TXE 位被置 1,重復這個過程,就可以發(fā)送多個字節(jié)數(shù)據(jù)了;

(4) 當我們發(fā)送數(shù)據(jù)完成后,控制 I2C 設備產(chǎn)生一個停止信號§,這個時候會產(chǎn)生EV8_2 事件,SR1 的 TXE 位及 BTF 位都被置 1,表示通訊結(jié)束。

假如我們使能了 I2C 中斷,以上所有事件產(chǎn)生時,都會產(chǎn)生 I2C 中斷信號,進入同一個中斷服務函數(shù),到 I2C 中斷服務程序后,再通過檢查寄存器位來判斷是哪一個事件。

IIC STM32固件庫函數(shù)鏈接: IIC STM32固件庫函數(shù)鏈接

1.1.1發(fā)送單字節(jié)數(shù)據(jù)

在這里插入圖片描述
AT24C02的單字節(jié)時序規(guī)定,向它寫入數(shù)據(jù)的時候,第一個字節(jié)為內(nèi)存地址,第二個字節(jié)是要寫入的數(shù)據(jù)內(nèi)容。在發(fā)送device地址之后,需要發(fā)送eeprom的內(nèi)部存儲地址和需要存的數(shù)據(jù)

#define EEPROM_I2Cx      I2C1/* 具體修改的寄存器位置,查看固件庫函數(shù)*/uint32_t I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr){/* 產(chǎn)生 I2C 起始信號 *///I2Cx->CR1 |= I2C_CR1_START; 操作I2C中的CR1寄存器I2C_GenerateSTART(I2C1, ENABLE);/*設置超時等待時間*/I2CTimeout = I2CT_FLAG_TIMEOUT;//I2CTimeout 常數(shù)/* 檢測 EV5 事件并清除標志*/while (!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_MODE_SELECT)){/* 超時,報錯*/if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(0);}/* 發(fā)送 EEPROM 設備地址 */I2C_Send7bitAddress(EEPROM_I2Cx, EEPROM_ADDRESS,I2C_Direction_Transmitter);/* 檢測 EV6 事件并清除標志*/while (!I2C_CheckEvent(EEPROM_I2Cx,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);}/* 發(fā)送要寫入的 EEPROM 內(nèi)部地址(即 EEPROM 內(nèi)部存儲器的地址) *//*  EEPROM 內(nèi)部存儲器讀寫的規(guī)則是第一個數(shù)據(jù)為要讀寫的地址,第二個數(shù)據(jù)是具體讀寫的數(shù)據(jù) */I2C_SendData(EEPROM_I2Cx, WriteAddr);I2CTimeout = I2CT_FLAG_TIMEOUT;/* 檢測 EV8 事件并清除標志*/while (!I2C_CheckEvent(EEPROM_I2Cx,I2C_EVENT_MASTER_BYTE_TRANSMITTED)){if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(2);}/* 發(fā)送一字節(jié)要寫入的數(shù)據(jù) */I2C_SendData(EEPROM_I2Cx, *pBuffer);I2CTimeout = I2CT_FLAG_TIMEOUT;I2CTimeout = I2CT_FLAG_TIMEOUT;/* 檢測 EV8 事件并清除標志*/while (!I2C_CheckEvent(EEPROM_I2Cx,I2C_EVENT_MASTER_BYTE_TRANSMITTED)){if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(2);}/* 發(fā)送停止信號 */I2C_GenerateSTOP(EEPROM_I2Cx, ENABLE);}

1.1.2發(fā)送多字節(jié)數(shù)據(jù)

等待存儲設備準備好

這個函數(shù)主要實現(xiàn)是向 EEPROM 發(fā)送它設備地址,檢測 EEPROM 的響應,若EEPROM 接收到地址后返回應答信號,則表示 EEPROM 已經(jīng)準備好,可以開始下一次通訊。函數(shù)中檢測響應是通過讀取 STM32 的 SR1 寄存器的 ADDR 位及 AF 位來實現(xiàn)的,當I2C 設備響應了地址的時候,ADDR 會置 1,若應答失敗,AF 位會置 1。

	//等待 EEPROM 到準備狀態(tài)void I2C_EE_WaitEepromStandbyState(void){vu16 SR1_Tmp = 0;do {/* 發(fā)送起始信號 */I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);/* 讀 I2C1 SR1 寄存器 */SR1_Tmp = I2C_ReadRegister(EEPROM_I2Cx, I2C_Register_SR1);/* 發(fā)送 EEPROM 地址 + 寫方向 */I2C_Send7bitAddress(EEPROM_I2Cx, EEPROM_ADDRESS,I2C_Direction_Transmitter);}// SR1 位 1 ADDR:1 表示地址發(fā)送成功,0 表示地址發(fā)送沒有結(jié)束// 等待地址發(fā)送成功while (!(I2C_ReadRegister(EEPROM_I2Cx, I2C_Register_SR1) & 0x0002));/* 清除 AF 位 */I2C_ClearFlag(EEPROM_I2Cx, I2C_FLAG_AF);/* 發(fā)送停止信號 */I2C_GenerateSTOP(EEPROM_I2Cx, ENABLE);
}
循環(huán)單字節(jié)發(fā)送
uint8_t I2C_EE_ByetsWrite(uint8_t* pBuffer,uint8_t WriteAddr,uint16_t NumByteToWrite)
{uint16_t i;uint8_t res;/*每寫一個字節(jié)調(diào)用一次 I2C_EE_ByteWrite 函數(shù),前文的單字節(jié)寫入*/for (i=0; i<NumByteToWrite; i++){/*等待 EEPROM 準備完畢*/I2C_EE_WaitEepromStandbyState();/*按字節(jié)寫入數(shù)據(jù)*/res = I2C_EE_ByteWrite(pBuffer++,WriteAddr++);}return res;
}

1.1.3 EEPROM 的頁寫入

EEPROM 定義了一種頁寫入時序,只要告訴 EEPROM 第一個內(nèi)存地址 address1,后面的數(shù)
據(jù)按次序?qū)懭氲?address2、address3… 這樣可以節(jié)省通訊的時間,加快速度。
在這里插入圖片描述
根據(jù)頁寫入時序,第一個數(shù)據(jù)被解釋為要寫入的內(nèi)存地址 address1,后續(xù)可連續(xù)發(fā)送 n個數(shù)據(jù),這些數(shù)據(jù)會依次寫入到內(nèi)存中。其中 AT24C02 型號的芯片頁寫入時序最多可以一次發(fā)送 8 個數(shù)據(jù)(即 n = 8 ),該值也稱為頁大小,某些型號的芯片每個頁寫入時序最多可傳輸 16 個數(shù)據(jù)。

但是這種方式還是比較慢,拘泥于頁的大小。

//在 EEPROM 的一個寫循環(huán)中可以寫多個字節(jié),但一次寫入的字節(jié)數(shù)不能超過 EEPROM 頁的大小,AT24C02 //每頁有 8 個字節(jié)
//NumByteToWrite:要寫的字節(jié)數(shù)要求 NumByToWrite 小于頁大小uint8_t I2C_EE_PageWrite(uint8_t* pBuffer, uint8_t WriteAddr,uint8_t NumByteToWrite)
{	I2CTimeout = I2CT_LONG_TIMEOUT;while (I2C_GetFlagStatus(EEPROM_I2Cx, I2C_FLAG_BUSY)){if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(4);}/* 產(chǎn)生 I2C 起始信號 */I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);I2CTimeout = I2CT_FLAG_TIMEOUT;/* 檢測 EV5 事件并清除標志 */while (!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_MODE_SELECT)){if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(5);}/* 發(fā)送 EEPROM 設備地址 */I2C_Send7bitAddress(EEPROM_I2Cx,EEPROM_ADDRESS,I2C_Direction_Transmitter);I2CTimeout = I2CT_FLAG_TIMEOUT;/* 檢測 EV6 事件并清除標志*/while (!I2C_CheckEvent(EEPROM_I2Cx,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(6);}/* 發(fā)送要寫入的 EEPROM 內(nèi)部地址(即 EEPROM 內(nèi)部存儲器的地址) */I2C_SendData(EEPROM_I2Cx, WriteAddr);I2CTimeout = I2CT_FLAG_TIMEOUT;/* 檢測 EV8 事件并清除標志*/while (! I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(7);}/* 循環(huán)發(fā)送 NumByteToWrite 個數(shù)據(jù) */while (NumByteToWrite--){/* 發(fā)送緩沖區(qū)中的數(shù)據(jù) */I2C_SendData(EEPROM_I2Cx, *pBuffer);/* 指向緩沖區(qū)中的下一個數(shù)據(jù) */pBuffer++;I2CTimeout = I2CT_FLAG_TIMEOUT;/* 檢測 EV8 事件并清除標志*/while (!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(8);}}/* 發(fā)送停止信號 */I2C_GenerateSTOP(EEPROM_I2Cx, ENABLE);
}

1.1.4 EEPROM 的頁寫入plus

利用 EEPROM 的頁寫入方式,可以改進前面的“多字節(jié)寫入”函數(shù),加快傳輸速度

 // AT24C01/02 每頁有 8 個字節(jié)#define I2C_PageSize 8void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr,u16 NumByteToWrite){u8 NumOfPage=0,NumOfSingle=0,Addr =0,count=0,temp =0;/*mod 運算求余,若 writeAddr 是 I2C_PageSize 整數(shù)倍,運算結(jié)果 Addr 值為 0*//*判斷目標地址(起始地址)是否為一頁的開始*/Addr = WriteAddr % I2C_PageSize;/*差 count 個數(shù)據(jù)值,剛好可以對齊到頁地址*/count = I2C_PageSize - Addr;/*計算出要寫多少整數(shù)頁*/NumOfPage = NumByteToWrite / I2C_PageSize;/*mod 運算求余,計算出剩余不滿一頁的字節(jié)數(shù)*/NumOfSingle = NumByteToWrite % I2C_PageSize;// Addr=0,則 WriteAddr 剛好按頁對齊 aligned,也就是從這頁的第一個byte開始// 這樣就很簡單了,直接寫就可以,寫完整頁后, 把剩下的不滿一頁的寫完即可if (Addr == 0) {//從某頁的第一位寫起/* 如果 NumByteToWrite < I2C_PageSize *//* 總字數(shù)還不滿一頁 */if (NumOfPage == 0) {//總頁數(shù)不滿一頁I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);I2C_EE_WaitEepromStandbyState();}/* 如果 NumByteToWrite > I2C_PageSize */else {/*先把整數(shù)頁都寫了*/while (NumOfPage--) {I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);//寫一頁I2C_EE_WaitEepromStandbyState();//等待rom準備好WriteAddr += I2C_PageSize;	//寫完一頁之后,下一頁的地址pBuffer += I2C_PageSize;	//寫完一頁之后,要傳輸?shù)脑吹刂芬惨?/span>}/*若有多余的不滿一頁的數(shù)據(jù),把它寫完*/if (NumOfSingle!=0) {I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);I2C_EE_WaitEepromStandbyState();}}}從某頁的第一位寫起// 如果 WriteAddr 不是按 I2C_PageSize 對齊// 那就算出對齊到頁地址還需要多少個數(shù)據(jù),先把這幾個數(shù)據(jù)寫完,剩下開始的地址就已經(jīng)對齊else{//不是從某頁的第一位寫起/* 如果 NumByteToWrite < I2C_PageSize */if (NumOfPage== 0){//總數(shù)不滿一頁if (NumOfSingle > count) {//count:還需要寫多少個字節(jié)才能頁面對齊//NumOfSingle:當前頁面空閑的字節(jié)數(shù)// temp 的數(shù)據(jù)要寫到寫一頁temp = NumOfSingle - count;I2C_EE_PageWrite(pBuffer, WriteAddr, count);//寫count數(shù)目的到當前頁I2C_EE_WaitEepromStandbyState();//等待準備完畢WriteAddr += count;//目標地址移動pBuffer += count;I2C_EE_PageWrite(pBuffer, WriteAddr, temp);//在下一頁寫完剩下的I2C_EE_WaitEepromStandbyState();}else{ /*若 count 比 NumOfSingle 大*/I2C_EE_PageWrite(pBuffer, WriteAddr, NumByteToWrite);I2C_EE_WaitEepromStandbyState();}}/* 如果 NumByteToWrite > I2C_PageSize *//* 如果 不止寫一頁 */else {	/* 如果 不止寫一頁 *//*地址不對齊多出的 count 分開處理,不加入這個運算*/NumByteToWrite -= count;NumOfPage = NumByteToWrite / I2C_PageSize;NumOfSingle = NumByteToWrite % I2C_PageSize;/*先把 WriteAddr 所在頁的剩余字節(jié)寫了*/if (count != 0) {I2C_EE_PageWrite(pBuffer, WriteAddr, count);I2C_EE_WaitEepromStandbyState();/*WriteAddr 加上 count 后,地址就對齊到頁了*/WriteAddr += count;pBuffer += count;}/*把整數(shù)頁都寫了*/while (NumOfPage--) {I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);I2C_EE_WaitEepromStandbyState();WriteAddr += I2C_PageSize;pBuffer += I2C_PageSize;}/*若有多余的不滿一頁的數(shù)據(jù),把它寫完*/if (NumOfSingle != 0) {I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);I2C_EE_WaitEepromStandbyState();}}/*把整數(shù)頁都寫了*/}/* 如果 不止寫一頁 */	}

1.2作為主機端,進行數(shù)據(jù)接收

即作為 I2C 通訊的主機端時,從外部接收數(shù)據(jù)的過程
在這里插入圖片描述
(1) 同主發(fā)送流程,起始信號(S)是由主機端產(chǎn)生的,控制發(fā)生起始信號后,它產(chǎn)生事件“EV5”,并會對 SR1 寄存器的“SB”位置 1,表示起始信號已經(jīng)發(fā)送;
(2) 緊接著發(fā)送設備地址并等待應答信號,若有從機應答,則產(chǎn)生事件“EV6”這時SR1 寄存器的“ADDR”位被置 1,表示地址已經(jīng)發(fā)送。
(3) 從機端接收到地址后,開始向主機端發(fā)送數(shù)據(jù)。當主機接收到這些數(shù)據(jù)后,會產(chǎn)生“EV7”事件,SR1 寄存器的 RXNE被置 1,表示接收數(shù)據(jù)寄存器非空,我們讀取該寄存器后,可對數(shù)據(jù)寄存器清空,以便接收下一次數(shù)據(jù)。此時我們可以控制I2C 發(fā)送應答信號(ACK)或非應答信號(NACK),若應答,則重復以上步驟接收數(shù)據(jù),若非應答,則停止傳輸;
(4) 發(fā)送非應答信號后,產(chǎn)生停止信號P,結(jié)束傳輸。

 uint8_t I2C_EE_BufferRead(uint8_t* pBuffer, uint8_t ReadAddr,u16 NumByteToRead){I2CTimeout = I2CT_LONG_TIMEOUT;while (I2C_GetFlagStatus(EEPROM_I2Cx, I2C_FLAG_BUSY)){if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(9);}/* 產(chǎn)生 I2C 起始信號 */I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);I2CTimeout = I2CT_FLAG_TIMEOUT;/* 檢測 EV5 事件并清除標志*/while (!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_MODE_SELECT)){if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(10);}/* 發(fā)送 EEPROM 設備地址 */I2C_Send7bitAddress(EEPROM_I2Cx,EEPROM_ADDRESS,I2C_Direction_Transmitter);I2CTimeout = I2CT_FLAG_TIMEOUT;/* 檢測 EV6 事件并清除標志*/while (!I2C_CheckEvent(EEPROM_I2Cx,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(11);}	/*通過重新設置 PE 位清除 EV6 事件 */I2C_Cmd(EEPROM_I2Cx, ENABLE);/* 發(fā)送要讀取的 EEPROM 內(nèi)部地址(即 EEPROM 內(nèi)部存儲器的地址) *//*  EEPROM 內(nèi)部存儲器讀寫的規(guī)則是第一個數(shù)據(jù)為要讀寫的地址,第二個數(shù)據(jù)是具體讀寫的數(shù)據(jù) */I2C_SendData(EEPROM_I2Cx, ReadAddr);I2CTimeout = I2CT_FLAG_TIMEOUT;/* 檢測 EV8 事件并清除標志*/while (!I2C_CheckEvent(EEPROM_I2Cx,I2C_EVENT_MASTER_BYTE_TRANSMITTED)){if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(12);}/* 產(chǎn)生第二次 I2C 起始信號 */I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);I2CTimeout = I2CT_FLAG_TIMEOUT;	/* 檢測 EV5 事件并清除標志*/while (!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_MODE_SELECT)){if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(13);}/* 發(fā)送 EEPROM 設備地址 */I2C_Send7bitAddress(EEPROM_I2Cx, EEPROM_ADDRESS, I2C_Direction_Receiver);I2CTimeout = I2CT_FLAG_TIMEOUT;/* 檢測 EV6 事件并清除標志*/while (!I2C_CheckEvent(EEPROM_I2Cx,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)){if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(14);}/* 讀取 NumByteToRead 個數(shù)據(jù)*/while (NumByteToRead){/*若 NumByteToRead=1,表示已經(jīng)接收到最后一個數(shù)據(jù)了,發(fā)送非應答信號,結(jié)束傳輸*/if (NumByteToRead == 1){/* 發(fā)送非應答信號 */I2C_AcknowledgeConfig(EEPROM_I2Cx, DISABLE);/* 發(fā)送停止信號 */I2C_GenerateSTOP(EEPROM_I2Cx, ENABLE);}I2CTimeout = I2CT_LONG_TIMEOUT;while (I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED)==0){if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);}{/*通過 I2C,從設備中讀取一個字節(jié)的數(shù)據(jù) */*pBuffer = I2C_ReceiveData(EEPROM_I2Cx);/* 存儲數(shù)據(jù)的指針指向下一個地址 */pBuffer++;/* 接收數(shù)據(jù)自減 */NumByteToRead--;}	}	/* 讀取 NumByteToRead 個數(shù)據(jù)*//* 使能應答,方便下一次 I2C 傳輸 */I2C_AcknowledgeConfig(EEPROM_I2Cx, ENABLE);}

1.3作為從機端,進行數(shù)據(jù)接收

在這里插入圖片描述

1.4作為從機端,進行數(shù)據(jù)接收

在這里插入圖片描述

GPIO模擬IIC

我之前使用這套方法讀取一個外置的RTC模塊,參考正點原子的例程,這邊就不贅述了?;蛘咧笥袡C會把例程貼出來哈

1.配置GPIO

2.編寫微秒級軟延時

3.根據(jù)時序編寫各個函數(shù)

DMA 與IIC

可以使用DMA,對IIC的DR中要傳輸或者接收的數(shù)據(jù)進行搬運,DMA請求(當被使能時)僅用于數(shù)據(jù)傳輸。發(fā)送時數(shù)據(jù)寄存器變空或接收時數(shù)據(jù)寄存器變滿,則產(chǎn)生DMA請求。DMA請求必須在當前字節(jié)傳輸結(jié)束之前被響應。當為相應DMA通道設置的數(shù)據(jù)傳輸量已經(jīng)完成時,DMA控制器發(fā)送傳輸結(jié)束信號ETO到I2C接口,并且在中斷允許時產(chǎn)生一個傳輸完成中斷。

主發(fā)送器:在EOT中斷服務程序中,需禁止DMA請求,然后在等到BTF事件后設置停止條件。

主接收器:當要接收的數(shù)據(jù)數(shù)目大于或等于2時,DMA控制器發(fā)送一個硬件信號EOT_1,它對應DMA傳輸(字節(jié)數(shù)-1)。如果在I2C_CR2寄存器中設置了LAST位,硬件在發(fā)送完EOT_1后的下一個字節(jié),將自動發(fā)送NACK。在中斷允許的情況下,用戶可以在DMA傳輸完成的中斷服務程序中產(chǎn)生一個停止條件。

意思是說當DMA產(chǎn)生EOT標志后,(如果開啟了EOT相關(guān)中斷就進中斷程序,沒有開啟就進行軟件查詢做后續(xù)處理)關(guān)閉DMA請求,然后等待BTF事件,之后執(zhí)行STOP操作。 這里的BTF事件就是I2C數(shù)據(jù)收發(fā)過程中的數(shù)據(jù)字節(jié)是否傳輸完成的的事件。
IIC通訊過程 標志位

配置DMA

對DMA進行配置

在IIC的配置中開啟DMA

通過設置I2C_CR2寄存器中的DMAEN位可以激活DMA模式。只要TxE位被置位,數(shù)據(jù)將由DMA從預置的存儲區(qū)裝載進I2C_DR寄存器。為I2C分配一個DMA通道,須執(zhí)行以下步驟(x是通道號)。

利用DMA發(fā)送

  1. 在DMA_CPARx寄存器中設置I2C_DR寄存器地址。數(shù)據(jù)將在每個TxE事件后從存儲器傳
    送至這個地址。

  2. 在DMA_CMARx寄存器中設置存儲器地址。數(shù)據(jù)在每個TxE事件后從這個存儲區(qū)傳送至
    I2C_DR。

  3. 在DMA_CNDTRx寄存器中設置所需的傳輸字節(jié)數(shù)。在每個TxE事件后,此值將被遞減。

  4. 利用DMA_CCRx寄存器中的PL[0:1]位配置通道優(yōu)先級。

  5. 設置DMA_CCRx寄存器中的DIR位。

  6. 根據(jù)應用要求可以配置在整個傳輸完成一半或全部完成時發(fā)出中斷請求。

  7. 通過設置DMA_CCTx寄存器上的EN位激活通道。

當DMA控制器中設置的數(shù)據(jù)傳輸數(shù)目已經(jīng)完成時,DMA控制器給I2C接口發(fā)送一個傳輸結(jié)束的EOT/ EOT_1信號。在中斷允許的情況下,將產(chǎn)生一個DMA中斷。
如果使用DMA進行發(fā)送時,不要設置I2C_CR2寄存器的ITBUFEN位。

利用DMA接收

通過設置I2C_CR2寄存器中的DMAEN位可以激活DMA接收模式。每次接收到數(shù)據(jù)字節(jié)時,將由DMA把I2C_DR寄存器的數(shù)據(jù)傳送到設置的存儲區(qū)(參考DMA說明)。設置DMA通道進行I2C接收,須執(zhí)行以下步驟(x是通道號):

  1. 在DMA_CPARx寄存器中設置I2C_DR寄存器的地址。數(shù)據(jù)將在每次RxNE事件后從此地
    址傳送到存儲區(qū)。
  2. 在DMA_CMARx寄存器中設置存儲區(qū)地址。數(shù)據(jù)將在每次RxNE事件后從I2C_DR寄存器
    傳送到此存儲區(qū)。
  3. 在DMA_CNDTRx寄存器中設置所需的傳輸字節(jié)數(shù)。在每個RxNE事件后,此值將被遞
    減。
  4. 用DMA_CCRx寄存器中的PL[0:1]配置通道優(yōu)先級。
  5. 清除DMA_CCRx寄存器中的DIR位,根據(jù)應用要求可以設置在數(shù)據(jù)傳輸完成一半或全部
    完成時發(fā)出中斷請求。
  6. 設置DMA_CCRx寄存器中的EN位激活該通道。

當DMA控制器中設置的數(shù)據(jù)傳輸數(shù)目已經(jīng)完成時,DMA控制器給I2C接口發(fā)送一個傳輸結(jié)束的
EOT/ EOT_1信號。在中斷允許的情況下,將產(chǎn)生一個DMA中斷。
注: 如果使用DMA進行接收時,不要設置I2C_CR2寄存器的ITBUFEN位

http://www.risenshineclean.com/news/60848.html

相關(guān)文章:

  • wordpress附件插件南寧seo推廣優(yōu)化
  • 建設企業(yè)資質(zhì)雙網(wǎng)是哪兩個網(wǎng)站線上推廣平臺都有哪些
  • 福州正規(guī)網(wǎng)站建設公司報價軟文廣告案例分析
  • 酒店網(wǎng)站設計模板免費創(chuàng)建網(wǎng)站的平臺
  • 手機微網(wǎng)站優(yōu)化大師使用心得
  • 網(wǎng)站建設聯(lián)盟深圳互聯(lián)網(wǎng)公司50強
  • 自適應網(wǎng)站如何做mip網(wǎng)頁快速排名優(yōu)化seo
  • 長葛網(wǎng)站建設公司最近國際新聞大事20條
  • 定制開發(fā)平臺電商網(wǎng)站seo怎么做
  • 哪個網(wǎng)站可以接任務做兼職移動網(wǎng)站如何優(yōu)化排名
  • 網(wǎng)站開發(fā)期間賬務處理新產(chǎn)品推廣
  • 網(wǎng)站設計步驟畢業(yè)論文互聯(lián)網(wǎng)營銷師證書怎么考多少錢
  • 湛江cms建站排名點擊工具
  • 千華網(wǎng)鞍山門戶網(wǎng)站關(guān)鍵詞搜索站長工具
  • h5制作軟件電腦百度ocpc怎么優(yōu)化
  • 中國建設銀行北海招聘信息網(wǎng)站百度旗下產(chǎn)品
  • 視頻網(wǎng)站app怎么做的長春做網(wǎng)絡優(yōu)化的公司
  • 外貿(mào)網(wǎng)站推廣計劃關(guān)鍵詞排名工具
  • 青島公司網(wǎng)站建設公司seo關(guān)鍵詞排名優(yōu)化案例
  • 網(wǎng)站如何防盜鏈網(wǎng)站運營策劃書范文
  • 圍場網(wǎng)站建設sem優(yōu)化師
  • 臨安建辦網(wǎng)站長沙關(guān)鍵詞優(yōu)化平臺
  • mysql做wp網(wǎng)站什么是網(wǎng)絡營銷公司
  • 網(wǎng)站輿情監(jiān)控怎么做運營推廣
  • 北京專業(yè)企業(yè)營銷網(wǎng)站建設互聯(lián)網(wǎng)推廣是什么意思
  • 大連哪家網(wǎng)站公司好如何做好精準營銷
  • 有模塊傳奇網(wǎng)站怎么做新東方雅思培訓價目表
  • 外貿(mào)做網(wǎng)站建設哪家好東莞網(wǎng)站優(yōu)化
  • 天河做網(wǎng)站哪家好騰訊體育nba
  • 普陀做網(wǎng)站優(yōu)化網(wǎng)站seo策略