1、IIC定义

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

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

STM32 IIC详解_操作系统

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

STM32 IIC详解_操作系统 _02

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

STM32 IIC详解_操作系统 _03

 

2、IIC协议规范

2.1 SDA和SCL信号

STM32 IIC详解_操作系统 _04

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

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

2.2 数据有效性STM32 IIC详解_操作系统 _05

STM32 IIC详解_操作系统 _06

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

2.3 开始和结束信号STM32 IIC详解_操作系统 _05

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

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

STM32 IIC详解_操作系统 _08

动画展示启动信号STM32 IIC详解_操作系统 _05

STM32 IIC详解_操作系统 _10

代码实现

void I2C_Start(void)
{  //IO输出  SDA_OUT(); 
  SCL_OUT(); 
  I2C_DELAY();  //IO置高  SDA_SET();  
  SCL_SET(); 
  //延时  I2C_DELAY();  
  //为低  SDA_CLR();
  I2C_DELAY();
  I2C_DELAY();
  SCL_CLR();
}

结束信号时类似的方式(不是动图)STM32 IIC详解_操作系统 _05

STM32 IIC详解_操作系统 _12

代码实现

void I2C_Stop(void)
{  //IO输出  SDA_OUT(); 
  SCL_OUT();  //IO置0  SDA_CLR();  
  SCL_CLR(); 
  I2C_DELAY();
  SCL_SET();  //延时  I2C_DELAY();  
  I2C_DELAY();
  I2C_DELAY();  //SDA置1  SDA_SET();
  I2C_DELAY();
  I2C_DELAY();
}

2.4 字节格式

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

STM32 IIC详解_操作系统 _13

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

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

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

动画描述写入的过程STM32 IIC详解_操作系统 _05

STM32 IIC详解_操作系统 _15

代码实现

uint8_t I2C_Send_byte(uint8_t data)
{
  uint8_t k;  //发送8bit数据
  for(k=0;k<8;k++){
    
    I2C_DELAY();    if(data&0x80){
      SDA_SET();
    }    else{
      SDA_CLR();
    }
    data=data<<1;
    I2C_DELAY();
    SCL_SET();
    I2C_DELAY();
    I2C_DELAY();
    SCL_CLR();
  }  //延时读取ACK响应  I2C_DELAY();
  SDA_SET();  //置为输入线  SDA_IN();
  I2C_DELAY();
  SCL_SET();   
  I2C_DELAY(); //这里出现了问题,延时变的无限大  //读数据
  k=SDA_READ();  if(k){ NACK响应    return 0;
  }
  I2C_DELAY();
  SCL_CLR();
  I2C_DELAY();
  SDA_OUT();  if(k){ NACK响应    return 0;
  }  return 1;
}
 
uint8_t I2C_Receive_byte(uint8_t flg)
{
  uint8_t k,data;  //接收8bit数据  //置为输入线  
  SDA_IN();
  data=0;  for(k=0;k<8;k++){
    I2C_DELAY();
    SCL_SET();
    I2C_DELAY();    //读数据
    data=data |SDA_READ();
    data=data<<1;
    I2C_DELAY();
    SCL_CLR();
    I2C_DELAY(); 
  }
  data=data>>1; //往回移动1次  //返回ACK响应  //置为输出线  SDA_OUT();  if(flg){
    SDA_SET(); //输出1-NACK
  }else{
    SDA_CLR();//输出0-ACK  }
  I2C_DELAY();
  SCL_SET();
  I2C_DELAY();
  I2C_DELAY();
  SCL_CLR();
  I2C_DELAY();
  SDA_OUT();  //返回读取的数据
  return (uint8_t)data;
}

2.5 从机地址和读写位STM32 IIC详解_操作系统 _05

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

STM32 IIC详解_操作系统 _17

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

STM32 IIC详解_操作系统 _18

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

STM32 IIC详解_操作系统 _19

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

STM32 IIC详解_操作系统 _20

(Combined)综合数据格式

STM32 IIC详解_操作系统 _21

 

3、计算IIC的频率

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

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

STM32 IIC详解_操作系统 _22

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

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

也就是频率是300Kbit/s

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

/*120Mhz时钟时,当ulCount为1时,函数耗时3个时钟,延时=3*1/120us=1/40us*//*SystemCoreClock=120000000
us级延时,延时n微秒
SysCtlDelay(n*(SystemCoreClock/3000000));
ms级延时,延时n毫秒
SysCtlDelay(n*(SystemCoreClock/3000));
m级延时,延时n秒
SysCtlDelay(n*(SystemCoreClock/3));*/
 #if defined   (__CC_ARM) /*!< ARM Compiler */__asm voidSysCtlDelay(unsigned long ulCount)
{
    subs    r0, #1;
    bne     SysCtlDelay;
    bx      lr;
}#elif defined ( __ICCARM__ ) /*!< IAR Compiler */voidSysCtlDelay(unsigned long ulCount)
{
    __asm("    subs    r0, #1\n"
       "    bne.n   SysCtlDelay\n"
       "    bx      lr");
} 
#elif defined (__GNUC__) /*!< GNU Compiler */void __attribute__((naked))
SysCtlDelay(unsigned long ulCount)
{
    __asm("    subs    r0, #1\n"
       "    bne     SysCtlDelay\n"
       "    bx      lr");
} 
#elif defined  (__TASKING__) /*!< TASKING Compiler */                           
/*无*/#endif /* __CC_ARM */ 
 
/*
 * @brief  SysCtlDelay
 * @param  ulCount 延时值,必须大于0
 * @retval None */void SysCtlDelay_IIC(unsigned long ulCount)
{
    SysCtlDelay(ulCount);
} 
 
/定义时钟频率,300KHz#define I2C_DELAY()  SysCtlDelay_IIC(30)
4、PCF8536

4.1 Acknowledge

这个地方能看到关于2.4节关于ACK和NACk的说明STM32 IIC详解_操作系统 _05

STM32 IIC详解_操作系统 _24

4.2 Addressing

这里直接给出读地址和写地址,也就是最后一位的区别STM32 IIC详解_操作系统 _05

STM32 IIC详解_操作系统 _26

4.3 读写时序

其实就是按照IIC协议的

读指定器件的指定寄存器STM32 IIC详解_操作系统 _05

STM32 IIC详解_操作系统 _28

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

注意:读取多个字节,最后一个字节的回包应该是NACKSTM32 IIC详解_操作系统 _05

STM32 IIC详解_操作系统 _30

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

注意:读取多个字节,最后一个字节的回包应该是NACKSTM32 IIC详解_操作系统 _05

STM32 IIC详解_操作系统 _32

 

开源地址:

https://github.com/strongercjd/STM32F207VCT6

 

点击查看本文所在的专辑,STM32F207教程

 

资料下载:

https://pan.baidu.com/s/1lRMxv2EnHRUtugIZloMrxg  提取码:npz0