你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

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

[复制链接]
aimejia 发布时间:2018-5-23 14:50
一、简单说明
本例子参考了ST官方历程,官方历程的链接如下

http://www.st.com/content/st_com ... /stsw-stm32094.html

关于i2c的协议这里就不做描述了

关于STM32 i2c的模式可以在中文数据手册中查看

1.png

手册中已经描述,该模块默认工作在从模式,要想变为主模式,主要生产一个起始条件。(主模式的代码可以参考野火开发板的硬件i2c历程,本例子中也是使用野火开发板硬件i2c作为主机的)

二、i2c从机的配置
  1. [cpp] view plain copy
  2.     I2C_DeInit(I2C1);  
  3.     /* I2C1 configuration ------------------------------------------------------*/  
  4.     I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;//模式  
  5.     I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;  
  6.     I2C_InitStructure.I2C_OwnAddress1 = I2C_SLAVE_ADDRESS7;//这个就是作为从机的地址,一定要配置正确  
  7.     I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;  
  8.     I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//7位的地址  
  9.     I2C_InitStructure.I2C_ClockSpeed = ClockSpeed;  
  10.     I2C_Init(I2C1, &I2C_InitStructure);  
复制代码
上面配置注意的就是从机地址,这就是主机要查询的从机地址

三、i2c从机中断的配置
  1. [cpp] view plain copy
  2.     /* Configure and enable I2Cx event interrupt -------------------------------*/  
  3.     NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;  
  4.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
  5.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  
  6.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
  7.     NVIC_Init(&NVIC_InitStructure);  
  8.   
  9.     /* Configure and enable I2C1 error interrupt -------------------------------*/  
  10.     NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;  
  11.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  
  12.     NVIC_Init(&NVIC_InitStructure);  
复制代码
标准库中的i2c一共有两个中断
一个是事件中断(EV_IRQ)和一个错误中断(ER_IRQ)
EV_IRQ的中断只要响应EV1 EV2 EV4 之类的,后面会说明
ER_IRQ的中断只要响应没有应答和起始和停止条件出错等

四、使能中断
  1. [cpp] view plain copy
  2. /* Enable I2C1 event and buffer interrupts */  
  3.   
  4. I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, ENABLE);  
  5.   
  6. /* Enable I2C1 Error interrupts */  
  7.   
  8. I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE);  
复制代码
使能了I2C1的这三个中断,每个中断的作用下面说明

五、中断处理函数
  1. [cpp] view plain copy
  2. void I2C1_EV_IRQHandler(void)      
  3.   
  4. //事件中断处理函数   
  5.   
  6. {   
  7.   
  8. switch (I2C_GetLastEvent(I2C1))  
  9.   
  10. //获取i2c1的中断事件   
  11.   
  12. {   
  13.   
  14.   /* Slave Transmitter ---------------------------------------------------*/   
  15.   
  16. case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:   
  17.   
  18.   /* 这个和下面那个都是从发送模式下发送数据的,具体两个的区别我也不是很明白,感觉就是移位寄存器空与非  空的区别,准备好数据发送吧 */   
  19.   
  20.   I2C_SendData(I2C1, I2C1_Buffer_Tx[Tx_Idx++]);  
  21.   
  22.    break;   
  23.   
  24. case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:             /* EV3 */      
  25.   
  26.   /* Transmit I2C1 data */  
  27.   
  28.   I2C_SendData(I2C1, I2C1_Buffer_Tx[Tx_Idx++]);   
  29.   
  30.    break;   
  31.   
  32. /* Slave Receiver ------------------------------------------------------*/   
  33.   
  34. case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:     /* EV1 */   
  35.   
  36.   /* 地址匹配中断,不管从发送和接收都要匹配地址,如下图244、243发送地址之后都会响应EV1 */   
  37.   
  38.   break;   
  39.   
  40. case I2C_EVENT_SLAVE_BYTE_RECEIVED:                /* EV2 */   
  41.   
  42.   /* Store I2C1 received data */   
  43.   
  44.   /* 这个中断就是响应EV2中断,如下图244,每次主机发送完一个数据就会产生一个EV2的中断 */   
  45.   
  46.   I2C1_Buffer_Rx[Rx_Idx++] = I2C_ReceiveData(I2C1);  
  47.   
  48.   /* 把接收到的中断填充到数组中 */   
  49.   
  50.   /* 注意:地址不会填充进来的 */  
  51.   
  52.    break;   
  53.   
  54. case I2C_EVENT_SLAVE_STOP_DETECTED:                /* EV4 */  
  55.   
  56.    /* Clear I2C1 STOPF flag */   
  57.   
  58.   /* 这个就是正常停止的时候产生的一个停止信号 */   
  59.   
  60.   I2C_Cmd(I2C1, ENABLE);   
  61.   
  62.   /* 我也不清楚这个为什么要这样,如果接收完一串数据之后,不响应主机的情况可以 关闭i2c,然后在处理完数据后再  从新配置i2c,记得是从新配置 */   
  63.   
  64.   Rx_Idx=0;   
  65.   
  66.   i2c_event = EVENT_OPCOD_NOTYET_READ;   
  67.   
  68.   break;   
  69.   
  70. default:   
  71.   
  72.   break;      
  73.   
  74.   }   
  75.   
  76. }   
  77.   
  78. void I2C1_ER_IRQHandler(void)   
  79.   
  80. {   
  81.   
  82. /* Check on I2C1 AF flag and clear it */   
  83.   
  84. if (I2C_GetITStatus(I2C1, I2C_IT_AF))   
  85.   
  86. {   
  87.   
  88.   /* 这个就是图243中最后那个没有应答的中断,也就是发送了一串数据后的中断,可以做清零工作 */   
  89.   
  90.   I2C_ClearITPendingBit(I2C1, I2C_IT_AF);   
  91.   
  92.   Tx_Idx = 0;   
  93.   
  94.   i2c_event = EVENT_OPCOD_NOTYET_READ;   
  95.   
  96. }   
  97.   
  98. /* Check on I2C1 AF flag and clear it */   
  99.   
  100. if (I2C_GetITStatus(I2C1, I2C_IT_BERR))   //这个就是起始和停止条件出错了  
  101.   
  102. {   
  103.   
  104.   I2C_ClearITPendingBit(I2C1, I2C_IT_BERR);  
  105.   
  106.   }  
  107.   
  108. }  
复制代码
2.png

3.png

注意:i2c中断中不要printf打印信息,否则会出错

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

4.png

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


转载自酱油师兄

收藏 评论0 发布时间:2018-5-23 14:50

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版