STM32F103使用硬體i2c作為從機模式
阿新 • • 發佈:2019-02-09
一、簡單說明
本例子參考了ST官方歷程,官方歷程的連結如下
關於i2c的協議這裡就不做描述了
關於STM32 i2c的模式可以在中文資料手冊中檢視
手冊中已經描述,該模組預設工作在從模式,要想變為主模式,主要生產一個起始條件。(主模式的程式碼可以參考野火開發板的硬體i2c歷程,本例子中也是使用野火開發板硬體i2c作為主機的)
二、i2c從機的配置
I2C_DeInit(I2C1); /* I2C1 configuration ------------------------------------------------------*/ I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;//模式 I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = I2C_SLAVE_ADDRESS7;//這個就是作為從機的地址,一定要配置正確 I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//7位的地址 I2C_InitStructure.I2C_ClockSpeed = ClockSpeed; I2C_Init(I2C1, &I2C_InitStructure);
上面配置注意的就是從機地址,這就是主機要查詢的從機地址
三、i2c從機中斷的配置
標準庫中的i2c一共有兩個中斷 一個是事件中斷(EV_IRQ)和一個錯誤中斷(ER_IRQ) EV_IRQ的中斷只要響應EV1 EV2 EV4 之類的,後面會說明 ER_IRQ的中斷只要響應沒有應答和起始和停止條件出錯等/* Configure and enable I2Cx event interrupt -------------------------------*/ NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* Configure and enable I2C1 error interrupt -------------------------------*/ NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_Init(&NVIC_InitStructure);
四、使能中斷
/* Enable I2C1 event and buffer interrupts */
I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, ENABLE);
/* Enable I2C1 Error interrupts */
I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE);
使能了I2C1的這三個中斷,每個中斷的作用下面說明
五、中斷處理函式
void I2C1_EV_IRQHandler(void)
//事件中斷處理函式
{
switch (I2C_GetLastEvent(I2C1))
//獲取i2c1的中斷事件
{
/* Slave Transmitter ---------------------------------------------------*/
case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:
/* 這個和下面那個都是從傳送模式下發送資料的,具體兩個的區別我也不是很明白,感覺就是移位暫存器空與非 空的區別,準備好資料傳送吧 */
I2C_SendData(I2C1, I2C1_Buffer_Tx[Tx_Idx++]);
break;
case I2C_EVENT_SLAVE_BYTE_TRANSMITTING: /* EV3 */
/* Transmit I2C1 data */
I2C_SendData(I2C1, I2C1_Buffer_Tx[Tx_Idx++]);
break;
/* Slave Receiver ------------------------------------------------------*/
case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED: /* EV1 */
/* 地址匹配中斷,不管從傳送和接收都要匹配地址,如下圖244、243傳送地址之後都會響應EV1 */
break;
case I2C_EVENT_SLAVE_BYTE_RECEIVED: /* EV2 */
/* Store I2C1 received data */
/* 這個中斷就是響應EV2中斷,如下圖244,每次主機發送完一個數據就會產生一個EV2的中斷 */
I2C1_Buffer_Rx[Rx_Idx++] = I2C_ReceiveData(I2C1);
/* 把接收到的中斷填充到陣列中 */
/* 注意:地址不會填充進來的 */
break;
case I2C_EVENT_SLAVE_STOP_DETECTED: /* EV4 */
/* Clear I2C1 STOPF flag */
/* 這個就是正常停止的時候產生的一個停止訊號 */
I2C_Cmd(I2C1, ENABLE);
/* 我也不清楚這個為什麼要這樣,如果接收完一串資料之後,不響應主機的情況可以 關閉i2c,然後在處理完資料後再 從新配置i2c,記得是從新配置 */
Rx_Idx=0;
i2c_event = EVENT_OPCOD_NOTYET_READ;
break;
default:
break;
}
}
void I2C1_ER_IRQHandler(void)
{
/* Check on I2C1 AF flag and clear it */
if (I2C_GetITStatus(I2C1, I2C_IT_AF))
{
/* 這個就是圖243中最後那個沒有應答的中斷,也就是傳送了一串資料後的中斷,可以做清零工作 */
I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
Tx_Idx = 0;
i2c_event = EVENT_OPCOD_NOTYET_READ;
}
/* Check on I2C1 AF flag and clear it */
if (I2C_GetITStatus(I2C1, I2C_IT_BERR)) //這個就是起始和停止條件出錯了
{
I2C_ClearITPendingBit(I2C1, I2C_IT_BERR);
}
}
注意:i2c中斷中不要printf列印資訊, 否則會出錯
主要是參考了官方的歷程,然後自己再調整一下邏輯即可使用。