使用移位寄存器的按位运算



我开始学习更多关于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))

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

试试吧:

#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%02Xn",val);
for(i=0;i<8;i++)
{
PORTD |= !!(val & (HIGH << i));
printf("PORTD 0x%02Xn",PORTD);
}
}
return(0);
}        

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

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

val&(HIGH<<i)虽然非常简单,但您应该再次发布 HIGH 的定义,让我们假设它是 1,因为相对于代码的其余部分,这最有意义。 有一个从 0 到 7 的循环 i。 所以这意味着你用1<<0和(按位),然后1<<1,然后1<<2等等。1<<0只是 1 对吧? 所以val&(1<<0)和Val&0x01是一样的。1<<1 = 0x02如此价值&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 值进行评估,您会看到至少在假设 HIGH 为 1 的情况下val&(HIGH<<i)发生了什么,如果 HIGH 是 0,那么您将始终得到此代码中的零。

如果你想和一个步行的,你为什么不做val&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%02Xn",val);
for(i=0;i<8;i++)
{
PORTD |= !(val & (HIGH << i));
printf("PORTD 0x%02Xn",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%02Xn",val);
for(i=0;i<8;i++)
{
PORTD |= (~(val>>i))&1;
printf("PORTD 0x%02Xn",PORTD);
}
}
return(0);
}        
PORTD 0x00
PORTD 0x00
PORTD 0x01
PORTD 0x01
PORTD 0x01
PORTD 0x01
PORTD 0x01
PORTD 0x01

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

想知道他们是否试图连续做两个布尔值 not,将非零位移动到零位位置或其他什么......而是首先使用 LSBIT 或 MSBIT 优先使用 7-I。

#include <stdio.h>
#define HIGH 1
int main ( void )
{
unsigned char i;
unsigned char PORTD;
unsigned char val;
PORTD=0;
val=3;
{
printf("0x%02Xn",val);
for(i=0;i<8;i++)
{
PORTD |= (val>>i)&1;
printf("PORTD 0x%02Xn",PORTD);
}
}
return(0);
}        

最新更新