[嵌入式]I2C协议指东
最近闲来无聊,入了一块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协议指东的更多相关文章
- i2c协议
i2c协议 http://blog.csdn.net/g_salamander/article/details/8016698 总线设备驱动模型 http://blog.csdn.net/u01395 ...
- i2c协议简要分析(转载)
声明 本文大部分内容为转载,因此标定为转载 源地址: http://www.cnblogs.com/zym0805/archive/2011/07/31/2122890.html http://blo ...
- (原创) 巩固理解I2C协议(MCU,经验)
题外话:这几天天气突然转冷了.今天已是11月23日了,查查黄历,昨天(11月22日)刚好是小雪,一夜温度骤降,果然老祖先的经验有灵验!冬天来了,还是多加加衣服,注意保暖! 1.Abstract ...
- I2C协议(转)
1.I2C协议 2条双向串行线,一条数据线SDA,一条时钟线SCL. SDA传输数据是大端传输,每次传输8bit,即一字节. 支持多主控(multimastering),任何时间点只能有一 ...
- 硬件和软件兼容i2c协议的24Cxx系列EEPROM存储器(转)
源:硬件和软件兼容i2c协议的24Cxx系列EEPROM存储器 硬件上由于24c01的A0A1A2管脚不允许悬空,故暂时的想法是兼容24c02 ---24c16 使用一个dip8封装的芯片插座,A0 ...
- 很清晰的解读i2c协议【转】
转自:https://blog.csdn.net/weixin_41718085/article/details/79376823 转载:http://dpinglee.blog.163.com/bl ...
- 很清晰的解读i2c协议
很清晰的解读i2c协议 转载:http://dpinglee.blog.163.com/blog/static/14409775320112239374615/ 1.I2C协议 2条双向串行线,一条数 ...
- UART、SPI、I2C协议异同点
I2C.SPI.UART都是常见的低速板级通信协议,目前主流的SoC都内置了这些通讯协议的控制器,同样,各种传感器.Touch控制器.指纹模块.蓝牙模块.WIFI模块也都兼容这三种通信方式的一种或几种 ...
- GPIO实现I2C协议模拟(1)
最近需要用GPIO模拟I2C协议,如果是在Linux下面比较简单,但在Windows下面,是否有没Linux那么简单了. 索性自己对I2C协议还有一些了解,翻了SPEC并结合示波器量出的实际信号分析, ...
随机推荐
- 设计模式--模板方法模式C++实现
模板方法模式C++实现 1定义 定义一个操作的算法的框架,而将一些步骤延迟到子类中.使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 实现方案:将算法/逻辑框架放在抽象基类中,并定义好 ...
- macOS和常用命令
macOS 常用命令 1. 显示“任何来源”选项 sudo spctl --master-disable 2. 阻止屏保和睡眠 caffeinate -t 3600 这是一个BSD命令.-t可选,按C ...
- Linux 踩坑记录
1. Linux系统上用火狐浏览器看视频的时候发现没有安装flash player插件,无法播放视频.简单几步安装插件,就可以快乐地使用linux系统看视频了. 步骤如下: 一.打开视频网站时提示无法 ...
- ZOJ 2283 Challenge of Wisdom 数论,Dilworth Theorem,求最长反链 难度:2
Challenge of Wisdom Time Limit: 2 Seconds Memory Limit: 32768 KB Background "Then, I want ...
- ES重要配置
虽然ES需要的配置很少,但是仍然有些配置需要我们手工去配置,尤其是在产品上线之前. path.data and path.logs cluster.name node.name bootstrap.m ...
- Java基础学习-Collection体系结构和迭代测试
package Collection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterat ...
- PostgreSQL CPU满(100%)性能分析及优化(转)
PostgreSQL CPU满(100%)性能分析及优化 转自:https://help.aliyun.com/knowledge_detail/43562.html 在数据库运维当中,一个DB ...
- Xcode Server (Xcode9)搭建CI
Xcode 9将Xcode Server集成进来了,这是Xcode一个新特性,不用去单独下载server了,server可以用来做CI.自动化Test等等.这里主要介绍搭建CI,相当简单 打开开关,新 ...
- Linux:Aircrack-ng
Aircrack-ng 工具主要有 airmon-ng 处理网卡工作模式 airodump-ng 抓包 aircrack-ng 破解 aireplay-ng 发包,干扰 另外还要用到以下 linux ...
- java中遍历类中的属性、调用getter&setter方法
public static void testReflect(Object model) throws NoSuchMethodException, IllegalAccessException, I ...