如何反转存储在存储器地址中的位?

时间:2019-07-18 20:58:40

标签: c++ beagleboneblack spi ioctl

我正在尝试通过光耦合器电平转换器发送SPI数据。 (基本上将3.3v信号转换为5v信号)

在此过程中,电平转换器翻转所有位(反相逻辑),而不是使用另一个反相器来重新对齐信号,我认为将反相位简单地从SPI端口发送会更容易。

为此,我将片选上的模式设置为高电平有效并更改了时钟极性。现在,我尝试对发送的数据进行翻转。

  unsigned short* tx;
  unsigned short* rx;
  while(!feof(data_file)){
    fread(buffer, 2, 80, data_file);
    tx = buffer;
    for(int i = 0; i < 80; i++){
      (*tx)= ~(*tx); //added this line
      spi.transfer((unsigned char*) tx,(unsigned char*) rx, 2);
      (*rx)= ~(*rx); //also added this line
      printf("0x%04x\n", *rx);
      pinControl.selectChip(i%8);
      usleep(5);
    }

在添加此内容之前,有很好的干净输出 收到的数据:

0x04cb
0x04cb
0x04cb
0x04cb
0x04cb
0x04cb
0x04cb
0x050b
0x050b
0x050b
0x050b

反转后:

0xfd36
0x02c9
0xfd36
0x02c9
0xfd36
0x02c9
0xfd36
0x02c9
0xfd36
0x02c9
0xfd36
0x02c9
0xfd36
0x02c9

请注意,我发送的数据是单调递增的,因此第二个输出不正确。

我的假设是

(* tx)=〜(* tx)

实际上并没有反转位。

所以我试图检验这个理论。

  unsigned short* tx;
  unsigned short* rx;
  (*tx)=4;
  std::cout << *tx << endl;
  std::cout << ~(*tx) << endl;
  (*tx) = ~(*tx);
  std::cout << (*tx);

收益:

4
-5 <-- this is ~4 correct
65531 <-- this is unexpected

2 个答案:

答案 0 :(得分:1)

两个代码示例中的问题都是指针使用不正确。 您正确声明了指针,但没有为它们分配有效的内存地址。

例如,当您执行此操作时:

unsigned short* tx;
(*tx)=4;

tx包含一些随机地址,因为您没有分配它。 因此,当您取消引用并尝试将4放在下一行时,无法得知这4的实际位置。

tx中的值可能为0或接近0,您的程序将崩溃(SEGFAULT)。 或者,其他一些代码可能正在使用此内存,并且将覆盖该值,这将解释为什么您突然得到65531的原因,尽管它与先前的值无关。

在带有SPI调用的代码示例中,存在两个问题:

  1. 您永远不会在循环中前进tx指针,因此您总是要反转并发送相同的两个字节。

  2. 您没有为rx指针分配任何有效的内存,因此与测试一样,数据将被随机放置,并且程序可能会随机崩溃。

最后,最大的问题是:您如何声明buffer? 如果以与rxtx相同的方式声明,那么即使从文件读取也可能无法正常工作。

这是您的代码应能正常运行的版本:

unsigned short tx;
unsigned short rx;

while(fread(&tx, 2, 1, data_file) > 0) {
   tx = ~tx;
   spi.transfer(&tx, &rx, 2);
   rx = ~rx; //also added this line
   printf("0x%04x\n", rx);
   pinControl.selectChip(i % 8);
   usleep(5);
}

答案 1 :(得分:1)

rx是未初始化的指针。它恰好指向了一些有效的可访问内存位置。您需要像使用tx那样将其指向缓冲区。

您的程序(据说)从文件中读取80个字的数据,因此,其目的可能是通过spi.transfer进行传输。但是,尽管循环数达80个字,但并不会增加txrx指针。

因此,您正在做的是重复反转buffer[0]始终指向的tx的位。同样,rx始终指向相同的未知内存位置,该位置已切换。

您看到的重复的值对:

0xfd36
0x02c9

实际上是彼此的按位倒数。如果您知道十六进制数字和二进制半字节之间的对应关系,这是显而易见的。

还必须测试fread的返回值。 fread返回它能够读取多少个元素,可能低至零。

while (!feof(...))模式不正确。对于尚未尝试输入操作的新打开流,feof(f)始终为false。

stdio范例是必须单独测试I / O操作的返回值。如果输入操作失败,则可能是由于数据结束或某些I / O错误。在流f上输入失败后,两个标志feof(f)ferror(f)中的一个为真,以区分数据结束和I / O错误。