最近闲来无聊,入了一块MPU6050,手头本来就有一块原子的STM32 MINI开发板,凑活着学习了一下IIC,特此总结。

IIC,是集成电路总线【Inter-Intergrated Circuit】的缩写,属于飞利浦公司的原创。

主要用两根线:数据线SDA和时钟线SCL。

关于时序方面本文就不截图了,网上一大堆。

下面就具体说IIC的传输过程中,比较重要的几个方法,下文的代码均是在STM32中实现,是一种模拟IIC。

SCL为输出模式的PC(12),SDA则根据情况切换输入和输出模式,为PC(11)。

1、开始信号

开始信号定义为:SCL高电平时,SDA的下降沿。

//开始信号
void IIC_Start(void)
{
SDA_OUT(); //SDA输出模式
IIC_SDA=;
IIC_SCL=;
delay_us(IIC_DELAY);
IIC_SDA=;//SCL高电平时SDA的下降沿
delay_us(IIC_DELAY);
}

2、结束信号

结束信号定义为:SCL高电平时,SDA的上升沿。

//结束信号
void IIC_Stop(void)
{
SDA_OUT();
IIC_SDA=;
IIC_SCL=;
delay_us(IIC_DELAY);
IIC_SDA=;//SCL高电平时SDA的上升沿
delay_us(IIC_DELAY);
}

其中的SDA_OUT()是STM32的IO口模式设置,其他MCU可忽略或更改。IIC_DELAY是定义的宏,可以控制延迟时间从而控制IIC速率。

3、IIC写一个字节

这里的写一个字节是说,控制了IIC总线的主机往总线上写数据。

void IIC_Send_Byte(u8 data)
{
u8 i;
SDA_OUT();//输出模式
for(i=;i<;i++)
{
IIC_SCL=;//拉低时钟 占据总线
delay_us(IIC_DELAY);
IIC_SDA=(data&0x80)>>;//每次1位,先高位
data<<=;
delay_us(IIC_DELAY);
IIC_SCL=;
delay_us(IIC_DELAY);
}
IIC_SCL=;
}

这里默认是先MSB后LSB,IIC_SDA根据数据位依次置1或0,传输数据时,SCL必须拉低,以此告诉其他器件“传输进行中”,在传输结束后,还需要再次拉高SCL总线。在送完一个字节后,拉低SCL,等待应答。

4、IIC读一个字节

//IIC读一个BYTE
u8 IIC_Read_Byte(void)
{
u8 i,receive=; SDA_IN();//输入模式
READ_SDA=;
for(i=;i<;i++)
{
receive<<=;//先接收的是高位
IIC_SCL=;
delay_us(IIC_DELAY);
IIC_SCL=;
delay_us(IIC_DELAY);
receive|=READ_SDA;
}
IIC_SCL=;
return receive;
}

这里同样的默认是先高位后低位,使用receive|=READ_SDA;来组成数据,接收数据位时,需要先拉低SCL再拉高SCL,然后再读取SDA的数据。这里的READ_SDA和IIC_SDA都是PC(11),只不过是不同的模式。

5、应答

在IIC中,应答不是必须的,所以对于应答的检测其实也不是必须的

下面是应答和不应答的代码。

//产生ACK应答
void IIC_Ack(void)
{
SDA_OUT();
IIC_SCL=;
delay_us(IIC_DELAY);
IIC_SDA=;
delay_us(IIC_DELAY);
IIC_SCL=;
delay_us(IIC_DELAY);
IIC_SCL=;//SDA为低时 拉低时钟线
delay_us(IIC_DELAY);
}
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL=;
SDA_OUT();
IIC_SDA=;
delay_us(IIC_DELAY);
IIC_SCL=;
delay_us(IIC_DELAY);
IIC_SCL=;// SDA为高时 SCL的脉冲
delay_us(IIC_DELAY);
}

6、应答检测

经过我的检验,当STM32写MPU6050时,是不需要进行应答检测的;但是当STM32读MPU6050时,如果不进行应答检测,就会出现数据出错/检测不到MPU6050等奇怪的错误,所以在应用IIC总线协议时,一律增加应答检测是比较好的一种规范做法

应答检测返回一个值,但是大多数情况中不需要用到这个返回值。

//应答信号确认
//1有ACK
//0无ACK
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=; SDA_IN();// SDA输入模式
IIC_SCL=;
delay_us(IIC_DELAY);
IIC_SDA=;
delay_us(IIC_DELAY);
IIC_SCL=;
delay_us(IIC_DELAY); while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>)
{
IIC_Stop();
return ;
}
}
IIC_SCL=;//关闭时钟
return ;
}

如果SDA一直是高电平没有被从设备【此处为MPU6050】拉低,则说明MPU没有应答,此时停止传输,并返回0.

如果接收到应答了,则把时钟线拉低,等待下一次开始信号。

7、MPU6050相关。

关于IIC的所有函数已经讲完了,下面贴一下MPU6050相关的操作。

//写MPU60X0
u8 IIC_Write_One_Byte(u8 regaddr, u8 data)
{
IIC_Start(); //起始信号
IIC_Send_Byte(SlaveAddress); //发送设备地址+写信号
if(IIC_Wait_Ack()==)
{
IIC_Stop();
return ;
}
IIC_Send_Byte(regaddr); //内部寄存器地址
//IIC_Wait_Ack();
IIC_Send_Byte(data); //内部寄存器数据
//IIC_Wait_Ack();
IIC_Stop(); //发送停止信号 return ;
}
//读MPU60X0
u8 IIC_Read_One_Byte(u8 regaddr)
{
u8 REG_data=;
IIC_Start(); //起始信号
IIC_Send_Byte(SlaveAddress); //发送设备地址+写信号
if(IIC_Wait_Ack()==)
{
IIC_Stop();
return ;
}
IIC_Send_Byte(regaddr); //发送存储单元地址,从0开始
IIC_Wait_Ack();
IIC_Start(); //起始信号
IIC_Send_Byte(SlaveAddress+); //发送设备地址+读信号
IIC_Wait_Ack();
REG_data=IIC_Read_Byte(); //读出寄存器数据,并且不应答
IIC_NAck(); //不回应
IIC_Stop(); //停止信号
return REG_data;
}

可以看到写一个字节的应答检测被我注释掉了,实验证明依旧可以正确写入MPU。

以上就是IIC的所有内容。

总结:IIC主要使用SDA,SCL两条线进行传输,其中SCL是独立的,SDA是接入总线的。当SCL为高时,说明有“事件”:比如开始信号、终止信号或者传输过程;当SCL为低时,说明总线闲,只要某一个设备拉高总线,并使得SDA总线产生一个下降沿,则主设备就可以得知是哪个设备的请求。这种通过独立SCL电平+SDA跳变的组合信号进行多设备整合的总线方案简单、有效,容错高,软件上易于实现,硬件上则更加方便。

[嵌入式]I2C协议指东的更多相关文章

  1. i2c协议

    i2c协议 http://blog.csdn.net/g_salamander/article/details/8016698 总线设备驱动模型 http://blog.csdn.net/u01395 ...

  2. i2c协议简要分析(转载)

    声明 本文大部分内容为转载,因此标定为转载 源地址: http://www.cnblogs.com/zym0805/archive/2011/07/31/2122890.html http://blo ...

  3. (原创) 巩固理解I2C协议(MCU,经验)

        题外话:这几天天气突然转冷了.今天已是11月23日了,查查黄历,昨天(11月22日)刚好是小雪,一夜温度骤降,果然老祖先的经验有灵验!冬天来了,还是多加加衣服,注意保暖! 1.Abstract ...

  4. I2C协议(转)

    1.I2C协议   2条双向串行线,一条数据线SDA,一条时钟线SCL.   SDA传输数据是大端传输,每次传输8bit,即一字节.   支持多主控(multimastering),任何时间点只能有一 ...

  5. 硬件和软件兼容i2c协议的24Cxx系列EEPROM存储器(转)

    源:硬件和软件兼容i2c协议的24Cxx系列EEPROM存储器 硬件上由于24c01的A0A1A2管脚不允许悬空,故暂时的想法是兼容24c02 ---24c16 使用一个dip8封装的芯片插座,A0 ...

  6. 很清晰的解读i2c协议【转】

    转自:https://blog.csdn.net/weixin_41718085/article/details/79376823 转载:http://dpinglee.blog.163.com/bl ...

  7. 很清晰的解读i2c协议

    很清晰的解读i2c协议 转载:http://dpinglee.blog.163.com/blog/static/14409775320112239374615/ 1.I2C协议 2条双向串行线,一条数 ...

  8. UART、SPI、I2C协议异同点

    I2C.SPI.UART都是常见的低速板级通信协议,目前主流的SoC都内置了这些通讯协议的控制器,同样,各种传感器.Touch控制器.指纹模块.蓝牙模块.WIFI模块也都兼容这三种通信方式的一种或几种 ...

  9. GPIO实现I2C协议模拟(1)

    最近需要用GPIO模拟I2C协议,如果是在Linux下面比较简单,但在Windows下面,是否有没Linux那么简单了. 索性自己对I2C协议还有一些了解,翻了SPEC并结合示波器量出的实际信号分析, ...

随机推荐

  1. 使用Mysql Workbench 导入数据库提示 ERROR 1227 (42000) at line 18: Access denied; you need (at least one of) the SUPER privilege(s) for

    今天再复制服务器上数据库的时候(使用Mysql Workbench )提示1227错误, 数据库版本5.7.18,复制到的数据库也是5.7.18. 总结一下网上的几种方法: 方法一: 最直观的翻译是说 ...

  2. 阅读《大型网站技术架构:核心原理与案例分析》第五、六、七章,结合《XXX重大技术需求征集系统》,列举实例分析采用的可用性和可修改性战术,将上述内容撰写成一篇1500字左右的博客阐述你的观点。

    这三章主要讲述的是网站的可用性.伸缩性和可扩展性. 首先,网站的可用性描述网站可有效访问的特性,相比于网站的其他非功能特性,网站的可用性更容易引起人们的注意,尤其是大型网站的可用性,如果大公司的网站出 ...

  3. Gruntjs提高生产力(三)

    以下例子来自真实项目,有所删减 grunt-test project 目录结构如下 一我的目的: 1.在src-dev目录中开发最终产出于src目录 2.src-dev中的index目录相当于一个wi ...

  4. linux中的redis缓存服务器

    Linux中的Redis缓存服务器 一.Redis基础部分: 1.redis介绍与安装比mysql快10倍以上 *****************redis适用场合**************** 1 ...

  5. 快速切题 poj 3026 Borg Maze 最小生成树+bfs prim算法 难度:0

    Borg Maze Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8905   Accepted: 2969 Descrip ...

  6. ftp的本地用户搭建

    前期的准备跟虚拟用户一样,就是配置文件不一样 修改配置文件 就是共享的都是自己的账号的家目录,然后启动服务就可以了 本地登陆的都是自己的账号密码 ftp本地的黑名单,

  7. HDU 3923 Invoker(polya定理+乘法逆元(扩展欧几里德+费马小定理))

    Invoker Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 122768/62768K (Java/Other) Total Subm ...

  8. UML_00_资源帖

    一.官方文档 https://www.uml-diagrams.org/ https://www.omg.org/spec/UML/ 二.精选资料 UML教程-w3cschool UML建模图实战笔记 ...

  9. ubuntu下编译neovim

    # 安装编译依赖 sudo apt-get install libtool libtool-bin autoconf automake cmake g++ pkg-config unzip -y # ...

  10. make笔记

    Makefile基本格式如下: target ... : prerequisites ... command ... ... 其中, target - 目标文件, 可以是 Object File, 也 ...