使用移位寄存器的按位操作

时间:2017-05-06 18:43:39

标签: c++ arduino bit-manipulation avr

我开始学习更多有关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 & (HIGH << i));行不是我100%清楚的。我知道我在PORTD上设置了第i位高位但是!!意味着什么和val&(HIGH <<i))

我知道这听起来很基本,但你可以帮帮我吗?

1 个答案:

答案 0 :(得分:0)

试一试:

#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。所以它似乎没有做任何事情。当你有&amp;&amp;例如,这是一个布尔表达式而不是按位逻辑,所以这可能是一个拼写错误?

val&(HIGH<<i)虽然非常简单,但你应该已经发布了HIGH被定义为的内容,我们假设它是1,因为它相对于代码的其余部分最有意义。有一个循环i从0到7.这意味着你正在(按位)1<<0然后1<<1然后1<<2依此类推。 1<<0只是1对吗?所以val&(1<<0)与val&amp; 0x01相同。 1<<1 = 0x02所以val&amp; 0x02。这段代码一次一位地隔离val中的各个位。你明白如果例如val是0x07然后0x07&amp; 0x02 = 0x02?你将每一位排成一行0x07 = 0b00000111,0x02 = 0b00000010

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

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

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

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

再增加i两次,并根据0x07的值进行评估,你会看到至少在val&(HIGH<<i)发生的事情,假设HIGH为1,如果HIGH为0,那么你将永远得到零这段代码。

如果你想要和一个走路的人为什么不要只做val&amp; HIGH,那么这再次没有意义,除非那个外围设备或那个端口另一端的东西一次只需要这一点。

双重爆炸(!!)对我来说看起来像是一个合乎逻辑的操作,在这里没有生意IMO。

单一爆炸是一种逻辑操作

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