【蓝桥杯】IIC通信协议

目录

    • 1、IIC通信简介
    • 2、IIC通信数据传输
      • 2.1总线启动条件
      • 2.2总线停止条件
      • 2.3应答/非应答信号
      • 2.4主机发送数据
      • 2.5主机接受数据

1、IIC通信简介

I2C总线是PHLIPS(飞利浦)公司推出的一种串行(集成电路总线)总线,是具备多主机系统所需的包括总线裁决和高低速器件同步功能的高性能串行总线。 I2C总线有两根双向信号线。一根是数据线SDA,另一根是时钟线SCL。
I2C总线通过上拉电阻(阻值为1k8 时性能最好)接正电源。当总线空闲时,两根线均为高电平。通常将SDA、SCL均置为1,用来释放总线。连到总线上的任一器件输出的低电平,都将使总线的信号变低,即各器件的SDA及SCL都是所有器件输出到该线路上的信号相“与”的结果)即如果一方输出低,另一方即使输出高也不能使SDA为高,相当于,输出低的一方占住了SDA口,所以两个口一个输出高一个输出低,则线上电平是低的。这是因为输出高的驱动能力不及输出低的拉电流的能力。这使得每次IIC总线都能从多个IIC从机设备中选择一个进行通讯。
【蓝桥杯】IIC通信协议_第1张图片
从设备不能主动发起传输,其传输是受到主设备控制的。所以主机读从机时,需先由主机向从机发读命令,然后由从机发送数据到主机。

2、IIC通信数据传输

只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化,所以在向SDA送数据之前,要将SCL置为低,等待数据稳定后,将SCL置为高,再进行读写。

2.1总线启动条件

初始化时(总线空闲)SCL、SDA均为高电平 。
在SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号;
具体的操作看代码注释

//总线启动条件
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;//初始状态两根线都要处于高电平
    IIC_Delay(5);//短暂延时等待电平稳定
    SDA = 0;//给低电平,注意此时的电平还没有改变,因为需要时钟线上的信号处于低电平期间
    IIC_Delay(5);//等待SDA上的数据稳定,
    SCL = 0;//拉低时钟线,此时数据线上的高电平或低电平状态才允许变化
}

2.2总线停止条件

在SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号。

//总线停止条件
void IIC_Stop(void)
{
    SDA = 0;//数据线拉低,以便待会产生上升沿
    SCL = 1;//使SCL线为高电平期间
    IIC_Delay(DELAY_TIME);//等待稳定
    SDA = 1;//产生SDA线由低电平向高电平的变化
    IIC_Delay(DELAY_TIME);
}

2.3应答/非应答信号

1、应答信号:
一次传送一个字节,每一个字节必须保证是8位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位),应答位由接收器发出。
发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号(发送端在发送一个字节数据后,要在SCL第9个脉冲来临前把SDA拉高,以等待接收端发来ACK信号)。
在第9个SCL时钟周期的高电平期间,读SDA,若为低电平表示应答(接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平),若为高电平表示非应答(从机输出高电平)或无应答(从机无任何输出)。所以检测非应答时,要通过持续循环一定长的时间,检测SDA是否为高,因为从机的反应速度慢。
2、非应答信号:
当主机接收数据时,它收到最后一个数据字节后,必须向从机发出一个结束传送的信号,即,向从机发送“非应答”(NACK)信号,以通知被控发送器结束数据发送。然后,从机释放SDA线,以便主控接收器发送一个停止信号P

//发送应答/非应答
void IIC_SendAck(bit ackbit)
{
    SCL = 0;//时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化
    SDA = ackbit;  //低电平0:应答,高电平1:非应答
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}
//等待应答
bit IIC_WaitAck(void)
{
    bit ackbit;
	
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;//低电平0:应答,高电平1:非应答
}

2.4主机发送数据

1、启动总线
2、 在起始信号后必须传送一个从机的地址(7位),第8位是数据的传送方向位(R/T),用“0”表示主机发送数据(T),“1”表示主机接收数据(R)。比如0X90,表示主机向器件地址为0X90的从机设备发送数据
3、等待应答
如何接受数据?

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
    unsigned char i, da;
    for(i=0; i<8; i++)//读8位数据
    {   
    SCL = 1;//禁止SDA线电平读写(禁止SDA下一位数据到来)
	IIC_Delay(DELAY_TIME);
	da <<= 1;//位选
	if(SDA) da |= 1;//该位如果读到低电平0即置零该位,读到高电平则等于1
	SCL = 0;//允许SDA下一位数据到来
	IIC_Delay(DELAY_TIME);
    }
    return da;    
}

主机发送数据,比如ADC写入

 void write_ADC(unsigned char x)
{
  IIC_Start();
  IIC_SendByte(0x90); //写
  IIC_WaitAck();
 
  IIC_SendByte(0x43); //允许输出
  IIC_WaitAck();
  IIC_SendByte(x);
  IIC_WaitAck();
  IIC_Stop();
 
}

2.5主机接受数据

读的过程比较复杂,在从slave读出数据前,你必须先要告诉它哪个内部寄存器是你想要读取的,因此必须先对其进行写入(dummy write):先写入从器件设备地址(对设备寻址)以及从器件内部地址(对设备内部存储单元寻址),然后再写一遍从器件设备地址并设置第8位数据传送方向位为1(R),通知从设备发送数据。

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
    unsigned char i, da;
    for(i=0; i<8; i++)
    {   
    SCL = 1;//先禁止SDA变化
	IIC_Delay(DELAY_TIME);
	da <<= 1;//位选
	if(SDA) da |= 1;//对SDA进行写入,0低电平。1高电平
	SCL = 0;//允许写入
	IIC_Delay(DELAY_TIME);
    }
    return da;    
}

主机接受,比如DAC读取

unsigned char read_rb(unsigned char channel)
{
  unsigned char dat;
  //告诉从机,主机我要开始读数据了,让从机寄存器准备好
  IIC_Start();
  IIC_SendByte(0x90); //写
  IIC_WaitAck();
  IIC_SendByte(40+channel);//从机内部寄存器命令,视从机命令而定
  IIC_WaitAck();
//发送读命令
  IIC_Start();
  IIC_SendByte(0x91); //读
  IIC_WaitAck();
  dat = IIC_RecByte();//读取数据
  IIC_SendAck(1);//非应答信号,向从机发出一个结束传送的信号
  IIC_Stop();//总线停止
  return dat;
}

你可能感兴趣的:(备考蓝桥杯,单片机,蓝桥杯,stm32)