×
单片机 > 单片机程序设计 > 详情

STM32 I2C Slave(SMBUS)模式软件参考设计

发布时间:2020-07-08 发布时间:
|

I2C大家都很熟悉,总共2根线,CLK和DATA,stm32的I2C相信大家就更熟悉了,采用写控制器的方式,直接由控制器去完成I2C时序操作,用户无需关心具体产生的逻辑。然而,大部分情况下,使用的都是I2C Master模式,即主设备模式,很少当成slave模式即从设备模式来用,这篇文章讲的是如何把stm32  I2C当成slave模式来使用,更严格来说,本篇讲的是smbus模式。


从官网stm32手册上我们发现了smbus和I2C区别,大家自行理解:



真正使用时,可以把smbus等同于I2C来设置和使用,从代码上看,除了I2C Clock设置为20K之外,其它暂无明显区别。以下为I2C  smbus模式的设置:


void IIC_Init(void)  

 

{  

 

  GPIO_InitTypeDef GPIO_InitStructure;  

 

  I2C_InitTypeDef I2C_InitStructure;  

 

  

 

//  RCC_APB2PeriphClockCmd  (RCC_APB2Periph_GPIOB , ENABLE);  

 

  

 

   /* Configure I2C1 pins: SCL and SDA */   

 

   GPIO_InitStructure.GPIO_Pin =   GPIO_Pin_6|GPIO_Pin_7; //6:SCL 7:SDA  

 

   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  

 

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//Out_PP;  

 

   GPIO_Init(GPIOB, &GPIO_InitStructure);   

 

   

 

//   RCC_APB1PeriphClockCmd  (RCC_APB1Periph_I2C1, ENABLE);   

 

   

 

   // Initialize I2C1 clock

 

   // Reset I2C1 device clock in order to avoid non-cleared error flags

 

   //__I2C_RCC_RESET(CPAL_I2C_CLK [Device]);

 

   RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,ENABLE);

 

   RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,DISABLE);

 

   // Enable I2C1 device clock

 

   RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);

 

   

 

   I2C_DeInit(I2C1);  

 

   I2C_InitStructure.I2C_Mode = I2C_Mode_SMBusDevice;  

 

   I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;  

 

   I2C_InitStructure.I2C_OwnAddress1 = 0x76;//slave addr  

 

   I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;  

 

   I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;  

 

   I2C_InitStructure.I2C_ClockSpeed = 20000;//20K

 

   I2C_Init(I2C1, &I2C_InitStructure);  

 

   I2C_ITConfig(I2C1, I2C_IT_EVT|I2C_IT_BUF, ENABLE);  

 

   I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE);

 

   I2C_Cmd(I2C1,ENABLE);  

 

   

 

}  

 


void NVIC_Configuration(void)  

 

{  

 

  NVIC_InitTypeDef NVIC_InitStructure;  

 

 

 

     /* 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);  

 

  

 

}  

从以上代码可以看出,I2C初始化的是I2C的IO映射、工作模式I2C_Mode_SMBusDevice、slave地址0x76(可以自定义)、I2C  Clock、I2C中断向量等参数。设置完成之后,每当I2C有数据产生时,就会产生IRQ中断,同时进入中断处理函数I2C1_EV_IRQn,如下所示:


void I2C1_EV_IRQHandler(void)  

 

{  

 

uint32_t  I2CFlagStatus;  

 

static uint8_t IIC_Data=0;

 

 

 

I2CFlagStatus = I2C_GetLastEvent(I2C1);  // =>  (SR2<<16|SR1)  

 

 

 

// print_info("I2CFlagStatus=0x%x rn",I2CFlagStatus);

 

IIC1_EV_INT_Flag=1;

 

IIC_Get_Data_Flag=1;

 

 

 

if ((I2CFlagStatus & I2C_SR1_ADDR) != 0)//bit1:addr matched  

 

{

 

//print_info("4rn");

 

if(I2CFlagStatus & I2C_SR1_TXE) //bit7 Data register empty (transmitters)  

 

{//read          

 

   Rx_Idx=0;

 

   Tx_Idx = 0;    

 

   I2C_SendData(I2C1, I2C_Buffer_Tx[Tx_Idx]);

 

}

 

else

 

{   

 

}  

 

}

 

 

 

else if((I2CFlagStatus & I2C_SR1_RXNE) != 0)//bit6  RxNE    -Data register not empty (receivers))  

 

{

 

IIC_Data=I2C_ReceiveData(I2C1);

 

I2C_Buffer_Rx[Frame_Idx][Rx_Idx] = IIC_Data;

 

Rx_Idx++;

 

}

 

else if((I2CFlagStatus & I2C_SR1_STOPF) != 0)//bit4  STOPF -Stop detection (slave mode)  

 

{

 

//I2C_Buffer_Rx[0] = num-1;      

 

I2C1->CR1 |= 0x1000;//CR1_PEC_Set;  

 

Rx_Idx_t=Rx_Idx;

 

Rx_Idx=0;

 

Frame_Idx++;

 

I2C1->SR1=0;  

 

I2C1->SR2=0;  

 

}

 

else

 

{  

 

}  

 

}  

 


中断处理函数中,产生中断后,把标志位IIC_Get_Data_Flag置1,根据读到的I2CFlagStatus状态位,来获取当前I2C的状态,获取数据,然后在main函数中根据该标志位来处理I2C产生的数据,处理完成后,再把IIC_Get_Data_Flag标志位置0,这是一种很好的处理数据方法。(PS:中断处理函数不能处理太复杂及费时的事务,以免影响中断响应的实时性,所以把处理数据的过程放到main函数中)





『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
STM32单片机的复用端口初始化的步骤及方法