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

【经验分享】STM32 IIC详解

[复制链接]
STMCU小助手 发布时间:2022-4-19 23:00
1、IIC定义
IIC 即Inter-Integrated Circuit(集成电路总线),这种总线类型是由飞利浦半导体公司(后被NXP收购)在八十年代初设计出来的一种简单、双向、二线制、同步串行总线,主要是用来连接整体电路(ICS) ,IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实时数据传输的控制源。多主多从的通讯协议。

下文将结合NXP官方的IIC手册讲解IIC协议。下载链接见文末。

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X2pwZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。速率最高400Kbit/s。

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

在1998年的修订中增加了高速模式,速率高达3.4Mbit/s。(这里不讲,只说快速模式)。

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

2、IIC协议规范
2.1 SDA和SCL信号


aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

连接到总线的器件输出级必须是漏极开路或集电极开路才能执行线与的功能,当总线空

闲时这两条线路都是高电平。SDA 和SCL 都是双向线路都通过一个电流源或上拉电阻连接到正的电源电压。一般情况下我们都采用上拉电阻的方式

2.2 数据有效性

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

在SCL高电平的时候采样,也就是有效。低电平的时候切换数据

2.3 开始和结束信号
起始条件:SCL线是高电平时,SDA线从高电平向低电平切换。

停止条件:SCL线是高电平时,SDA线从低电平向高电平切换。

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

动画展示启动信号

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X2dpZi8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

代码实现

  1. void I2C_Start(void)
  2. {
  3.   //IO输出
  4.   SDA_OUT();
  5.   SCL_OUT();
  6.   I2C_DELAY();
  7.   //IO置高
  8.   SDA_SET();  
  9.   SCL_SET();
  10.   //延时
  11.   I2C_DELAY();  
  12.   //为低
  13.   SDA_CLR();
  14.   I2C_DELAY();
  15.   I2C_DELAY();
  16.   SCL_CLR();
  17. }
复制代码


结束信号时类似的方式(不是动图)

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X2pwZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

代码实现

  1. void I2C_Stop(void)
  2. {
  3.   //IO输出
  4.   SDA_OUT();
  5.   SCL_OUT();
  6.   //IO置0
  7.   SDA_CLR();  
  8.   SCL_CLR();
  9.   I2C_DELAY();
  10.   SCL_SET();
  11.   //延时
  12.   I2C_DELAY();  
  13.   I2C_DELAY();
  14.   I2C_DELAY();
  15.   //SDA置1
  16.   SDA_SET();
  17.   I2C_DELAY();
  18.   I2C_DELAY();
  19. }
复制代码


2.4 字节格式
SDA数据线上的每个字节必须是8位,每次传输的字节数量没有限制。每个字节后必须跟一个响应位(ACK)。首先传输的数据是最高位(MSB),SDA上的数据必须在SCL高电平周期时保持稳定,数据的高低电平翻转变化发生在SCL低电平时期。

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

每一个字节后面跟着一个ACK,有ACK就可以继续写或读。NACK,就停止

ACK:主机释放总线,传输完字节最后1位后的SCL的高电处,从机拉低电平。

NACK:主机释放总线,传输完字节最后1位后的SCL的高电处,从机无响应,总线为高电平。

动画描述写入的过程

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X2dpZi8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

代码实现

  1. uint8_t I2C_Send_byte(uint8_t data)
  2. {
  3.   uint8_t k;
  4.   //发送8bit数据
  5.   for(k=0;k<8;k++){

  6.     I2C_DELAY();
  7.     if(data&0x80){
  8.       SDA_SET();
  9.     }
  10.     else{
  11.       SDA_CLR();
  12.     }
  13.     data=data<<1;
  14.     I2C_DELAY();
  15.     SCL_SET();
  16.     I2C_DELAY();
  17.     I2C_DELAY();
  18.     SCL_CLR();
  19.   }
  20.   //延时读取ACK响应
  21.   I2C_DELAY();
  22.   SDA_SET();
  23.   //置为输入线
  24.   SDA_IN();
  25.   I2C_DELAY();
  26.   SCL_SET();   
  27.   I2C_DELAY(); //这里出现了问题,延时变的无限大
  28.   //读数据
  29.   k=SDA_READ();
  30.   if(k){ NACK响应
  31.     return 0;
  32.   }
  33.   I2C_DELAY();
  34.   SCL_CLR();
  35.   I2C_DELAY();
  36.   SDA_OUT();
  37.   if(k){ NACK响应
  38.     return 0;
  39.   }
  40.   return 1;
  41. }

  42. uint8_t I2C_Receive_byte(uint8_t flg)
  43. {
  44.   uint8_t k,data;
  45.   //接收8bit数据
  46.   //置为输入线

  47.   SDA_IN();
  48.   data=0;
  49.   for(k=0;k<8;k++){
  50.     I2C_DELAY();
  51.     SCL_SET();
  52.     I2C_DELAY();
  53.     //读数据
  54.     data=data |SDA_READ();
  55.     data=data<<1;
  56.     I2C_DELAY();
  57.     SCL_CLR();
  58.     I2C_DELAY();
  59.   }
  60.   data=data>>1; //往回移动1次
  61.   //返回ACK响应
  62.   //置为输出线
  63.   SDA_OUT();
  64.   if(flg){
  65.     SDA_SET(); //输出1-NACK
  66.   }else{
  67.     SDA_CLR();//输出0-ACK
  68.   }
  69.   I2C_DELAY();
  70.   SCL_SET();
  71.   I2C_DELAY();
  72.   I2C_DELAY();
  73.   SCL_CLR();
  74.   I2C_DELAY();
  75.   SDA_OUT();
  76.   //返回读取的数据
  77.   return (uint8_t)data;
  78. }
复制代码

2.5 从机地址和读写位

开始信号—>地址—>读写位—>ACK—>数据—>ACK.............—>停止位

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

这里只说7位地址,前7位为地址,最后一位为读写位,1表示读操作,0表示写操作

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

主机发给从机数据,也就是写,没有数据转向时

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

主机立即读从机数据,从第一个字节

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

(Combined)综合数据格式

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

3、计算IIC的频率
通信频率由主机掌控,也就是代码中的延时函数决定的

从上面,我们得知最高速为400Kbit/s。我们设计300Kbit/s。

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

速率300Kbit/s,对应周期1/300ms=10/3us≈3us,4分频就是3/4us。

我们使用的延时是,1/120MHZ*3*30 =3/4us

也就是频率是300Kbit/s

和SPI类似,时钟下降沿时,数据转换,时钟上升沿时,采样数据。也就是时钟高电平数据有效。

  1. /*120Mhz时钟时,当ulCount为1时,函数耗时3个时钟,延时=3*1/120us=1/40us*/
  2. /*
  3. SystemCoreClock=120000000
  4. us级延时,延时n微秒
  5. SysCtlDelay(n*(SystemCoreClock/3000000));
  6. ms级延时,延时n毫秒
  7. SysCtlDelay(n*(SystemCoreClock/3000));
  8. m级延时,延时n秒
  9. SysCtlDelay(n*(SystemCoreClock/3));
  10. */

  11. #if defined   (__CC_ARM) /*!< ARM Compiler */
  12. __asm void
  13. SysCtlDelay(unsigned long ulCount)
  14. {
  15.     subs    r0, #1;
  16.     bne     SysCtlDelay;
  17.     bx      lr;
  18. }
  19. #elif defined ( __ICCARM__ ) /*!< IAR Compiler */
  20. void
  21. SysCtlDelay(unsigned long ulCount)
  22. {
  23.     __asm("    subs    r0, #1\n"
  24.        "    bne.n   SysCtlDelay\n"
  25.        "    bx      lr");
  26. }

  27. #elif defined (__GNUC__) /*!< GNU Compiler */
  28. void __attribute__((naked))
  29. SysCtlDelay(unsigned long ulCount)
  30. {
  31.     __asm("    subs    r0, #1\n"
  32.        "    bne     SysCtlDelay\n"
  33.        "    bx      lr");
  34. }

  35. #elif defined  (__TASKING__) /*!< TASKING Compiler */                           
  36. /*无*/
  37. #endif /* __CC_ARM */


  38. /*
  39. * @brief  SysCtlDelay
  40. * @param  ulCount 延时值,必须大于0
  41. * @retval None
  42. */
  43. void SysCtlDelay_IIC(unsigned long ulCount)
  44. {
  45.         SysCtlDelay(ulCount);
  46. }


  47. /定义时钟频率,300KHz
  48. #define I2C_DELAY()  SysCtlDelay_IIC(30)
复制代码

4、PCF8536
4.1 Acknowledge

这个地方能看到关于2.4节关于ACK和NACk的说明。

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

4.2 Addressing
这里直接给出读地址和写地址,也就是最后一位的区别

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

4.3 读写时序
其实就是按照IIC协议的

读指定器件的指定寄存器

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

主机设置完寄存器地址之后,再去读写

注意:读取多个字节,最后一个字节的回包应该是NACK

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png

主机立即从机第一个字节读取

注意:读取多个字节,最后一个字节的回包应该是NACK

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy8wUmc4RGRwQWliZlVwUU5FNlhoNWlhVzFUZTJP.png


收藏 评论0 发布时间:2022-4-19 23:00

举报

0个回答

所属标签

相似分享

官网相关资源

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