鱼C论坛

 找回密码
 立即注册
查看: 476|回复: 4

iic总线的数据读取,先移位操作,再位或操作 和 先位或操作,再移位操作 ,为什么...

[复制链接]
发表于 2023-5-8 13:28:29 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
u8 read_type()
{
        u8 type=0x00,i;
        scl=0;
        somenop();
        sda=1;
        somenop();
        for(i=0;i<8;i++)
        {
                scl=1;
                somenop();       
                type=type<<1;        //先移位操作,再位或操作  和 先位或操作,再移位操作 ,为什么读取的数据会不相同
                type=type|sda;
                scl=0;
                somenop();
        }
        return type;
               
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-5-8 13:28:56 | 显示全部楼层
这段代码是用来读取 IIC 总线上的数据。其中,type 变量是用来存储读取到的数据的,初始值为 0x00。for 循环中的代码是读取 8 位数据的过程,每次循环读取一位数据。

对于问题中的两种不同的代码顺序,即先移位再位或和先位或再移位,其实本质上是一样的,因为位运算的结果不受顺序的影响。

对于先移位再位或的代码顺序,type=type<<1 是将 type 左移一位,然后将 sda 的值通过位或运算(|)赋值给 type 的最低位。这样可以将 sda 的值存储到 type 中。最后将 type 的值返回。

对于先位或再移位的代码顺序,type=type|sda 是将 sda 的值通过位或运算(|)赋值给 type 的最低位,然后 type=type<<1 是将 type 左移一位。这样也可以将 sda 的值存储到 type 中。最后将 type 的值返回。

因此,这两种代码顺序的结果是等价的,不会影响读取的数据。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-8 15:08:52 | 显示全部楼层
isdkz 发表于 2023-5-8 13:28
这段代码是用来读取 IIC 总线上的数据。其中,type 变量是用来存储读取到的数据的,初始值为 0x00。for 循 ...

为了简单直白一点方便大家都能看清楚,就不考虑处理8位数据的情况了,就假设 type 是一个4位宽的变量,初始化为0吧
先或再位移:
  1. i=0, type=0000, sda=1 -> type|sda=0001, type<<1=0010
  2. i=1, type=0010, sda=0 -> type|sda=0010, type<<1=0100
  3. i=2, type=0100, sda=0 -> type|sda=0100, type<<1=1000
  4. i=3, type=1000, sda=1 -> type|sda=1001, type<<1=0010
复制代码

先位移再或:
  1. i=0, type=0000, sda=1 -> type<<1=0000, type|sda=0001
  2. i=1, type=0001, sda=0 -> type<<1=0010, type|sda=0010
  3. i=2, type=0010, sda=0 -> type<<1=0100, type|sda=0100
  4. i=3, type=0100, sda=1 -> type<<1=1000, type|sda=1001
复制代码

《因此,这两种代码顺序的结果是等价的,不会影响读取的数据》
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-8 18:00:48 | 显示全部楼层

2#说法有误,听我的


这段代码通过 I2C 总线读取一个 8 位数据,其中 `sda` 和 `scl` 分别为总线的数据和时钟线。函数中定义了一个 `type` 变量作为返回值,最终将读取到的 8 位数据返回。

在读取过程中,首先将时钟 `scl` 置为 0,然后将数据 `sda` 设置为高电平,再次延迟一段时间。之后进入循环,共进行 8 次读取操作。每次读取都需要将时钟 `scl` 置为 1,这样被读设备才能在数据线上输出下一位数据,并等待一段时间稳定后读取该数据,将其存储在 `type` 变量中。最后将时钟 `scl` 再次置为 0,等待一段时间稳定后开始下一轮读取,直到读取完全部 8 位数据为止。

在循环中,对于每一位数据,都使用位运算符 `<<` 左移 1 位,即将 `type` 左移一位(相当于将 `type` 乘以 2),并判断数据线上当前位的状态,如果是高电平,则使用位运算符 `|` 将 `type` 的最低位设为 1。这里通过左移和或运算操作组合来实现了将 8 个二进制位转换为一个八位无符号整数。

至于问题中的“先移位操作,再位或操作和先位或操作,再移位操作为什么读取的数据会不相同”,可能指的是以下两种语句的结果不同:


  1. type = type << 1;  // 先左移后位或操作
  2. type = type | sda;

  3. type = type | sda; // 先位或操作后左移
  4. type = type << 1;
复制代码

这两行代码实现的逻辑是不同的。第一种方式先将 `type` 左移,再用 `sda` 的值更新 `type` 的最低位。而第二种方式则是先将 `sda` 的值更新到 `type` 的最低位,再将 `type` 左移。因此,如果读取的数据是一个二进制数 `b7 b6 b5 b4 b3 b2 b1 b0`(其中 `b7` 表示最高位,`b0` 表示最低位),则上述两行代码实际操作后分别得到的结果为:


  1. 0b0 b7 b6 b5 b4 b3 b2 b1  // type = type << 1; type = type | sda;
  2. 0b0 b7 b6 b5 b4 b3 b2 b1 | sda

  3. sda << 8 | 0b0 b7 b6 b5 b4 b3 b2 b1  // type = type | sda; type = type << 1;
  4. (sda << 8) << 1
复制代码


可以看到,第一种方式得到的结果最低位是 `sda` 的值,而其他位都左移了一位。而第二种方式得到的结果则是最高位是 `sda` 的值,其他位都左移了一位且最低位是 `0`。因此,这两种方式得到的结果是不同的,对于同样的输入数据,最终得到的返回值也会不相同。
有用请设置最佳答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-2-4 12:10:06 | 显示全部楼层
stm32的hal库可以直接初始化结构体来实现iic通讯
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-29 02:53

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表