小腥腥 发表于 2023-5-8 13:28:29

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

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;
               
}

isdkz 发表于 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 的值返回。

因此,这两种代码顺序的结果是等价的,不会影响读取的数据。

dolly_yos2 发表于 2023-5-8 15:08:52

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

为了简单直白一点方便大家都能看清楚,就不考虑处理8位数据的情况了,就假设 type 是一个4位宽的变量,初始化为0吧
先或再位移:i=0, type=0000, sda=1 -> type|sda=0001, type<<1=0010
i=1, type=0010, sda=0 -> type|sda=0010, type<<1=0100
i=2, type=0100, sda=0 -> type|sda=0100, type<<1=1000
i=3, type=1000, sda=1 -> type|sda=1001, type<<1=0010
先位移再或:i=0, type=0000, sda=1 -> type<<1=0000, type|sda=0001
i=1, type=0001, sda=0 -> type<<1=0010, type|sda=0010
i=2, type=0010, sda=0 -> type<<1=0100, type|sda=0100
i=3, type=0100, sda=1 -> type<<1=1000, type|sda=1001
《因此,这两种代码顺序的结果是等价的,不会影响读取的数据》

sfqxx 发表于 2023-5-8 18:00:48


2#说法有误,听我的{:10_256:}


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

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

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

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


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

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

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


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

sda << 8 | 0b0 b7 b6 b5 b4 b3 b2 b1// type = type | sda; type = type << 1;
(sda << 8) << 1

可以看到,第一种方式得到的结果最低位是 `sda` 的值,而其他位都左移了一位。而第二种方式得到的结果则是最高位是 `sda` 的值,其他位都左移了一位且最低位是 `0`。因此,这两种方式得到的结果是不同的,对于同样的输入数据,最终得到的返回值也会不相同。
有用请设置最佳答案

会玩stm32 发表于 2024-2-4 12:10:06

stm32的hal库可以直接初始化结构体来实现iic通讯
页: [1]
查看完整版本: iic总线的数据读取,先移位操作,再位或操作 和 先位或操作,再移位操作 ,为什么...