STM32-I2C_CheckEvent-標誌位自動清除理解
STM32裡I2C_CheckEvent函式我們應該是相當熟悉了,在每次傳送資料後我們都需要檢驗相應的EVx(x = 0,1,2,,,)事件是否有傳送。
函式定義如下:
1 ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT) 2 { 3 uint32_t lastevent = 0; 4 uint32_t flag1 = 0, flag2 = 0; 5 ErrorStatus status = ERROR; 6 7 /* Check the parameters */ 8 assert_param(IS_I2C_ALL_PERIPH(I2Cx)); 9 assert_param(IS_I2C_EVENT(I2C_EVENT)); 10 11 /* Read the I2Cx status register */ 12 flag1 = I2Cx->SR1; 13 flag2 = I2Cx->SR2; 14 flag2 = flag2 << 16; 15 16 /* Get the last event value from I2C status register */ 17 lastevent = (flag1 | flag2) & FLAG_Mask; 18 19 /* Check whether the last event contains the I2C_EVENT */ 20 if ((lastevent & I2C_EVENT) == I2C_EVENT) 21 { 22 /* SUCCESS: last event is equal to I2C_EVENT */ 23 status = SUCCESS; 24 } 25 else 26 { 27 /* ERROR: last event is different from I2C_EVENT */ 28 status = ERROR; 29 } 30 /* Return status */ 31 return status; 32 }
該函式第一個引數是輸入需要檢查的I2Cx(x = 1,2,3,4,5)外設,第二個引數是檢查的事件,如下所示:
I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED : EV1
I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED : EV1
I2C_EVENT_SLAVE_TRANSMITTER_SECONDADDRESS_MATCHED : EV1
I2C_EVENT_SLAVE_RECEIVER_SECONDADDRESS_MATCHED : EV1I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED : EV1
I2C_EVENT_SLAVE_BYTE_RECEIVED : EV2
(I2C_EVENT_SLAVE_BYTE_RECEIVED | I2C_FLAG_DUALF) : EV2
(I2C_EVENT_SLAVE_BYTE_RECEIVED | I2C_FLAG_GENCALL) : EV2
I2C_EVENT_SLAVE_BYTE_TRANSMITTED : EV3
(I2C_EVENT_SLAVE_BYTE_TRANSMITTED | I2C_FLAG_DUALF) : EV3(I2C_EVENT_SLAVE_BYTE_TRANSMITTED | I2C_FLAG_GENCALL) : EV3
I2C_EVENT_SLAVE_ACK_FAILURE : EV3_2
I2C_EVENT_SLAVE_STOP_DETECTED : EV4
I2C_EVENT_MASTER_MODE_SELECT : EV5
I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED : EV6
I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED : EV6
I2C_EVENT_MASTER_BYTE_RECEIVED : EV7
I2C_EVENT_MASTER_BYTE_TRANSMITTING : EV8
I2C_EVENT_MASTER_BYTE_TRANSMITTED : EV8_2
I2C_EVENT_MASTER_MODE_ADDRESS10 : EV9
本文就舉裡面常用的一些事件為例,來分析該函式為什麼能夠自動清除標誌位。包含EV5,EV6,EV8以及EV7事件。
在使用I2C傳送資料時我們會用到EV5,EV6,EV8事件,事件名稱及定義如下:
/*I2C_EVENT_MASTER_MODE_SELECT : EV5*/ #define I2C_EVENT_MASTER_MODE_SELECT ((uint32_t)0x00030001) /* BUSY, MSL and SB flag */ /*I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED : EV6 */ #define I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) /* BUSY, MSL, ADDR and TRA flags */ /*I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED : EV6*/ #define I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ((uint32_t)0x00030002) /* BUSY, MSL and ADDR flags */ /*I2C_EVENT_MASTER_BYTE_TRANSMITTING : EV8*/ #define I2C_EVENT_MASTER_BYTE_TRANSMITTING ((uint32_t)0x00070080) /* TRA, BUSY, MSL, TXE flags */ /*I2C_EVENT_MASTER_BYTE_TRANSMITTED : EV8_2*/ #define I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint32_t)0x00070084) /* TRA, BUSY, MSL, TXE and BTF flags */
- 根據I2C_CheckEvent函式的定義,事件的高16位為I2C外設的SR2暫存器,低16位為I2C外設的SR1暫存器。
- 先來看看 I2C_EVENT_MASTER_MODE_SELECT,巨集定義為,0x00030001,對應的SR1和SR2暫存器如下所示:
其中MSL為1表為主模式,BUSY為1表匯流排忙碌,
這兩位一般都是在產生STOP訊號的時候置0,其他時候都為1。
看看SB位如何清零,
我們在Check_Event函式裡面讀取了SR1暫存器,我們在傳送了起始訊號之後就需要傳送裝置地址進行訪問,在I2C_Send7bitAddress函式裡面我們訪問了資料暫存器SD,於是在下一次檢測標誌位之前SB被清除。
- 再來看看兩個EV6事件 I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED 和 I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED,這兩者的區別就是一個用於傳送模式,另一個用於接受模式,傳送模式為0x00070082,
TRA資料單元一般產生STOP訊號後清除,至於ADDR位,在I2C_CheckEvent函式裡面,我們是順序地讀取了SR1和SR2暫存器,於是ADDR位被清除。對於TxE位,我們下一步能會進行資料傳送操作,也就是使用I2C_SendData函式訪問DR資料暫存器,於是TxE也被清除。
- 還有一個EV8事件 I2C_EVENT_MASTER_BYTE_TRANSMITTED, 定義為0x00070084,
此處只討論BTF位的清除,
也是訪問SR1暫存器和對資料暫存器的讀或寫可以清除該位,因此BTF位也被清除。
至於I2C_CheckEvent裡面其他事件所設計的位清除,我就不一一舉例了,可以按照這個思路,參考STM32F10x-中文參考手冊自己一步步的檢視。
I2C_ChencEvent比I2C_GetFlagStatus函式好的一點就是它檢測了與事件相關的所有暫存器位,而後者只檢測提供的標誌位。
&n