关于I2C总线

两根线数据线SDA和时序线SCL,这让我想到了火线和零线。

总线上任何一个IC器件输出低电平都会使总线拉低,是线与的关系。

支持多主和主从工作方式

有效性:只有时钟线变成低电平数据线才能变化。

I2C的初始化应包括,起始信号,寻址,应答,结束信号。

初始化时把两根线都拉高,表示正常未工作状态

起始信号:在阴影部分的意思是,在SDA产生高电平持续一会再变低电平延时一会,在这个变化中间,SCL时间线一直处于高电平。

 应答信号:SCL处于高电平的4us内,看SDA是否被拉低,如果没有被拉低就代表没应答,SDA会一直处在高电平,跳不出while循环,我们就给它定一个时间,取段延时大于4us,没有应答也要跳出循环,再将SCL拉低,延时。

终止信号:左边的虚线,SDA是低电平延时4us,SCL是高电平延时4us,把SDA拉高持续4.7us。

这里的共性就是看谁产生跳变沿,跳变沿那个变化写在最开始,再写另一个。产生跳变沿的是一个变化量,在一个状态不变的情况下发生变化。

写一个字节

:SCL在高电平期间,SDA一个上升沿停止信号

 读一个字节

 

原文地址:::分析一下到底是上升沿还是下降沿读写数据-FreedomXura-ChinaUnix博客

分析一下到底是上升沿还是下降沿读写数据--jinn3很好的总结_jinn的博客-CSDN博客

上面的读写操作都是单片机读写而不是器件du'x

输入(指器件的输入)<==>写(MCU的写操作),输出(指器件的输出)<==>读(MCU的读操作)。

 所谓读即是指MCU从器件的数据总线上根据一定的时序来读取器件的数据。一般而言,MCU提供一个边沿信号(上升沿或者下降沿均可)告诉器件可以发数据了,器件检测到边沿信号以后,立即在数据总线上更新数据,待数据稳定以后,MCU即可读取数据。所以一般所说的上升沿(下降沿)开始读数据是不准确地说法,上升沿(下降沿)这是数据总线上的数据发生改变,MCU并没有在此时刻读取数据,而是等待数据稳定之后才开始读取数据。

以DS1302的单字节读时序为例说明,要读取DS1302数据,先必须写1byte数据到DS1302,即是指(R/W,A0~A4,R/C,1这8位数据),然后再读。所以我们应该看后半部分来解读数据的read操作。

显然在时钟信号的下降沿数据总线上的数据发生改变,等待数据稳定之后,MCU将读取该数据D0,接着MCU产生下一个下降沿,器件检测到下降沿信号立即更新数据D1,等待数据稳定之后被MCU读取。后面相同。

2)所谓写即是指MCU向器件写入数据,其操作是:先将数据放置在数据总线上,等待其稳定之后,MCU产生一个边沿信号,将数据写入器件。以DS1302的单字节写时序为例说明,要向DS1302写数据,,先必须写1byte数据到DS1302,即是指(R/W,A0~A4,R/C,1这8位数据),然后再写。

所以上图的16个脉冲下的操作均是写操作,可以从第一位(R/W)分析起,当然也可以向读操作一样,只分析后半部分的操作。

/*
** 函 数:single_byte_read
** 参 数: unsigned char commd--读之前必须写入的命令
** 返回值: unsigned char tempbyte--读取的1byte数据
** 说 明: 这只是一个例子函数,对应上面的时序图所写的完整的读1字节数据函数
*/
unsigned char single_byte_read(unsigned char commd)
{
  int i;
  unsigned char tempbit;
  unsigned char tempbyte;
  /* 初始化*/
  CE = 0;
  SCLK_OFF;

  /* 写1byte 数据(R/W,addr,R/C,1):读的地址命令*/
  /* 数据总线上先准备好数据,上升沿写入数据到器件*/
  for(i=0;i<8;i++)
  {
    if(commd & 0x01)
     DataIO = 1; //数据总线上准备数据1
    else
     DataIO = 0; //数据总线上准备数据0
    commd=commd>>1;
    SCLK_ON; //上升沿来临,MCU将数据写入器件
    _NOP();
    SCLK_OFF; //再次拉低,为下一个数据提供上升沿条件
  }

  /*写完命令之后, 从器件读1byte数据*/
  /*下降沿通知器件更新数据,等待其稳定之后读取数据*/
  for(i=0;i<8;i++)
  {
   if(DataIO) //紧接上面写命令的最后一个信号是下降沿信号,故此时第一位数据即是器件更新数据
    tempbit = 0x80;
   else
    tempbit = 0;
   tempbyte = tempbyte >> 1 | tempbit;
   SCLK_ON; //上升沿,为下降沿提供条件
   _NOP();
   SCLK_OFF; //下降沿来临,通知器件更新数据,在下一个循环中MCU读取更新的数据.
  }

  return tempbyte;
}
/*
** 函 数:single_byte_write
** 参 数: unsigned char commd--写数据之前必须先写命令
** unsigned char data--写的1byte数据
** 返回值: none
** 说 明: 这只是一个例子函数,对应上面的时序图所写的完整的写1字节数据函数
*/
void single_byte_write(unsigned char commd,unsigned char data)
{
  int i;
  
  /* 初始化*/
  CE = 0;
  SCLK_OFF;

  /* 写1byte 数据(R/W,addr,R/C,1):读的地址命令*/
  /* 数据总线上先准备好数据,等待其数据稳定之后,MCU产生一个上升沿写入命令到器件*/
  for(i=0;i<8;i++)
  {
    if(commd & 0x01)
     DataIO = 1; //数据总线上准备数据1
    else
     DataIO = 0; //数据总线上准备数据0
    commd=commd>>1;
    SCLK_ON; //上升沿来临,MCU将数据写入器件
    _NOP();
    SCLK_OFF; //再次拉低,为下一个数据提供上升沿条件
  }

  /*写完1byte命令之后, 再写1byte数据*/
  /*与写命令是一样的,数据总线上先准备好数据,等待其数据稳定之后,MCU产生一个上升沿信号将数据写入*/
  for(i=0;i<8;i++)
  {
    if(data & 0x01)
     DataIO = 1; //数据总线上准备数据1
    else
     DataIO = 0; //数据总线上准备数据0
    data=data>>1;
    SCLK_ON; //上升沿来临,MCU将数据写入器件
    _NOP();
    SCLK_OFF; //再次拉低,为下一个数据提供上升沿条件
  }

}

​​​​​​​

  • 10
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值