通信协议-(一)IIC总线

IIC总线

  • IIC总线 简介
  • IIC总线 -硬件连接
  • IIC总线 -寻址
  • IIC总线 -通信协议
    • (一)起始信号和终止信号
    • (二)应答信号和非应答信号
    • (三)数据状态:SCL高读 / 低写
    • (四)IIC总线 -数据的读写过程
      • 写入过程
      • 读取过程
  • IIC软件模拟时序
    • (1)IIC时序函数
    • (2)IIC 发送/接收 数据帧的过程
    • (3)iic.h 头文件

IIC总线 简介

  • IIC(Inter-Integrated Circuit)或I2C:它是一种串行同步半双工总线,使用多主多从架构。由PHILIPS公司在1980年代为了让主板、嵌入式系统或手机连接低速周边设备而发展。IIC硬件结构简单,接口连接方便,成本低,因此应用很广。
  • 在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送数据,高速 IIC 总线一般可达 400kbps 以上。用IIC通信的芯片最常用的就是EEPROM芯片,如Atmel的AT24CXX系列;IC:集成电路设备。
    eg:单片机内部两个芯片间通信、单片机CPU和一些传感器之间通信

IIC总线 -硬件连接

(1)IIC总线硬件是由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成。
(2)IIC总线通信原理通过对SCL和SDA线高低电平时序的控制,来产生IIC总线协议所需要的信号进行数据的传递。在总线空闲状态时,这两根线会被上拉电阻拉高,保持着高电平。

  • IIC总线为两线制:即有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。
    所有设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。
    注:
    SDA:串行数据线
    SCL:串行时钟线
  • 上拉电阻的作用是在空闲状态下时,保持SDA和SCL为高电平状态。一般Rp = 4.7k

通信协议-(一)IIC总线_第1张图片

  • IIC总线是具有多主多从的系统总线可裁决功能的高性能串行总线。(多主机用的比较少,基本上都是一个主机挂载多个从机设备)

  • 主设备通过寻址来确定与哪个器件进行通信。通常情况下,我们把CPU带IIC总线接口的模块作为主设备,把挂接在总线上的其他设备都作为从设备。
    主机(主设备):主动发起接收和发送数据(CPU)
    从机(从设备):被动的接收和发送数据为从机

  • IIC总线上可挂接的设备总数量受总线的最大电容400pF所限制。如果所挂接的是相同型号的器件,则还受器件地址位个数的限制。

  • IIC总线数据传输速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s。一般通过IIC总线接口可编程时钟来实现传输速率的调整,同时也跟所接的上拉电阻的阻值有关。

IIC总线 -寻址

  • 怎么区分主机和哪一个从机通信?
    IIC总线上的每一个设备都可以作为主设备或从设备,而且每一个接到IIC总线上的器件都会分配一个唯一的地址。主机和其他从机器件在数据传输时通过对地址进行匹配后再确认通信,不区分主机、从机,发送数据的设备是发送器,接收数据的设备是接收器。

  • IIC总线上的主设备与从设备间以字节(8位 = 一帧)为单位进行双向的数据传输,主、从设备间的数据传输是建立在地址的基础上。也就是说:主设备在传输有效数据之前要先指定从设备的地址,地址指定的过程和上面数据传输的过程一样,只不过大多数从设备的地址是7位。然后协议规定再给地址添加一个最低位:用来表示接下来数据传输的方向
    0:主机向从机写(发送)数据
    1:主机向从机读(接收)数据,从机写数据

  • 设备地址的产生?
    通过芯片引脚的物理接地或上拉电阻拉高。
    eg:从IIC器件的数据手册得知,如TVP5158芯片,总共有7位地址依次为bit6~bit0:101 1xxx, 低三位总共有8种地址类型选配。如果第三位引脚全部物理接地,则该设备地址为0x58。
    注:此类芯片在该主、从总线上最多可以挂载8个。
    通信协议-(一)IIC总线_第2张图片

IIC总线 -通信协议

  • 起始信号
  • 终止信号
  • 应答和非应答信号
  • 数据传输

(一)起始信号和终止信号

(1)IIC协议规定,总线上数据的传输必须以一个起始信号作为开始条件,以一个结束信号作为传输的停止条件。起始和结束信号总是由主设备产生,即意味着从设备不可以主动通信,所有的通信都是从主设备发起的,主机可以发出询问的command,然后等待从机设备的通信。

(2)起始和结束信号的产生条件:总线在空闲状态时,SCL和SDA默认都是保持着高电平状态。

  • 当SCL为高电平时,SDA电平状态发生由高到低的跳变,产生一个下降沿:起始信号;
  • 当SCL为高电平时,SDA由低到高的跳变,产生一个上升沿:终止信号。

(3)在起始条件产生后,总线处于忙状态:即本次数据传输的总线由主、从设备独占,其他IIC器件此时无法访问总线;而在终止条件产生后,本次数据传输的主、从设备将总线释放,总线再次处于空闲状态。

起始和终止信号如图所示:
通信协议-(一)IIC总线_第3张图片

(二)应答信号和非应答信号

  • IIC总线数据传输是以字节为单位。SCL线上产生每个时钟脉冲的过程中,主设备将在SDA线上传输一个数据位,当一个字节的数据按数据位从高到低的顺序逐次传输完后,紧接着从设备将拉低SDA线,回传给主设备一个应答位(应答信号), 此时才认为一个字节真正的被传输完成。
  • 当然并不是所有的字节传输都必须有一个应答位,eg:当从设备不能在接收到主设备发送的数据时,从设备将会回传一个非应答位(即非应答信号:延时一段时间默认回传一个非应答信号)。

应答信号和非应答信号如图所示:
通信协议-(一)IIC总线_第4张图片

(三)数据状态:SCL高读 / 低写

SCL在高电平期间,SDA数据线必须保持数据的稳定,此时才可以读取数据。
SCL在低电平时,SDA数据线上高低电平状态才允许变化,此时才可以写入数据。通信协议-(一)IIC总线_第5张图片

(四)IIC总线 -数据的读写过程

注意:无论主机还是从机,发送或接收数据都是把数据先放入自己的移位寄存器里保存的,之后再进行数据的发送到SDA/写入到自己的内存中。

写入过程

通信协议-(一)IIC总线_第6张图片
过程描述:

  • 主机先向SDA发送一个起始信号S后(表示主机要开始传输数据了),再发送 从机地址(7位) + 读/写位(0写/1读)。紧接着每一个从机开始将自己的地址和主机发送的地址进行匹配,如果发现相同,则从机会发送一个应答信号ACK(表示从机已匹配上,可以与主机进行数据传输)。主机接收到从机的ACK信号后,主机继续会再发送一个 从机内部内存的地址来指定主机要写入的内存位置。从机接收到从机发送的数据后会产生应答信号ACK返回,主机接收到从机的ACK信号后,主机开始进行数据的传输。每次从机接收到数据都会应答发送ACK信号,当主机发送完数据不想发了,会向SDA发送停止信号P。

读取过程

通信协议-(一)IIC总线_第7张图片

IIC软件模拟时序

(1)IIC时序函数

以stm32F105VCT为例:

/* --------------------- IIC 初始化 -------------------------*/
/* IIC1 初始化 */
void IIC_Dev_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    /* 使能GPIOB端口时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    /* 配置SCL,SDA */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* SCL、SDA初始默认状态值 */
    IIC_SCL = 1;
    IIC_SDA = 1;
}

/* --------------------- IIC 初始化 -------------------------*/
/* IIC1 初始化 */
void IIC_Dev_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    /* 使能GPIOB端口时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    /* 配置SCL,SDA */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* SCL、SDA初始默认状态值 */
    IIC_SCL = 1;
    IIC_SDA = 1;
}


/*---------------------------- 软件模拟 IIC时序 ---------------------------*/
/* 产生IIC 起始信号 */
void IIC_Start(void)
{
    SDA_OUT(); // 设置SDA线为输出
    IIC_SDA = 1;
    IIC_SCL = 1;
    delay_us(4);
    IIC_SDA = 0;
    delay_us(4);
    IIC_SCL = 0; 
}

/* 产生IIC 停止信号 */
void IIC_Stop(void)
{
    SDA_OUT(); 
    IIC_SCL = 0;
    IIC_SDA = 0; 
    delay_us(4);
    IIC_SCL = 1;
    IIC_SDA = 1; // 发送I2C总线结束信号
    delay_us(4);
}

/* 等待应答信号到来 */
u8 IIC_Wait_Ack(void)
{
    u8 ucErrTime = 0;
    SDA_IN(); //设置SDA线为输入
    IIC_SDA = 1;
    delay_us(1);
    IIC_SCL = 1;
    delay_us(1);
    while (READ_SDA) {
        ucErrTime++;
        if (ucErrTime > 250) {
            IIC_Stop();
            return 1;
        }
    }
    IIC_SCL = 0; //时钟输出0

    return 0;
}

/* 产生ACK应答信号 */
void IIC_Ack(void)
{
    IIC_SCL = 0;
    SDA_OUT();
    IIC_SDA = 0;
    delay_us(2);
    IIC_SCL = 1;
    delay_us(2);
    IIC_SCL = 0;
}

/* 不产生ACK应答 */
void IIC_NAck(void)
{
    IIC_SCL = 0;
    SDA_OUT();
    IIC_SDA = 1;
    delay_us(2);
    IIC_SCL = 1;
    delay_us(2);
    IIC_SCL = 0;
}

/*------------- 指令周期 约1.05us ----------------*/
void delay_us(int i)
{
    while(i--);
}

可以适用于任何的stm32F系列平台的IIC时序,delay_us()使用MDK(keil5.0)可以调试仿真:一条指令的大概执行时间。

(2)IIC 发送/接收 数据帧的过程

/*---------------- IIC发送/接收一个 Byte数据 -------------------*/
/**
  * @brief  IIC发送一个字节
  * @param  
  * @retval 返回从机有无应答
  *         1:有应答
  *         0:无应答
  */
void IIC_Send_Byte(u8 txd)
{
    u8 t;
    SDA_OUT();
    IIC_SCL = 0; //拉低时钟开始数据传输
    for (t = 0; t < 8; t++) {
        IIC_SDA = (txd & 0x80) >> 7;
        txd <<= 1;
        delay_us(2); //对TEA5767这三个延时都是必须的
        IIC_SCL = 1;
        delay_us(2);
        IIC_SCL = 0;
        delay_us(2);
    }
}

/* ack=1时,发送ACK,ack=0,发送nACK */
u8 IIC_Read_Byte(unsigned char ack)
{
    unsigned char i, receive = 0;
    SDA_IN(); //SDA设置为输入
    for (i = 0; i < 8; i++) {
        IIC_SCL = 0;
        delay_us(2);
        IIC_SCL = 1;
        receive <<= 1;
        if (READ_SDA)
            receive++;
        delay_us(1);
    }
    if (!ack)
        IIC_NAck(); //发送nACK
    else
        IIC_Ack(); //发送ACK

    return receive;
}

(3)iic.h 头文件


#define I2C_CLK_SPEED 100000 //100KHZ < 400KHZ


/* ------------------------ IIC的SCL、SDA 位带操作 ----------------------- */
//外设地址
#define PERIPH_BASE ((uint32_t)0x40000000) 
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
#define GPIOB_ODR_Addr (GPIOB_BASE + 12)
#define GPIOB_IDR_Addr (GPIOB_BASE + 8)
    
//位带映射操作
#define BITBAND(addr, bitnum) \
			((addr & 0xF0000000) + 0x2000000 + ((addr & 0xFFFFF) << 5) + (bitnum << 2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))

#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr, n)
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr, n)

#define IIC_SCL PBout(8) //SCL
#define IIC_SDA PBout(9) //SDA
#define READ_SDA PBin(9) //read SDA

/* ------------------- 设置SDA_IO数据流传输方向--------------------*/
/* SDA数据流输入 */
#define SDA_IN()                   \
    do                             \
    {                              \
        GPIOB->CRH &= 0XFFFFFF0F;  \
        GPIOB->CRH |= (u32)8 << 4; \
    } while (0) //上拉输入

/* SDA数据流输出 */
#define SDA_OUT()                  \
    do                             \
    {                              \
        GPIOB->CRH &= 0XFFFFFF0F;  \
        GPIOB->CRH |= (u32)3 << 4; \
    } while (0) //50MHZ推挽输出

你可能感兴趣的:(通信协议-(一)IIC总线)