STM32F103使用硬件i2c作为从机模式

一、简单说明

本例子参考了ST官方历程,官方历程的链接如下

http://www.st.com/content/st_com/zh/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32-standard-peripheral-library-expansion/stsw-stm32094.html

关于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从机中断的配置
    /* 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);
标准库中的i2c一共有两个中断
一个是事件中断(EV_IRQ)和一个错误中断(ER_IRQ)
EV_IRQ的中断只要响应EV1 EV2 EV4 之类的,后面会说明
ER_IRQ的中断只要响应没有应答和起始和停止条件出错等
四、使能中断
/* 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打印信息,

则会出错


主要是参考了官方的历程,然后自己再调整一下逻辑即可使用。


最后的效果感觉还是挺稳定的,这篇文章主要是给大家抛砖引玉的作用,也记录一下自己调试几天的成果。
ST官网的历程还是挺多的,没遇到的知识可以去官网找找。


评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值