【问题标题】:Bitwise Operations using shift registers使用移位寄存器的按位运算
【发布时间】:2017-05-06 18:43:38
【问题描述】:

我开始学习有关 AVR ATMEGA 编程的更多信息。
阅读一篇关于 Arduinos 内部工作原理的文章,我正在了解 shiftOut 方法的结构。到目前为止,我对按位运算有点熟悉,但我有一个我还不明白的表达式:

void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
{
    uint8_t i;

    for (i = 0; i < 8; i++)  {
        if (bitOrder == LSBFIRST) {
            PORTD |= !!(val & (HIGH << i)); 
        } else {
            PORTD |= !!(val & (HIGH << (7 - i)));           
        }   
        PORTB |= (HIGH << clockPin);
        PORTB ^= (HIGH << clockPin);
    }
}

PORTD |= !!(val &amp; (HIGH &lt;&lt; i)); 对我来说不是 100% 清楚。我知道我在 PORTD 上将第 i 位设置为高,但 !!val&amp;(HIGH &lt;&lt;i)) 是什么意思

我知道这听起来很简单,但请你帮帮我吗?

【问题讨论】:

  • 对我来说看起来很糟糕。
  • 什么意思?
  • 这是Arudino wiring_shift.c的原始代码,除了1已更改为HIGH
  • 我需要做更多的研究来找出发生了什么,也许这个 ghee whiz C 代码可以以更易读的方式完成。

标签: c++ arduino bit-manipulation avr


【解决方案1】:

试试吧:

#include <stdio.h>
#define HIGH 0
int main ( void )
{

    unsigned char i;
    unsigned char PORTD;
    unsigned char val;

    PORTD=0;

    for(val=3;val;val<<=1)
    {
        printf("0x%02X\n",val);
        for(i=0;i<8;i++)
        {
            PORTD |= !!(val & (HIGH << i));
            printf("PORTD 0x%02X\n",PORTD);
        }
    }
    return(0);
}        

我不知道你对 HIGH 的定义是什么,但由于他们在一个字节上走了 8 次,我假设它是一位,它可能允许端口上的正逻辑或负逻辑,所以可能是 0 或 1我在想。

如果 HIGH 为 1,我得到所有 0x01,如果 HIGH 为 0,我得到所有 0x00。所以它似乎没有做任何事情。例如,当您有 && 时,这是一个布尔表达式而不是按位逻辑,那么这可能是一个错字吗?

val&amp;(HIGH&lt;&lt;i) 虽然很简单,但您应该再次发布 HIGH 的定义,假设它是 1,因为相对于其余代码而言,这最有意义。有一个循环 i 从 0 到 7。这​​意味着您正在(按位)与 1&lt;&lt;0 然后 1&lt;&lt;1 然后 1&lt;&lt;2 等等。 1&lt;&lt;0 只是 1 对吗?所以val&amp;(1&lt;&lt;0) 与 val&0x01 相同。 1&lt;&lt;1 = 0x02 所以 val&0x02。此代码一次一位地隔离 val 中的各个位。你明白如果例如 val 是 0x07 那么 0x07&0x02 = 0x02?您将每个位对齐 0x07 = 0b00000111, 0x02 = 0b00000010

 00000111
&00000010
=========
 00000010

您一次查看垂直隔离一列并使用 AND 真值表,它基本上说结果为 0,除非两个操作数都是 1,有一个列的两个操作数都是 1,所以该列的结果为 1,其余列的一个或另一个操作数或两者都为零,因此该列的结果为零。

 00000111
&00000100
=========
 00000100

 00000111
&000010000
=========
 00000000

再增加 i 两次并针对 0x07 的 val 进行评估,假设 HIGH 为 1,您至少会看到 val&amp;(HIGH&lt;&lt;i) 发生的情况,如果 HIGH 为 0,那么您将始终从中得到零代码。

如果你想要一个走路的人,为什么不做 val&HIGH,所以这又没有意义,除非那个外围设备或那个端口的另一端的东西每次都需要这个。

双重爆炸 (!!) 在我看来是一个合乎逻辑的操作,在 IMO 中没有任何意义。

一个 bang 是一个逻辑操作

#include <stdio.h>

#define HIGH 1

int main ( void )
{

    unsigned char i;
    unsigned char PORTD;
    unsigned char val;

    PORTD=0;

    val=3;
    {
        printf("0x%02X\n",val);
        for(i=0;i<8;i++)
        {
            PORTD |= !(val & (HIGH << i));
            printf("PORTD 0x%02X\n",PORTD);
        }
    }
    return(0);
}

这里的希望是我们知道编译器会为 false 生成 0x00,但它会为 true 生成什么? 0x01,0xFF,C语言大概有定义吧。所以上面的代码是根据我们的值生成一个比特流

PORTD 0x00
PORTD 0x00
PORTD 0x01
PORTD 0x01
PORTD 0x01
PORTD 0x01
PORTD 0x01
PORTD 0x01

在 lsbit 位置,循环会触发时钟。

我个人的偏好不是玩 C 语言规范的游戏,而是明确你想要做什么:

#include <stdio.h>
#define HIGH 1
int main ( void )
{

    unsigned char i;
    unsigned char PORTD;
    unsigned char val;

    PORTD=0;

    val=3;
    {
        printf("0x%02X\n",val);
        for(i=0;i<8;i++)
        {
            PORTD |= (~(val>>i))&1;
            printf("PORTD 0x%02X\n",PORTD);
        }
    }
    return(0);
}        

PORTD 0x00
PORTD 0x00
PORTD 0x01
PORTD 0x01
PORTD 0x01
PORTD 0x01
PORTD 0x01
PORTD 0x01

使用所有按位运算,没有布尔真/假运算。

想知道他们是否试图连续执行两个布尔非运算以将非零位移动到零位位置或其他什么...而不是首先用于 lsbit 或 7-i 用于 msbit。

#include <stdio.h>
#define HIGH 1
int main ( void )
{

    unsigned char i;
    unsigned char PORTD;
    unsigned char val;

    PORTD=0;

    val=3;
    {
        printf("0x%02X\n",val);
        for(i=0;i<8;i++)
        {
            PORTD |= (val>>i)&1;
            printf("PORTD 0x%02X\n",PORTD);
        }
    }
    return(0);
}        

【讨论】:

  • 所以你可以理解我希望 msbit first else 条件是从 7,6,5,4,3,2,1,0 lsbit first 0,1,2,3 走一个,4,5,6,7 就位和正在隔离,所以这是试图一次隔离一位,也许是移位器。但正如我的简单程序所演示的(如果你将 HIGH 设为 1,它至少不会与另一个编译器隔离位,所以如果这是可移植的 C 语言,它就没有多大意义)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-21
相关资源
最近更新 更多