I2C簡(jiǎn)介
I2C總線是一個(gè)兩線串行接口,包含串行數(shù)據(jù)線(SDA)與串行時(shí)鐘線(SCL),能夠在連接到總線的器件間傳遞信息,每一個(gè)連接總線的設(shè)備都有獨(dú)立的地址,主機(jī)可以通過該地址選擇連接總線的設(shè)備并與之通信。I2C通過對(duì)SCL和SDA線高低電平時(shí)序的控制,來產(chǎn)生I2C總線協(xié)議所需要的信號(hào),從而進(jìn)行數(shù)據(jù)傳輸,微控制器可通過I2C總線接口實(shí)現(xiàn)芯片間串行互聯(lián)。
I2C的功能框圖如圖1所示,當(dāng)I2C采用主模式進(jìn)行數(shù)據(jù)傳輸時(shí),主機(jī)先發(fā)送從機(jī)設(shè)備地址與讀寫位數(shù)據(jù),在從機(jī)地址匹配時(shí)可進(jìn)行數(shù)據(jù)傳輸;I2C采用從模式時(shí),從設(shè)備等待接收由主機(jī)發(fā)送來的地址數(shù)據(jù),地址匹配時(shí)可進(jìn)行數(shù)據(jù)傳輸。

主機(jī)與從機(jī)
主機(jī)是初始化總線的數(shù)據(jù)傳輸并產(chǎn)生允許傳輸?shù)臅r(shí)鐘信號(hào)的器件。此時(shí),任何被尋址的器件都被認(rèn)為是從機(jī),在主模式下只支持一個(gè)主機(jī)。
設(shè)備地址
在進(jìn)行數(shù)據(jù)傳輸前需要發(fā)送從設(shè)備地址,只有當(dāng)主機(jī)的發(fā)送設(shè)備地址與從機(jī)的設(shè)備地址匹配時(shí)才能進(jìn)行數(shù)據(jù)傳輸。總線的每個(gè)器件都有一個(gè)唯一的地址識(shí)別,而且都可以作為一個(gè)發(fā)送或接收器。
I2C信號(hào)
起始信號(hào)
當(dāng)總線處于空閑狀態(tài)時(shí),SCL和SDA同時(shí)被外部上拉電阻拉為高電平。當(dāng)主機(jī)啟動(dòng)數(shù)據(jù)傳輸時(shí),必須先產(chǎn)生一個(gè)起始信號(hào)。在SCL線是高電平時(shí), SDA線從高電平向低電平切換表示起始信號(hào),如圖2所示。在起始信號(hào)產(chǎn)生后,總線處于忙碌狀態(tài),除當(dāng)前數(shù)據(jù)傳輸?shù)闹鲝脑O(shè)備外,其他I2C器件無法訪問總線。

停止信號(hào)
停止信號(hào)如圖2所示,當(dāng)主機(jī)結(jié)束傳輸時(shí)要發(fā)送停止信號(hào),在SCL線為高電平、SDA線由低電平向高電平切換時(shí),產(chǎn)生停止信號(hào),從而釋放總線,總線再次處于空閑狀態(tài)。
應(yīng)答信號(hào)
I2C具有完善的應(yīng)答機(jī)制,當(dāng)主機(jī)發(fā)送完成地址與讀寫位或者主機(jī)發(fā)送一個(gè)字節(jié)的數(shù)據(jù)到從機(jī)上時(shí),從機(jī)會(huì)回應(yīng)一個(gè)應(yīng)答信號(hào)(ACK),即在第9個(gè)SCL時(shí)鐘周期時(shí)拉低SDA,如圖3所示。

非應(yīng)答信號(hào)
如圖3所示,當(dāng)?shù)?個(gè)SCL時(shí)鐘周期時(shí)拉高SDA,表示為非應(yīng)答信號(hào),主機(jī)或從機(jī)將產(chǎn)生一個(gè)停止信號(hào)中止傳輸。
讀寫位
在傳輸設(shè)備地址時(shí)會(huì)跟隨1bit的讀寫位數(shù)據(jù),該讀寫位決定當(dāng)前數(shù)據(jù)傳輸方向。如圖4所示,起始信號(hào)后發(fā)送從設(shè)備地址及讀寫位數(shù)據(jù),當(dāng)讀寫位為1時(shí),執(zhí)行讀操作;讀寫位為0時(shí),執(zhí)行寫操作。

I2C配置
I2C的配置包括傳輸速率、從設(shè)備地址、數(shù)據(jù)傳輸方向及主從模式選擇的配置,從而進(jìn)行數(shù)據(jù)傳輸。
工作速率
I2C存在兩種工作速率模式:標(biāo)準(zhǔn)模式(數(shù)據(jù)傳輸速率為0 ~ 100Kbps),快速模式(數(shù)據(jù)傳輸速率最大為400Kbps);可通過I2C控制寄存器(I2C_CR)的SPEED位進(jìn)行控制,由于I2C從機(jī)速率跟隨主機(jī)速率,因此只需在I2C為主模式下配置工作速率,如圖5所示。

地址格式
I2C有兩種地址格式:7位地址格式和10位地址格式。
7位地址
如圖6所示,在起始條件(S)后發(fā)送的一個(gè)字節(jié)的前7位(A6 ~ A0)為從機(jī)地址,最低位(R/W)是數(shù)據(jù)方向位,當(dāng)R/W位為0,表示主機(jī)寫數(shù)據(jù)到從機(jī),R/W位為1表示主機(jī)從從機(jī)讀數(shù)據(jù)。

10位地址
在10位的地址格式中,發(fā)送2個(gè)字節(jié)來傳輸10位地址。發(fā)送的第一個(gè)字節(jié)的起始位后的5位(bit7:3)用于告示從機(jī)接下來是10位的傳輸,第一個(gè)字節(jié)的后兩位(bit2:1)是從機(jī)地址的bit9:8,最低位(bit 0)是數(shù)據(jù)方向位(R/W)。傳輸?shù)牡诙€(gè)字節(jié)為10位地址的低八位,如圖7所示。

寫操作
I2C進(jìn)行寫操作時(shí),先通過I2C目標(biāo)地址寄存器(I2C_TAR)配置從設(shè)備地址,再配置讀寫位,令控制數(shù)據(jù)命令寄存器(I2C_DR)的CMD位為0,所需傳輸數(shù)據(jù)放入I2C_DR寄存器的DR位,進(jìn)行寫操作。
讀操作
I2C進(jìn)行讀操作時(shí),先由主機(jī)寫從設(shè)備地址及設(shè)備內(nèi)寄存器地址,當(dāng)從設(shè)備地址及設(shè)備內(nèi)寄存器地址發(fā)送完成后,將控制數(shù)據(jù)命令寄存器(I2C_DR)的CMD位為1,進(jìn)行讀操作,讀出設(shè)備內(nèi)寄存器地址中的數(shù)值。

主模式
I2C主模式配置需在I2C未使能狀態(tài)下進(jìn)行,將I2C使能寄存器(I2C_IMR)的ENABLE位置0。通過配置控制寄存器(I2C_CR)的SPEED位選擇速率模式,MASTER10位選擇地址格式,DISSLAVE位為1使從模式禁止,MASTER位為1選擇主模式。向目標(biāo)地址寄存器(I2C_TAR)寫入從設(shè)備地址,I2C_IMR寄存器的ENABLE位置1,使能I2C。
I2C 接口支持讀寫的動(dòng)態(tài)切換,當(dāng)發(fā)送數(shù)據(jù)時(shí),寫數(shù)據(jù)到I2C的RX/TX數(shù)據(jù)緩沖及命令寄存器(DR)的低字節(jié)中,配置CMD位為0產(chǎn)生寫操作。接下來的讀命令,需要確保CMD位為1。如果發(fā)送FIFO為空,I2C模塊拉低SCL直到下個(gè)命令寫入到發(fā)送FIFO中。
從模式
I2C做從機(jī)時(shí),等待其他主機(jī)的訪問,只有其他主機(jī)發(fā)送了I2C從機(jī)對(duì)應(yīng)的設(shè)備地址,才能進(jìn)行數(shù)據(jù)傳輸。配置I2C為從模式,將I2C使能寄存器(I2C_IMR)的ENABLE位置0,禁止I2C使能,將I2C自身從地址寫入從機(jī)地址寄存器(I2C_SAR),配置控制寄存器(I2C_CR)的SLAVE10選擇尋址格式,DISSLAVE位為0,選擇從模式,MASTER位為0,禁止主模式;I2C_IMR寄存器的ENABLE位置1,使能I2C。
當(dāng)其他主機(jī)發(fā)送地址與 SAR 寄存器中的從機(jī)地址匹配,I2C接口響應(yīng)發(fā)送的地址,并識(shí)別傳輸方向;當(dāng)I2C產(chǎn)生讀請(qǐng)求,從機(jī)將數(shù)據(jù)發(fā)送至主機(jī);當(dāng)主機(jī)為寫操作時(shí),I2C從機(jī)接收到主機(jī)的數(shù)據(jù)并將數(shù)據(jù)存儲(chǔ)在接收緩沖中,軟件通過讀DR寄存器中的bit7:0來獲得接收到的數(shù)據(jù)。
實(shí)驗(yàn)
本實(shí)驗(yàn)使用輪詢進(jìn)行數(shù)據(jù)的寫操作與讀操作,初始化配置I2C為主模式,從設(shè)備地址為0x50,速率為100KHz,使用7位地址格式。I2C初始化后,按下一次任意按鍵,進(jìn)行8字節(jié)數(shù)據(jù)的寫操作,其中第一字節(jié)寫入數(shù)據(jù)設(shè)置為設(shè)備內(nèi)的寄存器地址,串口顯示寫入數(shù)據(jù);寫操作完成后,再次按下任意按鍵,進(jìn)行7位數(shù)據(jù)的讀操作,從設(shè)備的寄存器地址中讀出相關(guān)數(shù)據(jù)。
啟用I2C外設(shè)時(shí)鐘 enable_clock()
實(shí)驗(yàn)使用I2C1,串口打印輸出結(jié)果,串口使用引腳屬于GPIOA組,I2C使用引腳屬于GPIOB組,因此需要啟用I2C1、UART1、GPIOA及GPIOB的外設(shè)時(shí)鐘。
voidenable_clock()
{
/*EnableI2C1clock.*/
RCC->APB1ENR|=RCC_APB1_PERIPH_I2C1;
/*EnableGPIOAclock.*/
RCC->AHB1ENR|=RCC_AHB1_PERIPH_GPIOA;
/*EnableGPIOBclock.*/
RCC->AHB1ENR|=RCC_AHB1_PERIPH_GPIOB;
/*EnableUART1clock.*/
RCC->APB2ENR|=RCC_APB2_PERIPH_UART1;
}
配置引腳 pin_init()
配置I2C1引腳,I2C1_SCL為PB6引腳,I2C1_SDA為PB7引腳,復(fù)用通道為AF1;由于實(shí)驗(yàn)現(xiàn)象通過串口顯示,故配置UART的TX(PA9)與RX(PA10)引腳。
voidpin_init()
{
/*PB6-I2C1_SCL.*/
GPIOB->CRL&=~GPIO_CRL_MODE6_MASK;
GPIOB->CRL&=~GPIO_CRL_CNF6_MASK;
GPIOB->CRL|=GPIO_CRL_MODE6(GPIO_Speed_50MHz);
GPIOB->CRL|=GPIO_CRL_CNF6(GPIO_PinMode_AF_OpenDrain);
GPIOB->AFRL&=~GPIO_AFRL_AFRY_MASK;
GPIOB->AFRL|=(GPIO_AF_1<
/*PB7-I2C1_SDA.*/
GPIOB->CRL&=~GPIO_CRL_MODE7_MASK;
GPIOB->CRL&=~GPIO_CRL_CNF7_MASK;
GPIOB->CRL|=GPIO_CRL_MODE7(GPIO_Speed_50MHz);
GPIOB->CRL |= GPIO_CRL_CNF7(GPIO_PinMode_AF_OpenDrain);
GPIOB->AFRL|=(GPIO_AF_1<
/*PA9-UART_TX.*/
GPIOA->CRH&=~GPIO_CRH_MODE9_MASK;
GPIOA->CRH&=~GPIO_CRH_CNF9_MASK;
GPIOA->CRH|=GPIO_CRH_MODE9(GPIO_Speed_50MHz);
GPIOA->CRH|=GPIO_CRH_CNF9(GPIO_PinMode_AF_PushPull);
GPIOA->AFRH|=(GPIO_AF_1<
/*PA10-UART_RX.*/
GPIOA->CRH&=~GPIO_CRH_MODE10_MASK;
GPIOA->CRH&=~GPIO_CRH_CNF10_MASK;
GPIOA->CRH|=GPIO_CRH_CNF10(GPIO_PinMode_In_Floating);
GPIOA->AFRH|=(GPIO_AF_1<
}
UART初始化 uart_init()
初始化UART,配置時(shí)鐘頻率、波特率、數(shù)據(jù)長(zhǎng)度、停止位、傳輸模式及是否使用校驗(yàn)。
voiduart_init()
{
/*Clearthecorrespondingbittobeused.*/
UART1->CCR&=~(UART_CCR_PEN_MASK|UART_CCR_PSEL_MASK|UART_CCR_SPB0_MASK|UART_CCR_SPB1_MASK|UART_CCR_CHAR_MASK);
UART1->GCR&=~(UART_GCR_AUTOFLOWEN_MASK|UART_GCR_RXEN_MASK|UART_GCR_TXEN_MASK);
/*WordLength.*/
UART1->CCR|=UART_CCR_CHAR_MASK;
/*XferMode.*/
UART1->GCR|=(UART_XferMode_RxTx<
/*Setupbaudrate,BOARD_DEBUG_UART_FREQ=48000000u,BOARD_DEBUG_UART_BAUDRATE=9600u.*/
UART1->BRR=(BOARD_DEBUG_UART_FREQ/BOARD_DEBUG_UART_BAUDRATE)/16u;
UART1->FRA=(BOARD_DEBUG_UART_FREQ/BOARD_DEBUG_UART_BAUDRATE)%16u;
/*EnableUART1.*/
UART1->GCR|=UART_GCR_UARTEN_MASK;
}
I2C初始化 i2c_init()
I2C通過操作配置寄存器(I2C_CR)實(shí)現(xiàn)初始化,配置I2C為主模式、速率為100KHz、7位地址格式、時(shí)鐘頻率為60000000u,設(shè)置從設(shè)備地址為0x50,使能I2C。
voidi2c_init()
{
I2C1->ENR&=~I2C_ENR_ENABLE_MASK;
uint32_ttmp=BOARD_I2C_FREQ/I2C_BaudRate_100K;/*BOARD_I2C_FREQ=60000000u,I2C_BaudRate_100K=100000u.*/
I2C1->SSHR=tmp/2u-12u;/*Configurehighlevelcountinnormalspeed.*/
I2C1->SSLR=tmp/2u-1u; /*Configurelowlevelcountinnormalspeed.*/
I2C1->CR=I2C_CR_SPEED(1u);
I2C1->CR&=~I2C_CR_MASTER10_MASK; /*Addressformat.*/
I2C1->CR|=I2C_CR_RESTART_MASK /*Generaterestartsignal.*/
|I2C_CR_DISSLAVE_MASK /*Disableslavemodule.*/
|I2C_CR_REPEN_MASK /*Enablesendingrestartcondition.*/
|I2C_CR_EMPINT_MASK /*Controltx_emptyinterruptgeneration.*/
|I2C_CR_MASTER_MASK; /*Enablemastermodule.*/
I2C1->RXTLR=0u; /*Configurethesendingreceivevalue.*/
I2C1->TXTLR=0u; /*Configurethesendingthresholdvalue.*/
/*Setuptargetaddress.*/
I2C1->TAR=I2C_TAR_ADDR(APP_I2C_TARGET_ADDR);/*APP_I2C_TARGET_ADDR=0x50.*/
I2C1->ENR|=I2C_ENR_ENABLE_MASK; /*EnableI2C.*/
}
I2C寫操作 i2c_write()
設(shè)置I2C發(fā)送數(shù)組i2c_tx_buf及發(fā)送數(shù)據(jù)長(zhǎng)度i2c_tx_len,將數(shù)組i2c_tx_buf的第一個(gè)數(shù)值設(shè)置為寄存器地址,發(fā)送8字節(jié)數(shù)據(jù)。數(shù)據(jù)發(fā)送后讀取狀態(tài)寄存器(I2C_SR),等待發(fā)送緩沖空,再進(jìn)行下一次發(fā)送;數(shù)據(jù)傳輸完成,操作使能寄存器的ABORT位為1,使I2C停止數(shù)據(jù)傳輸;讀清除TX_ABRT中斷寄存器(I2C_TXABRT),將TX FIFO從刷新/復(fù)位狀態(tài)中釋放。
voidi2c_write()
{
I2C1->DR=I2C_DR_DAT(i2c_tx_buf[0]);
while(0u==(I2C1->SR&I2C_STATUS_TX_EMPTY))
{
}
for(uint32_ti=1u;i
{
I2C1->DR=I2C_DR_DAT(i2c_tx_buf[i]);
while(0u==(I2C1->SR&I2C_STATUS_TX_EMPTY)) /*Waittotxfifoempty.*/
{
}
}
I2C1->ENR|=I2C_ENR_ABORT_MASK; /*Prepareforthestop.*/
I2C1->TXABRT; /*Readregistertoreleasetxfifo.*/
while(I2C1->SR&I2C_STATUS_ACTIVE) /*WaittoI2Cnotactive,whichmeansstopistakingeffect.*/
{
}
}
I2C讀操作 i2c_read()
設(shè)置I2C接收數(shù)組i2c_rx_buf及接收長(zhǎng)度i2c_rx_len,在進(jìn)行數(shù)據(jù)讀取前,需要發(fā)送從設(shè)備地址及寄存器地址,本實(shí)驗(yàn)設(shè)置發(fā)送數(shù)組的第一個(gè)數(shù)據(jù)為寄存器地址,發(fā)送完成后再將I2C_DR寄存器的讀寫位(CMD)置1,讀取I2C_DR寄存器進(jìn)行讀操作。讀操作結(jié)束后,操作使能寄存器的ABORT位為1,使I2C停止數(shù)據(jù)傳輸。
voidi2c_read()
{
I2C1->DR=I2C_DR_DAT(i2c_tx_buf[0]);
while(0u==(I2C1->SR&I2C_STATUS_TX_EMPTY))
{
}
/*Readdatafromtargetdevice.*/
for(uint32_ti=0u;i
{
I2C1->DR=I2C_DR_CMD_MASK; /*Swichread-writebittoread,preparetogetdata.*/
while(0u==(I2C1->SR&I2C_STATUS_RX_NOTEMPTY)) /*Waittorxfifonotempty.*/
{
}
i2c_rx_buf[i]=(uint8_t)I2C1->DR;
}
I2C1->ENR|=I2C_ENR_ABORT_MASK; /*Prepareforthestop.*/
I2C1->TXABRT; /*Readregistertoreleasetxfifo.*/
while(I2C1->SR&I2C_STATUS_ACTIVE) /*WaittoI2Cnotactive,whichmeansstopistakingeffect.*/
{
}
}
main()函數(shù)
main()函數(shù)結(jié)合上述操作,串口打印“i2c_master_basic example”,初始化I2C后,將發(fā)送數(shù)組設(shè)置為0到7,按下一次任意按鍵,進(jìn)行數(shù)據(jù)發(fā)送,串口顯示發(fā)送數(shù)據(jù);再次按下任意按鍵,進(jìn)行數(shù)據(jù)讀取,從寄存器地址中讀出數(shù)值,設(shè)置寄存器地址設(shè)置為發(fā)送數(shù)據(jù)的首個(gè)數(shù)據(jù),串口顯示接收數(shù)據(jù),實(shí)驗(yàn)結(jié)果如圖9所示。
intmain()
{
enable_clock();
pin_init();
uart_init();
printf("\r\ni2c_master_basicexample\r\n");
i2c_init();
for(uint32_ti=0u;i
{
i2c_tx_buf[i]=i;
}
while(1)
{
printf("pressanykeytowritei2c-eeprom.\r\n");
getchar();
i2c_write();
printf("writedata:");
for(uint32_ti=0u;i
{
printf("0x%02X,",i2c_tx_buf[i]);
}
printf("\r\n");
printf("pressanykeytoreadi2c-eeprom.\r\n");
getchar();
i2c_read();
printf("readdatafromdeviceregisteraddress:0x%02X\r\n",i2c_tx_buf[0u]);
printf("readdata:");
for(uint32_ti=0u;i
{
printf("0x%02X,",i2c_rx_buf[i]);
}
printf("\r\n");
}

-
mcu
+關(guān)注
關(guān)注
146文章
17984瀏覽量
366982 -
I2C
+關(guān)注
關(guān)注
28文章
1541瀏覽量
127863 -
靈動(dòng)微
+關(guān)注
關(guān)注
4文章
176瀏覽量
22972 -
MM32
+關(guān)注
關(guān)注
1文章
108瀏覽量
1102
發(fā)布評(píng)論請(qǐng)先 登錄
評(píng)論