【学习笔记】软件模拟I2C

 

目录

 

一.I2C简介

1.什么是I2C

2.I2C帧格式

3.I2C时序

二.代码实现

三.时序实现过程中遇到的问题


一.I2C简介

1.什么是I2C

I2C是串行总线的一种,属于半双工通信(数据的发送和接收不能同时进行),由两线组成(时钟线SCL和数据线SDA),采用主从通信模式(支持多主机模式)。

2.I2C帧格式

SADDRW/RADATAA/ĀP

S:起始位;由主机发起,表示此次通信的开始。

ADDR:从机地址位,为7bit。

W/R:数据方向位,主机是读数据还是写数据;

A:应答位。

DATA:数据位;要发送的数据,为8bit;在第一个字节中,其中7-1bit为要通信的从机地址,第0bit为通信的方向。

A/Ā:应答/非应答;主机读或写数据后,都需要有对应 的应答位,表示是否继续接收或发送数据。

P:停止位;由主机发起,表示此次通信的结束。

综上,每帧数据共有9bit。

3.I2C时序

数据位的有效性规定:

 在时钟线为高电平期间不允许数据的改变,此时进行数据传输,在时钟线为低电平期间才允许数据信号的改变。

1.起始信号和停止信号

 当SCL=1,SDA由高电平变为低电平表示起始信号;

当SCL=1,SDA由低电平变为高电平表示停止信号;

2.应答信号

 在数据线为低电平期间,时钟线发送一个持续时间不低于4us的高电平脉冲信号。

3.非应答信号

在数据线为高电平期间,时钟线发送一个持续时间不低于4us的高电平脉冲信号。

4. 字节传输

在进行字节传输时,需保证数据为8bit,采用先传输高位,后传输低位的方式进行,在每传输字节后需跟一位应答位。

二.代码实现

//起始信号

void I2C_Start(void)
{
  I2C_SDA_OUT();//数据线通信方向
    I2C_SDA_H;//拉高数据线
  I2C_SCL_H;//拉低时钟线
  Delay_us(5);//延时5us

  I2C_SDA_L;//拉低数据线
  Delay_us(5);
  I2C_SCL_L;//拉低时钟线
}

//停止信号

void I2C_Stop(void)
{
  I2C_SDA_OUT();
  I2C_SCL_L;
  I2C_SDA_L;
  Delay_us(5);
    I2C_SCL_H;
  I2C_SDA_H;
  Delay_us(5);
}

//应答信号

void I2C_Ack(void)
{
    I2C_SCL_L;
  I2C_SDA_OUT();
  I2C_SDA_L;
  Delay_us(2);
  I2C_SCL_H;
  Delay_us(5);
  I2C_SCL_L;
}

//非应答信号

void I2C_Nack(void)
{
    I2C_SCL_L;
  I2C_SDA_OUT();
  I2C_SDA_H;
  Delay_us(2);
  I2C_SCL_H;
  Delay_us(5);
  I2C_SCL_L;
}

//主机等待从机应答

u8 I2C_Wait_Ack(void)
{
  int num=0;
  int ack_flag;
  I2C_SDA_IN();
  I2C_SDA_H;
  Delay_us(2);
  I2C_SCL_H;
  Delay_us(2);
  while(I2C_READ)
  {
    num++;
    if(num>250)
    {
      I2C_Stop();
      ack_flag=1;
    }
  }
     I2C_SCL_L;
   ack_flag=0;
  return ack_flag;
}

//主机发送一个字节

void I2C_Send_Byte(u8 data)
{
   u8 t;   
        I2C_SDA_OUT();         
    I2C_SCL_L;
    for(t=0;t<8;t++)
    {              
        I2C_SDA=(data&0x80)>>7;
        data<<=1;       
            I2C_SCL_H;
            Delay_us(2);
            I2C_SCL_L;    
            Delay_us(2);
    }     
}

//主机接收一个字节

u8 I2C_Recive_Byte(unsigned char ack)
{
  unsigned char i,receive=0;
    I2C_SDA_IN();
    for(i=0;i<8;i++ )
    {
    I2C_SCL_L; 
    Delay_us(2);
        I2C_SCL_H;
    receive<<=1;
    if(I2C_READ)receive++;   
        Delay_us(2); 
    }                     
    if (!ack) I2C_Nack();
    else I2C_Ack();   
    return receive;
}

三.时序实现过程中遇到的问题
 

 1.延时时间需参考时序,看是否达到要求的最低延时时间。

2.在写完时序后,发现通信错误或无法通信,看是否是先钳住总线,因为在本人实现过程中,没有先钳住总线,导致通信数据错误,如读取MPU6050的地址应为0x68,而实际读取到不是此值,当先钳住总线后通信正常。

  • 16
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

haiLiangZhou-6

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值