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

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

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

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

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

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

1、开始信号

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

  1. //开始信号
  2. void IIC_Start(void)
  3. {
  4. SDA_OUT(); //SDA输出模式
  5. IIC_SDA=;
  6. IIC_SCL=;
  7. delay_us(IIC_DELAY);
  8. IIC_SDA=;//SCL高电平时SDA的下降沿
  9. delay_us(IIC_DELAY);
  10. }

2、结束信号

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

  1. //结束信号
  2. void IIC_Stop(void)
  3. {
  4. SDA_OUT();
  5. IIC_SDA=;
  6. IIC_SCL=;
  7. delay_us(IIC_DELAY);
  8. IIC_SDA=;//SCL高电平时SDA的上升沿
  9. delay_us(IIC_DELAY);
  10. }

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

3、IIC写一个字节

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

  1. void IIC_Send_Byte(u8 data)
  2. {
  3. u8 i;
  4. SDA_OUT();//输出模式
  5. for(i=;i<;i++)
  6. {
  7. IIC_SCL=;//拉低时钟 占据总线
  8. delay_us(IIC_DELAY);
  9. IIC_SDA=(data&0x80)>>;//每次1位,先高位
  10. data<<=;
  11. delay_us(IIC_DELAY);
  12. IIC_SCL=;
  13. delay_us(IIC_DELAY);
  14. }
  15. IIC_SCL=;
  16. }

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

4、IIC读一个字节

  1. //IIC读一个BYTE
  2. u8 IIC_Read_Byte(void)
  3. {
  4. u8 i,receive=;
  5.  
  6. SDA_IN();//输入模式
  7. READ_SDA=;
  8. for(i=;i<;i++)
  9. {
  10. receive<<=;//先接收的是高位
  11. IIC_SCL=;
  12. delay_us(IIC_DELAY);
  13. IIC_SCL=;
  14. delay_us(IIC_DELAY);
  15. receive|=READ_SDA;
  16. }
  17. IIC_SCL=;
  18. return receive;
  19. }

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

5、应答

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

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

  1. //产生ACK应答
  2. void IIC_Ack(void)
  3. {
  4. SDA_OUT();
  5. IIC_SCL=;
  6. delay_us(IIC_DELAY);
  7. IIC_SDA=;
  8. delay_us(IIC_DELAY);
  9. IIC_SCL=;
  10. delay_us(IIC_DELAY);
  11. IIC_SCL=;//SDA为低时 拉低时钟线
  12. delay_us(IIC_DELAY);
  13. }
  14. //不产生ACK应答
  15. void IIC_NAck(void)
  16. {
  17. IIC_SCL=;
  18. SDA_OUT();
  19. IIC_SDA=;
  20. delay_us(IIC_DELAY);
  21. IIC_SCL=;
  22. delay_us(IIC_DELAY);
  23. IIC_SCL=;// SDA为高时 SCL的脉冲
  24. delay_us(IIC_DELAY);
  25. }

6、应答检测

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

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

  1. //应答信号确认
  2. //1有ACK
  3. //0无ACK
  4. u8 IIC_Wait_Ack(void)
  5. {
  6. u8 ucErrTime=;
  7.  
  8. SDA_IN();// SDA输入模式
  9. IIC_SCL=;
  10. delay_us(IIC_DELAY);
  11. IIC_SDA=;
  12. delay_us(IIC_DELAY);
  13. IIC_SCL=;
  14. delay_us(IIC_DELAY);
  15.  
  16. while(READ_SDA)
  17. {
  18. ucErrTime++;
  19. if(ucErrTime>)
  20. {
  21. IIC_Stop();
  22. return ;
  23. }
  24. }
  25. IIC_SCL=;//关闭时钟
  26. return ;
  27. }

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

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

7、MPU6050相关。

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

  1. //写MPU60X0
  2. u8 IIC_Write_One_Byte(u8 regaddr, u8 data)
  3. {
  4. IIC_Start(); //起始信号
  5. IIC_Send_Byte(SlaveAddress); //发送设备地址+写信号
  6. if(IIC_Wait_Ack()==)
  7. {
  8. IIC_Stop();
  9. return ;
  10. }
  11. IIC_Send_Byte(regaddr); //内部寄存器地址
  12. //IIC_Wait_Ack();
  13. IIC_Send_Byte(data); //内部寄存器数据
  14. //IIC_Wait_Ack();
  15. IIC_Stop(); //发送停止信号
  16.  
  17. return ;
  18. }
  19. //读MPU60X0
  20. u8 IIC_Read_One_Byte(u8 regaddr)
  21. {
  22. u8 REG_data=;
  23. IIC_Start(); //起始信号
  24. IIC_Send_Byte(SlaveAddress); //发送设备地址+写信号
  25. if(IIC_Wait_Ack()==)
  26. {
  27. IIC_Stop();
  28. return ;
  29. }
  30. IIC_Send_Byte(regaddr); //发送存储单元地址,从0开始
  31. IIC_Wait_Ack();
  32. IIC_Start(); //起始信号
  33. IIC_Send_Byte(SlaveAddress+); //发送设备地址+读信号
  34. IIC_Wait_Ack();
  35. REG_data=IIC_Read_Byte(); //读出寄存器数据,并且不应答
  36. IIC_NAck(); //不回应
  37. IIC_Stop(); //停止信号
  38. return REG_data;
  39. }

可以看到写一个字节的应答检测被我注释掉了,实验证明依旧可以正确写入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. layui弹窗宽度固定高度自适应界面

    //默认上下15px的边距高度,可根据需要修改function layuiDialogFitScreen(){ var layui_title_height=$(window.parent.docum ...

  2. 51nod-1179-最大的gcd(数学)

    1179 最大的最大公约数  题目来源: SGU 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题  收藏  关注 给出N个正整数,找出N个数两两之间最大公约数的最大 ...

  3. mysql学习之旅

    1,mysql安装脚本 #!/bin/bash RSYNC='10.39.2.120::wenhui/database/install' CMAKE='cmake-2.8.6.tar.gz' MYSQ ...

  4. 【问题解决记录】无法识别的标志“-sdlMode”,在“p2”中

    本文为大便一箩筐的原创内容,转载请注明出处,谢谢:http://www.cnblogs.com/dbylk/ 这是本人第一次使用MarkDown编辑器,试试看效果-w-,下面是正文: 一.报错原因 昨 ...

  5. [Android]如何减小APK的大小

    能不引用的外部包就不用,删除没用的图片.xml,优化代码去掉没用的部分,能异步下载的资源就运行时从网络上下载.

  6. LeetCode OJ:Ugly Number II(丑数II)

    Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime factors ...

  7. React 与 可视化

    一般会想到 canvas 和 svg ; svg更适合画图, 但由于cavans在移动端的良好兼容性, 使用的更广; 什么是svg, scalable vector graphics  全称 可缩放矢 ...

  8. 【PL/SQL编程】循环语句

    1. loop语句 loop plsql_sentence; exit when end_condition_exp; end loop; loop语句会先执行一次循环体,然后再判断“exit whe ...

  9. js函数的伪重载

    这也是今天写东西是遇到的一个问题,导致我联想起了函数重载的问题. 在javascript中是没有函数重载机制的,对于用惯了java开发的同学可能就表示吃惊了,我屮艸芔茻,函数 没有重载?那怎么搞?!! ...

  10. GPU编程自学5 —— 线程协作

    深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...