MicroChip的芯片手册真的好看,恨不得都做笔记,今天这篇文章先对IIC协议进行了一个回顾,针对具体的数据手册逐位描述。
后面就是STM32的工程,以及一个数据处理上面的运算。
5块钱性价比真的很高
在时钟的高电平周期内,SDA线上的数据必须保持稳定,数据线仅可以在时钟SCL为低电平时改变。
SCL高的时候,DATA是要稳定读取的
每次都是8位的数据一个字节, 读写 ACK
高->低
前面的1101,是固定的电平,也叫器件码。后面的A2,A1,A1,是000,闭合图形的意思大概是固定的。
一次传输一个字节,那么最后就是一个第九位,为0的时候是ACK收到
前面的7位为地址码,第八位是写入标志,第九位是回复
在总线的一次数据传输过程中,可以有以下几种组合方式:
[1] 主机向从机发送数据,数据传送方向在整个传送过程中不变:
注:有阴影部分表示数据由主机向从机传送,无阴影部分则表示数据由从机向主机传送。
A表示应答(低电平), A非表示非应答(高电平)。S表示起始信号,P表示终止信号。
[2]主机在第一个字节后,立即从从机读数据:
[3]在传送过程中,当需要改变传送方向时,起始信号和从机地址都被重复产生一次,但两次读/写方向位正好反相:
我来说一个这个18位是什么意思,一个数据有18位,除去别的样板数据。我们知道这个18bit的数据就是18个2进制位置,红色的部分,D0-D17就是18个也就是说18位的数据都是传输完整了,LSB就是D0,数据从这里开始。接着从右往左排列三个时钟周期,一个完整的应该是9位,前两个数据位满满的,第三个用了两位,最后的数据位怎么办?因为是连续完整的,所以这里的做法就是把剩下的位置都补18位数据的MSB,就是最后一个数字,我们忽略就可以。
这个就是说你是12或者是14的情况下,也是有多余的位置没有传输
这是低位数下的传输
IIC的输入输出结构采用的是开漏的结构。
开漏结构不能够自主得到高电平,所以需要通过外部上拉电阻Rp来的实现IIC通信过程中的高电平。
Rp的大小取决于IIC不同模式时的灌电流大小。
由于种类的设备都有可能连接到IIC总线上面,比如说CMOS、NMOS等,所以IIC的高电平和低电平的标准是不一定的。高电平和低电平的值分别为0.7VDD和0.3VDD。
应答位、非应答位:当主机传送8位数据结束后,主机会将SDA线拉高,此时如果从机正确接收数据则会将SDA拉低并在SCL高电平时保持低电平,这个信号为ACK信号。如果在传输8位数据后从机没有将SDA拉低则该信号为NACK。如果出现NACK则表示数据传输出错。
是主动拉低的意思
数据有效性:当时钟信号为高电平的时候,数据线上的信号需要保持不变也就是在时钟线为高电平的时候数据线出现上升下降沿的话就会产生停止和启动信号,从而导致数据的传输出错。
byte:SDA上的数据传输是以8bit即一个字节为单位传输的,每一次传输的字节数没有限制,每传输完一个字节后必须跟随一个应答位。
我们以01001001(0X49)为例,其时序图如下:
写操作:主机确定了从机的设备地址后,生成一个开始信号,然后向IIC总线上面发送设备的地址和读写方向标志。从机检测到该地址和自己设备地址相对应后,回复主机一个应答信号。主机接收到应答信号后就开始向这个设备以字节为单位发送数据,每一个字节后面都会带有从机的应答信号,直到主机发送完成最后一个数据后生成一个停止信号结束此次数据的传输。
写就是主机一直捣鼓,后来问下从机,逼崽子听见没有
读操作:读操作与写操作有一些类似,同样的是需要确定需要读取的从设备的地址。然后主机生成开始信号,再向IIC总线上发送从设备的地址和读数据的指令。从设备接收到地址与自己的吻合后会产生一个应答信号。就这从设备就开始向主机发送主机想要读取的数据,主机正确接收数据后会向从机回复应答信号,当主机想要结束读取操作时,主机会回复一个非应答信号,然后生成停止信号结束数据的读取。
牛鼻
所示是示波器采集的IIC信号,我们通过自己的观察得到这一段IIC包含的信息,主机向地址为0XA0 的设备写入0X0C。
配置寄存器
IIC总线的传输速率一般是几百KHZ,传输速率设置为几MHz就可以。这里我们采用4MHz的采样率对IIC进行采样。
这些是一些函数,顺手翻译
这个是配置位
第4位
11 18位
最后两个00,不增益
1101是跑不了的
那就000,最后再补一个
地址也就是这样的
IIC的CubeMX配置,就默认就好
这个是初始化函数
翻译的另外一个函数
计数值满了以后就开始一次转换
输出的位数字
这个就是建立的一个数组
好,两个位
先留啊
具体就是这样算的,然后除了最后两位,前面都是0
中,低
直接拼接
这是就是左移,将一个二进制数的所有位向左移动指定的位数,右边用0填充。
之后相加是很简单的事情了。
也可以写成完整的位运算的样子,一个字节一个字节的去取
我们上面拿到的数据才是一堆位数据,我们要变成人类可读的数字
所有的数据都是补码:
判断一个32位无符号整数(Voltage)的最高位符号位是否为1。
& 是按位与运算符,用于将两个数的对应位进行逻辑与操作。
0x00020000 是一个十六进制数,其二进制表示为 :
00000001 00000000 00000000 00000000。
Voltage & 0x00020000 的结果是将 Voltage 的最高位符号位与 0x00020000 进行按位与操作。
如果结果等于 0x00020000,则说明 Voltage 的最高位符号位为1,返回 True;否则返回 False。
如果是1的话,也就是算过的数字是不变的
我们知道了是负数,接着把他还原
这段代码是用于将一个32位无符号整数(Voltage)的最高位符号位清零,并将其转换为正数。
Voltage &= 0x0001ffff; 这行代码将 Voltage 与十六进制数 0x0001ffff 进行按位与操作。
0x0001ffff 的二进制表示为:
00000001 11111111 11111111 11111111。
这个操作的目的是保留 Voltage 的低20位,并将最高位符号位清零。
Voltage = (~Voltage) 1;
这行代码首先对 Voltage 进行按位取反操作,然后加1。加1是为了将取反后的负数转换为正数。
Voltage &= 0x0001ffff; 这行代码再次将 Voltage 与十六进制数 0x0001ffff 进行按位与操作。
这个操作的目的是保留 Voltage 的低20位,将其转换为正数。
最终,这段代码的作用是将一个32位无符号整数的最高位符号位清零,并将其转换为正数。
这个就是负数的
正数的
如果是CubeMX的工程,记得把自己的头文件放这里
C文件是在这里添加
这样就添加好了
编译通过
最后展示几个用途
代码语言:javascript复制https://dreamsourcelab.cn/articles/i2c/