I2C是一種多主從的串行通訊協(xié)議。STM32F1的I2C模塊支持標(biāo)速(最高100kHz)和高速(最高400kHz)兩種工作模式。
一、I2C協(xié)議簡(jiǎn)介
標(biāo)準(zhǔn)的IIC接口有數(shù)據(jù)線SDA、時(shí)鐘線SCL兩條總線,只能工作于半雙工模式,在設(shè)計(jì)中,對(duì)總線的負(fù)載電容有一定的要求,具體請(qǐng)查閱元件的技術(shù)手冊(cè)確定。
IIC的通訊時(shí)序如圖,通訊電平為正邏輯:
※數(shù)據(jù)發(fā)送的起始和終止信號(hào)為:SCL為高時(shí),
起始:SDA下降沿 終止:SDA上升沿
※當(dāng)總線空閑時(shí),SDA和SCL均為高電平,總線需要外接上拉電阻,阻值5-10k。
※每次發(fā)送一字節(jié)(8bits)信號(hào),MSB高位先發(fā)。
二、I2C通訊時(shí)序(使用時(shí)以具體被控芯片手冊(cè)為準(zhǔn))
通訊時(shí)序(主機(jī)發(fā)送若干數(shù)據(jù)):
※主機(jī)引腳配置為open Drain,務(wù)必不要內(nèi)部上拉、下拉
***①保持SCL=1,拉低SDA,產(chǎn)生起始信號(hào)。
***②拉低SCL,準(zhǔn)備發(fā)送數(shù)據(jù);
***③將數(shù)據(jù)高位Shift Out(SDA上),隨后拉高SCL。在SCL=1期間SDA電平不能變動(dòng)。
***④將數(shù)據(jù)依次輸出
***⑤輸出最后一位數(shù)據(jù)且SCL變?yōu)榈碗娖胶?,主機(jī)接SDA引腳立即變換為高阻輸入模式。
⑥主機(jī)向SCL輸出一個(gè)時(shí)鐘方波,在方波高位檢測(cè)從機(jī)是否將SDA拉低(即發(fā)送ACK);若未收到表明發(fā)送未成功。
***⑦當(dāng)主機(jī)檢測(cè)到SDA被拉低時(shí),表明從機(jī)準(zhǔn)備好接收下一字節(jié)數(shù)據(jù)。隨后主機(jī)拉高SCL,從機(jī)釋放SDA,形成終止信號(hào)。若錯(cuò)誤,主機(jī)也拉高SCL并記錄錯(cuò)誤。此時(shí)SCL=1,SDA=1。***
⑧準(zhǔn)備下一次傳輸。
通訊時(shí)序(從機(jī)接收若干數(shù)據(jù)):
①?gòu)臋C(jī)引腳均配置為輸入模式
***②檢測(cè)開(kāi)始信號(hào),隨后接收數(shù)據(jù)(可以通過(guò)SCL上升、下降沿觸發(fā)方式檢測(cè)校驗(yàn))
③若接收沒(méi)有出現(xiàn)錯(cuò)誤,從機(jī)將SDA配置為開(kāi)漏,在定義的數(shù)據(jù)長(zhǎng)度(數(shù)據(jù)位+1ACK)的前一個(gè)時(shí)鐘方波之后(時(shí)鐘下降沿)拉低SDA發(fā)出ACK。若接受錯(cuò)誤(例如一個(gè)時(shí)鐘信號(hào)上升下降沿SDA數(shù)據(jù)不同)則不下拉。
④檢測(cè)到SCL出現(xiàn)上升后,釋放SDA。
⑤準(zhǔn)備下一次傳輸。
※IIC數(shù)據(jù)以1個(gè)數(shù)據(jù)包(主機(jī))+1位ACK(從機(jī))格式傳送:
發(fā)送地址的最后一位是數(shù)據(jù)方向位(R/W位),該位用“0”表示主機(jī)發(fā)送數(shù)據(jù),“1”表示主機(jī)接收數(shù)據(jù)(R)。
※當(dāng)STM32做主機(jī)時(shí),在發(fā)送地址位后(10位地址模式為首序列最后一位)會(huì)根據(jù)方向位自動(dòng)判斷進(jìn)入主發(fā)送器模式或主接收器模式**。**
三、STM32 LL庫(kù)IIC驅(qū)動(dòng)
STM32的I2C模塊可以配置為從機(jī)輸出、從機(jī)輸入、主機(jī)輸出、主機(jī)輸入四種模式。
■主模式時(shí),I2C接口啟動(dòng)數(shù)據(jù)傳輸并產(chǎn)生時(shí)鐘信號(hào)。串行數(shù)據(jù)傳輸總是以起始條件開(kāi)始并以停止條件結(jié)束。起始條件和停止條件都是在主模式下由軟件控制產(chǎn)生。
■從模式時(shí),I2C接口能識(shí)別它自己的地址(7位或10位)和廣播呼叫地址。軟件能夠控制開(kāi)啟或禁止廣播呼叫地址的識(shí)別。
※ SCL時(shí)鐘信號(hào)、起始終止信號(hào)由主機(jī)輸出 , 應(yīng)答始終由從機(jī)應(yīng)答 ;從機(jī)由主機(jī)發(fā)送地址選中(主機(jī)和從機(jī)的區(qū)別)。
1.IIC時(shí)鐘配置:
在I2C_CR2寄存器中Freq[5:0]設(shè)定該模塊的輸入時(shí)鐘( APH1旁路時(shí)鐘輸入,最高36MHz )。輸入時(shí)鐘的頻率至少為:
● 標(biāo)準(zhǔn)模式下為:2MHz ● 快速模式下為:4MHz
若使用CubeMX進(jìn)行模塊的配置,則生成的模塊初始化函數(shù)中自動(dòng)設(shè)置
2.相關(guān)寄存器
①自身地址寄存器(I2C_OAR1):
STM32的IIC模塊支持雙地址模式,即 可以設(shè)置兩個(gè)自身地址 :
自身地址寄存器2(I2C_OAR2):
*②時(shí)鐘控制寄存器(I2C_CCR): * (CubeMX自動(dòng)配置)
在I2C_CR2中設(shè)置完成模塊輸入時(shí)鐘后對(duì)SCL輸出時(shí)鐘進(jìn)行配置
③控制寄存器(I2C_CR1)
④控制寄存器(I2C_CR2)
⑤數(shù)據(jù)寄存器(I2C_DR)
⑥狀態(tài)寄存器(I2C_SR1)
PEC校驗(yàn)的使用較為復(fù)雜,使用時(shí)請(qǐng)具體參看手冊(cè)
對(duì)包序號(hào)的判斷(第幾個(gè)包?)從起始條件開(kāi)始計(jì)算。
⑦狀態(tài)寄存器(I2C_SR2)
3.傳輸時(shí)序(請(qǐng)參考傳輸時(shí)序進(jìn)行開(kāi)發(fā))
** ①主發(fā)送器模式**
※7位地址最后一位為R/W位,10位幀頭最后一位為R/W,此時(shí)設(shè)置為"0",由本機(jī)發(fā)送
** ②主接收器模式(主模式下起始、終止條件都由本機(jī)發(fā)出)**
※7位地址最后一位為R/W位,10位幀頭最后一位為R/W,此時(shí)設(shè)置為"1",由本機(jī)發(fā)送
** ③從接收器模式**
※地址R/W位非本機(jī)發(fā)送,由硬件自動(dòng)比對(duì)本機(jī)地址判斷是否被選中。此時(shí)R/W位為"0"
** ④從發(fā)送器模式**
※地址R/W位非本機(jī)發(fā)送,由硬件自動(dòng)比對(duì)本機(jī)地址判斷是否被選中。此時(shí)R/W位為"0"
關(guān)于主從模式:
*** ■模塊默認(rèn)處于從模式***
*** ■當(dāng)本機(jī)通過(guò)START位主動(dòng)發(fā)送起始條件時(shí),進(jìn)入主模式***
*** ■當(dāng)主模式最后一字節(jié)傳輸完成后,由本機(jī)置STOP位發(fā)送停止條件,進(jìn)入從模式***
*** ■從模式下模塊自動(dòng)檢測(cè)總線上的電平變化***
*** ■發(fā)送/接收模式的選擇通過(guò)硬件自動(dòng)判斷R/W實(shí)現(xiàn)***
■注意發(fā)送/接收地址后,讀ADDR才能進(jìn)入主/從模式下一步的數(shù)據(jù)傳輸
LL庫(kù)函數(shù):
1、初始化結(jié)構(gòu)體LL_I2C_InitTypeDef
typedef struct
{
uint32_t PeripheralMode;/*
選擇模塊工作模式,通過(guò)LL_I2C_SetMode()實(shí)現(xiàn)
@ref LL_I2C_MODE_I2C //I2C模式
LL_I2C_MODE_SMBUS_HOST //
LL_I2C_MODE_SMBUS_DEVICE //
LL_I2C_MODE_SMBUS_DEVICE_ARP //
*/
uint32_t ClockSpeed;/*
配置時(shí)鐘頻率(< 400kHz(高速);< 100kHz(標(biāo)準(zhǔn)));通過(guò)LL_I2C_SetClockPeriod()、LL_I2C_SetDutyCycle()、
LL_I2C_SetClockSpeedMode()、LL_I2C_ConfigSpeed()實(shí)現(xiàn)
//示例: 若需要100kHz時(shí)鐘,則輸入100000
*/
uint32_t DutyCycle;/*
設(shè)置高速模式(僅)下信號(hào)占空比;通過(guò)LL_I2C_SetDutyCycle()實(shí)現(xiàn)
@ref LL_I2C_DUTYCYCLE_2 //低:高=2
LL_I2C_DUTYCYCLE_16_9 //低:高=16:9
*/
uint32_t OwnAddress1;/*
設(shè)置自身的主地址,通過(guò) LL_I2C_SetOwnAddress1()實(shí)現(xiàn)
//10位模式最大為0x3FF, 7位最大為0x7F
※該結(jié)構(gòu)體及模塊初始化函數(shù)不提供設(shè)置第二地址(副地址)的方式
*/
uint32_t TypeAcknowledge;/*
配置ACK使能;通過(guò)LL_I2C_AcknowledgeNextData()實(shí)現(xiàn)
@ref LL_I2C_ACK //在接收到一個(gè)字節(jié)后返回一個(gè)應(yīng)答(匹配的地址或數(shù)據(jù))
LL_I2C_NACK //無(wú)應(yīng)答
*/
uint32_t OwnAddrSize;/*
設(shè)置自身地址長(zhǎng)度;通過(guò)LL_I2C_SetOwnAddress1()實(shí)現(xiàn)
※在雙地址模式下只能設(shè)置為7位長(zhǎng)度
@ref LL_I2C_OWNADDRESS1_7BIT //7位長(zhǎng)度
LL_I2C_OWNADDRESS1_10BIT //10位長(zhǎng)度
*/
} LL_I2C_InitTypeDef;
2、工作模式設(shè)置
void LL_I2C_SetMode(I2C_TypeDef *I2Cx, uint32_t PeripheralMode);/*
設(shè)置模塊工作模式
@reg CR1- >SMBUS、SMBTYPE、ENARP
@ref LL_I2C_MODE_I2C //I2C模式
LL_I2C_MODE_SMBUS_HOST //
LL_I2C_MODE_SMBUS_DEVICE //
LL_I2C_MODE_SMBUS_DEVICE_ARP //
*/
uint32_t LL_I2C_GetMode(I2C_TypeDef *I2Cx);
3、模塊開(kāi)啟/關(guān)閉函數(shù)
void LL_I2C_Enable(I2C_TypeDef *I2Cx);/*
使能(開(kāi)啟)I2C模塊
@reg CR1- >PE
*/
void LL_I2C_Disable(I2C_TypeDef *I2Cx);/*
禁用(關(guān)閉)I2C模塊
@reg CR1- >PE
*/
uint32_t LL_I2C_IsEnabled(I2C_TypeDef *I2Cx);/*
檢測(cè)I2C模塊是否開(kāi)啟
@retval: 1//開(kāi)啟
0//關(guān)閉
*/
4.時(shí)鐘延長(zhǎng)控制(ClockStretching)
參考https://blog.csdn.net/happygaohualei/article/details/52864694
通過(guò)將SCL線拉低來(lái)暫停一個(gè)傳輸.直到釋放SCL線為高電平,傳輸才繼續(xù)進(jìn)行。一般情況是從機(jī)在發(fā)送過(guò)程中將SCL接地,主機(jī)無(wú)法拉高電平后暫停傳輸,從機(jī)處理完成任務(wù)后釋放SCL,傳輸繼續(xù)。 大多數(shù)外設(shè)不支持時(shí)鐘延長(zhǎng)功能。
※STM32默認(rèn)允許時(shí)鐘延長(zhǎng)
void LL_I2C_EnableClockStretching(I2C_TypeDef *I2Cx);/*
使能時(shí)鐘延長(zhǎng)。
@reg CR1- >NOSTRETCH
*/
void LL_I2C_DisableClockStretching(I2C_TypeDef *I2Cx);/*
禁用時(shí)鐘延長(zhǎng)
@reg CR1- >NOSTRETCH
*/
uint32_t LL_I2C_IsEnabledClockStretching(I2C_TypeDef *I2Cx);/*
檢測(cè)是否啟用時(shí)鐘延長(zhǎng)
@retval 1//啟用
*/
5.自身地址設(shè)置
地址在從模式下由硬件自動(dòng)比較
void LL_I2C_SetOwnAddress1(I2C_TypeDef *I2Cx, uint32_t OwnAddress1, uint32_t OwnAddrSize);/*
設(shè)置自身主地址,并設(shè)置地址模式(7位或10位)
@reg ADD0 ADD1_7 ADD8_9 ADDMODE
@param OWnAddress//自身主地址
OwnAddrSize//地址模式(7位或10位),@ref LL_I2C_OWNADDRESS1_7BIT
LL_I2C_OWNADDRESS1_10BIT
※若啟用第二地址,設(shè)置為7位地址模式
*/
void LL_I2C_EnableOwnAddress2(I2C_TypeDef *I2Cx);/*
雙地址模式(啟用第二地址),啟用后只支持7位地址模式
@reg OAR2- >ENDUAL
*/
void LL_I2C_SetOwnAddress2(I2C_TypeDef *I2Cx, uint32_t OwnAddress2);/*
設(shè)置第二地址(7位)
*/
void LL_I2C_DisableOwnAddress2(I2C_TypeDef *I2Cx);/*
禁用雙地址模式
@reg OAR2- >ENDUAL
*/
6.廣播呼叫控制(General Call)
當(dāng)本機(jī)作為從機(jī)接收到地址0x00時(shí),將被選中并發(fā)ACK(如果使能ACK),0x00即廣播地址。
void LL_I2C_EnableGeneralCall(I2C_TypeDef *I2Cx);/*
使能廣播呼叫。
@reg CR1- >ENGC
*/
void LL_I2C_DisableGeneralCall(I2C_TypeDef *I2Cx);/*
禁用廣播呼叫.
@reg CR1- >ENGC
*/
uint32_t LL_I2C_IsEnabledGeneralCall(I2C_TypeDef *I2Cx);/*
檢測(cè)是否啟用了廣播呼叫。
@retval 1//啟用
*/
7.模塊時(shí)鐘配置
- 請(qǐng)?jiān)谀K關(guān)閉的狀態(tài)下配置*
void LL_I2C_SetClockPeriod(I2C_TypeDef *I2Cx, uint32_t ClockPeriod);/*
配置SCL時(shí)鐘周期;
@reg CCR- >CCR
@note 具體配置參見(jiàn)MANUAL的CCR寄存器(前有)
*/
uint32_t LL_I2C_GetClockPeriod(I2C_TypeDef *I2Cx);/*
讀取CCR- >CCR的值
*/
void LL_I2C_SetClockSpeedMode(I2C_TypeDef *I2Cx, uint32_t ClockSpeedMode);/*
設(shè)置速度模式(標(biāo)準(zhǔn)/高速)
@reg CCR- >FS
@ref LL_I2C_CLOCK_SPEED_STANDARD_MODE //標(biāo)準(zhǔn)模式(最高100kHz)
LL_I2C_CLOCK_SPEED_FAST_MODE //高速模式(最高400kHz)
@note ※高速模式下可設(shè)置信號(hào)占空比
*/
void LL_I2C_SetPeriphClock(I2C_TypeDef *I2Cx, uint32_t PeriphClock);/*
設(shè)置模塊的輸入時(shí)鐘(e.g.36Mhz,84Mhz...);單位Hz,函數(shù)自動(dòng)與10MHz對(duì)齊;
@reg CR2- >FREQ
*/
uint32_t LL_I2C_GetPeriphClock(I2C_TypeDef *I2Cx);/*
讀取模塊的輸入時(shí)鐘(由上一函數(shù)設(shè)置)
@reg CR2- >FREQ =@retval
*/
void LL_I2C_SetDutyCycle(I2C_TypeDef *I2Cx, uint32_t DutyCycle);/*
設(shè)置信號(hào)占空比(※僅高速模式)
@reg CCR- >DUTY
@ref LL_I2C_DUTYCYCLE_2 //低:高=2
LL_I2C_DUTYCYCLE_16_9 //低:高=16:9
*/
uint32_t LL_I2C_GetDutyCycle(I2C_TypeDef *I2Cx);/*
獲取信號(hào)占空比(僅高速模式);
@reg CCR- >DUTY
*/
void LL_I2C_SetRiseTime(I2C_TypeDef *I2Cx, uint32_t RiseTime);/*
設(shè)置主模式下SCL的最大上升時(shí)間。
@reg TRISE- >TRISE[5:0]
@note 默認(rèn)值0x02 計(jì)算方法請(qǐng)?jiān)敿?xì)參看MANUAL
*/
uint32_t LL_I2C_GetRiseTime(I2C_TypeDef *I2Cx);/*
獲取主模式下SCL的最大上升時(shí)間。
@retval = TRISE[5:0]
*/
時(shí)鐘配置整合函數(shù)(優(yōu)先使用):
void LL_I2C_ConfigSpeed(I2C_TypeDef I2Cx, uint32_t PeriphClock, uint32_t ClockSpeed,
uint32_t DutyCycle);/
配置輸入時(shí)鐘、時(shí)鐘周期、占空比(高速模式下)
*/
8.SMbus部分
暫不補(bǔ)充
9.關(guān)鍵控制
①ACK控制(接收時(shí))
void LL_I2C_AcknowledgeNextData(I2C_TypeDef I2Cx, uint32_t TypeAcknowledge);/
配置應(yīng)答使能(是否接收到一個(gè)數(shù)據(jù)(地址或數(shù)據(jù))后返回一個(gè)應(yīng)答)
@reg CR1->ACK
@ref LL_I2C_ACK //返回應(yīng)答
LL_I2C_NACK //不返回應(yīng)答
*/
②生成起始條件與終止條件
void LL_I2C_GenerateStartCondition(I2C_TypeDef I2Cx);/
生成起始條件(S),可與SB配合檢測(cè)起始條件的生成狀況
@reg CR1->START
@note 起始條件發(fā)送后START位自動(dòng)清除
*/
void LL_I2C_GenerateStopCondition(I2C_TypeDef I2Cx);/
發(fā)送終止條件(P)
@reg CR1->STOP
@note 終止條件發(fā)送后STOP位自動(dòng)清除
*/
③讀取/發(fā)送操作
uint8_t LL_I2C_ReceiveData8(I2C_TypeDef I2Cx);/
接收8位數(shù)據(jù)。
讀取一次DR,獲得8位數(shù)據(jù)
*/
void LL_I2C_TransmitData8(I2C_TypeDef I2Cx, uint8_t Data);/
發(fā)送8位數(shù)據(jù)。
向DR寫(xiě)入一個(gè)字節(jié)
*/
I2C中斷
(摘自RM008)
從中可以看出,I2C模塊的中斷掩碼非常少,一旦開(kāi)啟可靠性將大大降低,因此一般不使用中斷功能
中斷總共有兩個(gè)入口,條件檢測(cè)、中斷配置類似UART和SPI
中斷掩碼控制:
void LL_I2C_EnableIT_BUF(I2C_TypeDef I2Cx);/
置位ITBUFEN
*/
void LL_I2C_DisableIT_BUF(I2C_TypeDef I2Cx);/
清零ITBUFEN
*/
void LL_I2C_EnableIT_ERR(I2C_TypeDef I2Cx);/
置位ITERREN
*/
void LL_I2C_DisableIT_ERR(I2C_TypeDef I2Cx);/
清零ITERREN
*/
void LL_I2C_EnableIT_EVT(I2C_TypeDef I2Cx);/
置位ITEVTEN
*/
void LL_I2C_DisableIT_EVT(I2C_TypeDef I2Cx);/
清零ITEVTEN
*/
I2C狀態(tài)判斷 ※在軟件方式使用I2C時(shí)非常重要
讀取狀態(tài)位判斷的格式為 LL_I2C_IsActiveFlag_XXX()
使用請(qǐng)參見(jiàn)前面的時(shí)序圖。
DMA控制
I2C模塊同樣可以配置DMA傳輸,這通常使用在主模式下傳輸大量數(shù)據(jù)的情況。
但LL庫(kù)使用DMA時(shí)容易發(fā)生通訊錯(cuò)誤,因此不推薦使用。
評(píng)論
查看更多