天天看點

STM32F407硬體I2C從機配置

公司項目需要用到I2C從機與上位機通信。在網上搜了搜,發現大部分都是說STM32硬體有問題的,與硬體I2C從機相關的資料很少。調通之後,想着把demo分享出來,豐富一下網上的例程。STM32F1系列稍微修改下也能适用。

#include "i2c.h"

//PB6 I2C1_SCL
//PB7 I2C1_SDA

 void MyI2C_Init(void)
 {
	  GPIO_InitTypeDef  GPIO_InitStructure;
	 I2C_InitTypeDef I2C_InitStructure;
	 NVIC_InitTypeDef NVIC_InitStructue;
	 
	 
	 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOA時鐘
	 RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//使能I2C1時鐘 
   //I2C_DeInit(I2C1);
	 I2C_InitStructure.I2C_Mode=I2C_Mode_I2C;
	 I2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2;
	 I2C_InitStructure.I2C_OwnAddress1=0x30;//I2C_SLAVE_ADDRESS7為從機位址
	 I2C_InitStructure.I2C_Ack=I2C_Ack_Enable;
	 I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;//指定位址的長度
	 I2C_InitStructure.I2C_ClockSpeed=ClockSpeed;//設定SCL時鐘頻率,
	 
	 I2C_Init(I2C1,&I2C_InitStructure);
	 
	 NVIC_InitStructue.NVIC_IRQChannel=I2C1_EV_IRQn;
	 NVIC_InitStructue.NVIC_IRQChannelPreemptionPriority =0;
	 NVIC_InitStructue.NVIC_IRQChannelSubPriority=2;
	 NVIC_InitStructue.NVIC_IRQChannelCmd=ENABLE;
	 NVIC_Init(&NVIC_InitStructue);
	 /*配置錯誤中斷,ER_IRQ的中斷隻要響應沒有應答和起始和停止條件出錯等*/
	 NVIC_InitStructue.NVIC_IRQChannel=I2C1_ER_IRQn;
	 NVIC_InitStructue.NVIC_IRQChannelSubPriority=3;
	 NVIC_Init(&NVIC_InitStructue);
	 
	 	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//模拟輸入
	 GPIO_InitStructure.GPIO_OType=GPIO_OType_OD;
   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//上拉
	 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
   GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化  
	 
	 GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_I2C1);//PB6複用為I2C1
	 GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_I2C1);//PB7複用為I2C1
	 
	 
	 
	 /*使能I2C1 event and buffer interrupt*/
	 I2C_ITConfig (I2C1,I2C_IT_EVT|I2C_IT_BUF,ENABLE);
	 
	 /*使能I2C1 Error interrupts*/
	 I2C_ITConfig(I2C1,I2C_IT_ERR,ENABLE);
	 I2C_Cmd(I2C1,ENABLE);
	 
 }

void I2C1_EV_IRQHandler(void)     //事件中斷處理函數 
{ 
	
    __IO uint16_t SR1Register =0;
    __IO uint16_t SR2Register =0; 
    SR1Register = I2C1->SR1;
    SR2Register = I2C1->SR2;

 switch (I2C_GetLastEvent(I2C1))//擷取i2c1的中斷事件 
 { 
 
  /* 從發送 Slave Transmitter ---------------------------------------------------*/  
 case I2C_EVENT_SLAVE_BYTE_TRANSMITTED: //i2c_event_slave_byte_transmitted//
 
  /* 移位寄存器為空,資料寄存器為空,在DR中寫入Data1.
     這個和下面那個都是從發送模式下發送資料的,具體兩個的差別我也不是很明白,感覺就是移位寄存器空與非  空的差別,準備好資料發送吧 
    ***** */ 
 
 I2C_SendData(I2C1, 0X88);
 
   break; 
 
 case I2C_EVENT_SLAVE_BYTE_TRANSMITTING: /* EV3 */   //i2c_event_slave_byte_transmitting 
 
  /* 
 移位寄存器非空,資料寄存器為空,通過對DR執行寫操作來清零。
 Transmit I2C1 data 
 *******/
		if(I2C1_Data_Adress_Mark==1)
		{
		//
			I2C_SendData(I2C1, I2C1_Data_Page1[I2C1_Data_Adress++]); 
		}else
		{
		I2C_SendData(I2C1, 28); 
		}
 
 
   break; 
 
 /* 從接收 Slave Receiver ------------------------------------------------------*/ 
 
 case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:     /* EV1:從接收,收到位址後響應EV1中斷 */
 
  /* 位址比對中斷,不管從發送和接收都要比對位址,如下圖244、243發送位址之後都會響應EV1 */ 
 
  break; 
 
 case I2C_EVENT_SLAVE_BYTE_RECEIVED:                /* EV2 從接收,位址後開始收到的資料*/ 
 
  /* Store I2C1 received data */ 
 
  /* 這個中斷就是響應EV2中斷,如下圖244,每次主機發送完一個資料就會産生一個EV2的中斷 */ 
	 if(I2C1_Data_Adress_Mark==0)
	 {
	  I2C1_Data_Adress=I2C_ReceiveData(I2C1);
    I2C1_Data_Adress_Mark=1;//收到資料位址,資料位址标志位置1;
	 }else if(I2C1_Data_Adress_Mark==1)
		{
		
    I2C1_Data_Page1[I2C1_Data_Adress++]=I2C_ReceiveData(I2C1);

		}
  /* 把接收到的中斷填充到數組中 */ 
 
  /* 注意:位址不會填充進來的 */
 
   break; 
 
 
 case I2C_EVENT_SLAVE_STOP_DETECTED:                /* EV4 收到STOP停止信号*/
 
   /* Clear I2C1 STOPF flag */ 
  I2C1_Data_Adress_Mark=0;
 
  /* 這個就是正常停止的時候産生的一個停止信号 */ 
 
  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)) 
 
 { 
 
  /* 沒有應答的中斷,發送了一串資料後的中斷,可以做清零工作 */  
 
  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);
 
  }
 
 }
           

繼續閱讀