历史上的今天
返回首页

历史上的今天

今天是:2025年04月08日(星期二)

正在发生

2019年04月08日 | GPIO模拟IIC过程中对IIC的理解

2019-04-08 来源:eefocus

前两天在配置一款数字陀螺仪的IIC时序,分别实现了使用芯片自带IIC模块配置和使用GPIO模拟,下面谈谈个人对IIC的一些理解。


概述

IIC是一个总线协议,和spi类似的一个串行总线协议,它的特点是只用的信号线特别少,只需要两根,分别是SCL和SDA,但是与此同时也降低了通信速度。

IIC总线信号线少就造成它的通信协议稍微复杂,理解IIC的时序是理解IIC总线的关键。

.IIC总线通过上拉电阻接到VDD,当总线空闲时,两根信号线均为高电平。连接总线的任意一个器件输出低电平,将使总线信号变低,即各器件的信号线是“线与”关系。

每个IIC上连接的器件都有唯一的地址(7bit),当某个器件发出广播(地址信号)时,该器件即为主机,其它器件为从机,读写行为都由主机发起,SCL信号总由主机产生。

.当有多个器件企图发起广播传送数据时,需要总线仲裁模块进行仲裁。

.在SCL为高电平期间,数据线上的数据必须保持稳定(0或者1),数据接收者会在这个期间接受数据,在SCL为低电平期间可以改变数据(改变SDA的电平)。

读时序:主机发起通信start(7bit从器件ID+1bit读写位0)——从机收到广播并回应(ack)——主机发送地址信号(8bit)——主机重新发起通信start(7bit从器件ID+1bit读写位0)——再次发送从器件寄存器地址address(8bit)——接收数据(SCL高电平期间从器件不会改变SDA,在此期间读SDA,将SCL拉低后从器件会将下一位数据送到SDA上)——每8bit主机需要发送一个应答信号表示继续接收,否则认为结束接收——接收结束发送无应答信号通知从器件完成数据接收——发送停止信号stop——一次通信结束写时序:主机发起通信start(7bit器件ID+1bit读写位1)——从机接收到广播并回应ack——主机写从机寄存器地址(8bit)——从机应答——写数据(8bit)——从机应答——主机发送停止信号stop——一次通信结束

两次通信之间应该有足够的时间间隔,不同器件的时间间隔不一样,一般为us数量级

当SCL=1期间,SDA从1变为0表示start信号当SCL=1期间,SDA从0变为1表示stop信号应答期间输出0表示有应答,输出1表示无应答接受应答期间接收0表示有应答,接收1表示无应答

K60上使用LPLD底层库实现GPIO模拟IIC的代码如下,该代码是用于对GY_50数字陀螺仪的读写


master

master

salver

salver

start信号

发送data

ack()应答

stop信号

数据线空闲时候才能启动

start信号

SCL为1期间SDA从1变为0表示开始信号


//开始信号

void GY_50_Start(void)

{                                                         

    LPLD_GPIO_Output_b(GY_50_SDA_PORT_ID,GY_50_SDA_PORT_NUM,1);

    LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID,GY_50_SCL_PORT_NUM,1);


    GY_50_Delay(1);


    LPLD_GPIO_Output_b(GY_50_SDA_PORT_ID,GY_50_SDA_PORT_NUM,0);


    GY_50_Delay(1);

    LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID,GY_50_SCL_PORT_NUM,0);

}


停止信号

SCL为1期间SDA从1变为0表示结束信号


//停止信号

void GY_50_Stop(void)

{

  LPLD_GPIO_Output_b(GY_50_SDA_PORT_ID, GY_50_SDA_PORT_NUM,0);

  LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,1);

  GY_50_Delay(1);

  LPLD_GPIO_Output_b(GY_50_SDA_PORT_ID, GY_50_SDA_PORT_NUM,1); 

  GY_50_Delay(1);

}


发送应答信号

向数据线上传送一位数据表示有应答或者无应答


//发送应答信号(0:ACK 1:NAK)

void GY_50_SendAck(uint8 ack)

{

  ack= ack?1:0;

  LPLD_GPIO_Output_b(GY_50_SDA_PORT_ID, GY_50_SDA_PORT_NUM,ack);

  LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,1);

  GY_50_Delay(1);

  LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,0);

  GY_50_Delay(1);

}


接收应答信号

从数据线上读取一位数据查看是否应答


//接收应答信号(0:ACK 1:NAK)

uint8 GY_50_ReceiveAck(void)

{

  uint8 data_temp=0;

  LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,1);

  GY_50_Delay(1);

  SetGpioPortIO(GY_50_SDA_PORT_ID,GY_50_SDA_PORT_PIN,DIR_INPUT);

  data_temp = LPLD_GPIO_Input_b(GY_50_SDA_PORT_ID, GY_50_SDA_PORT_NUM);

  SetGpioPortIO(GY_50_SDA_PORT_ID,GY_50_SDA_PORT_PIN,DIR_OUTPUT);

  LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,0);

  GY_50_Delay(1);

  return data_temp;

}


向IIC总线发送一个字节的数据

按照协议要求,在SCL为低期间改变数据,在SCL为高期间保持数据,并保持一定时间,保证对方读取完毕


//向IIC发送一个字节的数据

void GY_50_SendByte(uint8 data)

{

  static uint8 i,data_temp;

  for(i=0;i<8;i++)

  {

    data_temp = data&0x80;//取最高位

    data <<= 1;

    data_temp = data_temp?1:0;


    LPLD_GPIO_Output_b(GY_50_SDA_PORT_ID, GY_50_SDA_PORT_NUM,data_temp);

    LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,1);

    GY_50_Delay(1);

    LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,0);

    GY_50_Delay(1);

  }

  GY_50_ReceiveAck();

}


从IIC接收一个字节数据

根据协议要求,在SCL为高期间读取数据,在SCL为低期间让对方发送数据,SCL为低要保持一定时间,保证数据线上的数据稳定


//从IIC接收一个数据

uint8 GY_50_ReceiveByte(void)

{

  static uint8 i,data_temp=0;

  LPLD_GPIO_Output_b(GY_50_SDA_PORT_ID, GY_50_SDA_PORT_NUM,1);

  SetGpioPortIO(GY_50_SDA_PORT_ID,GY_50_SDA_PORT_PIN,DIR_INPUT);

  for(i=0;i<8;i++)

  {

    data_temp <<= 1;

    LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,1);

    GY_50_Delay(1);

    data_temp |= LPLD_GPIO_Input_b(GY_50_SDA_PORT_ID, GY_50_SDA_PORT_NUM);

    LPLD_GPIO_Output_b(GY_50_SCL_PORT_ID, GY_50_SCL_PORT_NUM,0);

    GY_50_Delay(1);

  }

  SetGpioPortIO(GY_50_SDA_PORT_ID,GY_50_SDA_PORT_PIN,DIR_OUTPUT);

  //GY_50_Delay(1);

  return data_temp;

}



写一个字节

根据协议要求,串行传送信号


//单字节写入

void GY_50_WriteByte(uint8 add, uint8 data)

{

  GY_50_Start();

  GY_50_SendByte(GY_50_ADDRESS);

  GY_50_SendByte(add);

  GY_50_SendByte(data);

  GY_50_Stop();

}


读单个字节

根据协议要求,串行传送信号和指令


//单字节读取

uint8 GY_50_ReadByte(uint8 add)

{

  uint8 data_temp;

  GY_50_Start();

  GY_50_SendByte(GY_50_ADDRESS);

  GY_50_SendByte(add);

  GY_50_Start();

  GY_50_SendByte(GY_50_ADDRESS|0x01);

  data_temp = GY_50_ReceiveByte();

  GY_50_SendAck(1);

  GY_50_Stop();


  return data_temp;

}


延迟函数

该函数在总线周期为50M的K60芯片上大约延迟4us(k=1)


//延时函数

void GY_50_Delay(uint8 k)

{

  uint16 i,j;

  for(i=0;i

  {

    for(j=0;j<200;j++)

    {

      asm("nop");

    }

  }

}


注:

SetGpioPortIO(GPIO_Type *portx,uint32 pins,uint8 io)为一个改变GPIO引脚数据传送方向的函数。

希望以上对大家的学习有所帮助

推荐阅读

史海拾趣

CTS [CTS Corporation]公司的发展小趣事

CTS Corporation的创始人在1896年创立了这家公司,当时的主要业务是设计并生产高品质的电话产品。随着电话技术的普及和通信行业的快速发展,CTS凭借其出色的产品质量和创新的设计理念,逐渐在电话市场中占据了一席之地。公司的创始人凭借其敏锐的商业洞察力和不懈的努力,为CTS奠定了坚实的基础。

Aearo Technologies公司的发展小趣事

Aearo Technologies公司创立于四十多年前,从一开始就致力于能量控制技术的研发。公司凭借创始团队在声学、材料科学和工程领域的深厚背景,成功开发出了一系列高性能的噪声和振动控制材料。这些创新材料为公司在电子行业中树立了良好的声誉,也为其后续发展奠定了坚实的基础。

Goldentech Discrete Semiconductor Inc公司的发展小趣事

随着物联网、可穿戴设备等新兴领域的兴起,Goldentech敏锐地捕捉到了市场的新机遇。公司迅速调整战略方向,加大在微型化、低功耗半导体器件的研发投入。通过引入先进的制造工艺和封装技术,Goldentech成功推出了一系列适用于物联网和可穿戴设备的高性能离散半导体产品。这些产品凭借出色的性能和稳定性,在市场中获得了广泛认可,为公司的持续发展注入了新的动力。

ELESTA GmbH公司的发展小趣事

2013年,ELESTA公司更名为ELESTA GmbH,这一品牌重塑标志着公司进入了新的发展阶段。同时,ELESTA也开始实施全球化战略,积极拓展国际市场,通过不断提升产品质量和服务水平,赢得了全球客户的信赖和认可。

Dell公司的发展小趣事

2013年,ELESTA公司更名为ELESTA GmbH,这一品牌重塑标志着公司进入了新的发展阶段。同时,ELESTA也开始实施全球化战略,积极拓展国际市场,通过不断提升产品质量和服务水平,赢得了全球客户的信赖和认可。

AIRPAX公司的发展小趣事

AIRPAX的故事始于一个对电气保护和传感器技术充满热情的团队。在20世纪初,电气技术的快速发展为各种行业带来了巨大的变革。看到这一机遇,AIRPAX的创始人在美国马萨诸塞州的阿特波罗创立了这家公司,专注于传感器、电气保护器和控制器的设计与制造。最初,AIRPAX的产品主要服务于本地的小规模工业应用,但凭借其卓越的性能和可靠性,很快赢得了市场的认可。

问答坊 | AI 解惑

求助:问个电路板的问题

1.电路板(除去元器件)由什么材料制成? 2.电路板用PROTEL画图的时候,哪些层分别对应着哪些位置?(比如;topoverly,layout...) 3.什么是波峰焊,回流焊?…

查看全部问答>

哈佛结构

哈佛结构   哈佛结构是一种将程序指令存储和数据存储分开的存储器结构。中央处理器首先到程序指令存储器中读取程序指令内容,解码後得到数据地址,再到相应的数据存储器中读取数据,并进行下一步的操作(通常是执行)。程序指令存储和数据存储 ...…

查看全部问答>

免费教你实现LED指示灯,不容错过哦!

replyreload += \',\' + 371188;Timson,如果您要查看本帖隐藏内容请回复…

查看全部问答>

测脉冲,波形不能稳定

1、  用示波器测试脉冲时波形不能稳定下来,我用的时鼎阳SDS1102C,大家有没有遇到过这个问题?…

查看全部问答>

收购:现需要收购 SmartARM2400 的包装盒若干个,以及装书的那个硬包装盒若干个,谢谢!

发现 SmartARM 2400 的包装盒装东西非常合适,想弄几个, SmartARM套件中的那个装书的硬纸盒也非常不错,用来整理书架是非常不错的选择,非常想多弄几个。 可以和我邮件联系,  rampc@sian.com 不要太贵哦,我明天再把我想要的 ...…

查看全部问答>

有没有哪位在wince 6.0 r2上定制出中文模拟器?

自己在wince 6.0 r2上定制了一个模拟器,但不能显示中文,汉字都是以空框显示,不知道是什么原因?请高人指点一下!…

查看全部问答>

求教:stm的rtc用的爱普生的晶振叫什么晶振

                                 该晶振的1,4脚与OSC32IN,OSC32OUT 的连接有没规定:哪个脚跟哪个脚相连,找不到相关材料,望知情高手指导下,拜谢 ...…

查看全部问答>

有关rtdx的问题!

若想在H.263程序运行时,看到实时的压缩数据流,是否只能使用rtdx?仿真器必须用560吗?我现在用的是DM642,510JTAG,求各位大人给予高见!! …

查看全部问答>

利尔达开发板的问题,232串口调试不成功

1、PC机串口连接TEST44X学习板的9芯串行接口 J5_232 // 2、对拨动开关P_232、P1、U_USART,只有拨动开关 U_USART 的P2脚和P5脚拨到ON 的位置; 按照上面的设置设置了,我从pc端给开发板发数据,没有回来的数据,没反应,其他几个历程也不行,请问 ...…

查看全部问答>

前仿真与后仿真结果不同,原因是什么?

前仿真出来的状态机时钟正确的, 而后仿真出来的状态机中,有些状态之间就会有很短时间的其他状态,时间不到系统时钟的十分之一。 上图是后仿真时序,状态3后应该是状态4,但是实际却是状态7 和 6 ,而且时间很短,不到一个时钟周期,这导致了后 ...…

查看全部问答>