2012-03-26 232 views
4

我尝试在stm32f4上实现i2c从机接收器中断服务程序。 这是我的一段聪明的代码。stm32f4上的I2C从机接收器

void I2C2_EV_IRQHandler() 
    { 
    switch (I2C_GetLastEvent(I2C2)) 
    { 
    //The address sent by the master matches the own address of the peripheral 
    case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED: 
     //The slave stretches SCL low until ADDR is 
     //cleared and DR filled with the data to be sent 
     I2C_ClearFlag(I2C2,I2C_FLAG_ADDR); 
     break; 

    //The application is expecting a data byte to be received 
    case I2C_EVENT_SLAVE_BYTE_RECEIVED: 
     I2C_ReceiveData(I2C2); 
     break; 

    //The application is expecting the end of the communication 
    //Make sure that both ADDR and STOPF flags are cleared 
    //if both are found set. 
    case I2C_EVENT_SLAVE_STOP_DETECTED: 
     if(I2C_GetFlagStatus(I2C2,I2C_FLAG_ADDR) == SET) 
      I2C_ClearFlag(I2C2,I2C_FLAG_ADDR); 
     if(I2C_GetFlagStatus(I2C2,I2C_FLAG_STOPF) == SET) 
      I2C_ClearFlag(I2C2,I2C_FLAG_STOPF); 
} 

}

中断变得打来电话,输入I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED情况。 现在SCL很低。参考手册说如果我清除地址标志,时钟将继续并且数据将被发送(页579 - 从站接收器)。在我看来,如果任何数据到达,中断总是被调用,并且下一个状态将是I2C_EVENT_SLAVE_BYTE_RECEIVED。

我找不到任何来自stm或通过谷歌的例子。任何人都可以帮助我或向我展示一个例子。

+0

上面的代码中的一个错误是每种情况下缺少的确认。在我的情况下,还有其他奴隶与主人沟通。所以初始化我的奴隶后,在公共汽车上听一听。我收到一个停止位,这不是我通信的一部分。所以我不能删除停止位。同样重置ADDR标志并不像我想象的那么容易。 – 2012-03-26 21:09:16

回答

2

现在它工作。我的问题是,我无法用参考手册中的给定命令重置ADDR和STOPF寄存器。但是如果在循环中使用它,它对我来说工作得很好。在这里我的工作中断例程。

void I2C3_EV_IRQHandler() 
{ 
    switch (I2C_GetLastEvent(I2C3)) 
    { 

    case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED: 
     STM_EVAL_LEDOn(LED3); 
     STM_EVAL_LEDOff(LED5); 
     break; 

    case I2C_EVENT_SLAVE_BYTE_RECEIVED: 
     STM_EVAL_LEDToggle(LED4); 
     STM_EVAL_LEDOff(LED3); 
     I2C_InputBuffer[I2C_InputBufferIndex++] = I2C_ReceiveData(I2C3); 
     break; 

    case I2C_EVENT_SLAVE_STOP_DETECTED: 
     STM_EVAL_LEDOn(LED6); 
     STM_EVAL_LEDOff(LED4); 
     break; 
    } 

    I2C_CleanADDRandSTOPF(); 

    if(I2C_InputBufferIndex > MOTOR_PACKAGE_SIZE-1) 
    { 
     motorHandleEvent(I2C_InputBuffer); 
     I2C_InputBufferIndex = 0; 
     uint8_t resetIndex; 
     for(resetIndex = 0; resetIndex < MOTOR_PACKAGE_SIZE; resetIndex ++) 
     I2C_InputBuffer[resetIndex] = 0; 
    } 
} 

inline void I2C_CleanADDRandSTOPF() 
{ 
    while ((I2C3->SR1 & I2C_SR1_ADDR) == I2C_SR1_ADDR) 
    { 
    volatile uint32_t temp; 
    temp=I2C3->SR1; 
    temp=I2C3->SR2; 
    } 
    while ((I2C3->SR1&I2C_SR1_STOPF) == I2C_SR1_STOPF) 
    { 
    volatile uint32_t temp; 
    temp=I2C3->SR1; 
    I2C3->CR1 |= 0x1; 
    } 
} 
0

硬件正在执行时钟延伸以确保从站正在跟上主站。奴隶首先等待地址匹配。然后你在SCL保持低电平时中断。这允许从设备基本上为主设备提供流量控制。主器件检测到SCL被从器件保持为低电平,它将等待它在主器件发送更多数据之前释放。所以你不会因为接收到的数据而获得额外的中断,因为直到你让SCL变高为止,主机才会发送更多的数据。你可以阅读关于在这里延伸的时钟http://en.wikipedia.org/wiki/I%C2%B2C

+0

H TJD谢谢你的回答。但正如我所推荐的那样,我知道从设备保持SCL为低电平,直到ADDR寄存器变为已读且为空。这不是在这种情况下的问题 – 2012-03-26 21:03:58

+0

我想我很困惑你的实际问题是什么。 – TJD 2012-03-26 23:12:10