怎么样:
GIMSK |= (1 << PCIE);
PCMSK |= (1 << PCINT4);
等于(我可以在程序的设置中使用上方或下方的内容,可以工作并激活引脚4),由于某种原因,GIMSK和PCMSK彼此相等,我试图了解原因。
GIMSK = 0b00100000;
PCMSK = 0b00010000;
第一: https://thewanderingengineer.com/2014/08/11/pin-change-interrupts-on-attiny85/
秒: https://embeddedthoughts.com/2016/06/06/attiny85-introduction-to-pin-change-and-timer-interrupts/
工作表说PCIE在位掩码中为0b00100000,所以| =(1 << PCIE)等于那吗?如果PCIE应该是这样的话,我不明白,那么做一个转变会改变那个值。 您将如何以及为什么使用它而不是二进制文件?我猜想它会改变它,但是显然,它不会改变。我在几个不同的地方问过这个问题,没人能回答,所以我来了。希望有人可以解释。
我是C语言的新手,我今天刚刚学习了按位运算,以弄清楚这里发生了什么,我的代码确实可以工作,但是我想知道为什么!谢谢。
答案 0 :(得分:1)
这是相等的,因为在OR
操作之前,这些寄存器的所有其他位均为0
1u << x向左移x个位置。结果,您清除了除x
以外的所有位的数字
答案 1 :(得分:0)
变量在标头中定义,或在其他地方定义该位用于兼容性。新卡?只需获取一个新的定义文件(通常会自动完成)。 PCIE和PCINT4定义在某个地方,如果需要的话可以找它,但这应该可以为您处理这些细节。
但是,由于第二组,我们知道PCINT4为4,PCIE为5,在这里我们看到移位的'1'-PCIE为5个空格,PCINT4为4个空格。这就是为什么它们看起来相等的原因。因为它们在字面上是等价的,所以一旦您对表达式求值,便知道0b意味着后面的内容是二进制的(可能很明显)。但是它们并不等效。不太准确-见下文-
4-因此,如果您对寄存器进行“ OR ”,则如果TRUE,它将覆盖存在的所有内容,并强制其为True,并保留其他所有内容。我们将1移位以显示所需的位,然后选择将具有所需效果的操作数。看看桌子上的其他人。**
但是我们得到GIMSK = GIMSK OR 0b00100000
和PCMSK = PCMSK OR 0b00010000;
这是相似的,但不完全相同。
The devil is in the details, see below for
又有人更好地读了这篇,把我带到了永远。
GIMSK |= (1 << PCIE); PCMSK |= (1 << PCINT4);
等于(我可以在我的程序设置中使用上面或下面的内容,可以工作并激活引脚4), GIMSK和PCMSK由于某种原因彼此相等,我是 试图了解原因。
GIMSK = 0b00100000; PCMSK = 0b00010000;
让我们从词法上以令牌开始,所以我们都在谈论同一件事。
GIMSK | =(1 << PCIE);
从第一位开始。拆开它-
GIMSK- variable or 'id'
|= - operator and assignment combo bitwise OR and =
1 - the integer 1
<< - shift operation
PCIE - Variable and ID
当然,这使得很难解释。什么是|=
?我敢肯定,这使这个问题有些混乱。最著名的是+ =。因此,如果我有一个变量x,并且我总是在任何时候加进它本身,等等,那么变量在等式的两边。像这样:
x = x + 1 ;this is so common though, that in C, it was shortened to +=
x += 1 ; now its written like this. It takes some time
因此程序员很懒惰,如果某种“酷”东西以一种语言弹出,通常会蔓延到其他语言,所以大多数语言现在都允许这样做。如果您至少用Java编写+ =或= +,它会确实有所不同。不会的。
y = y * 2; it works for other types of operands
y *= 2; Now we take y, multiply by 2 and assign back to y.
现在,让我们看一下'C'风格的按位运算符-尽管有例外,但大多数语言都采用了类似的符号。
通常在C语言中,您使用两个符号来比较“ &&”或“ ||”或'==' 好吧,这是因为单个运算符比较位。之所以有一个符号,是因为它在计算机上更为自然,而且更为常见。不再是我们了,我们通过软件的层次将其抽象了。
所以我们有:** Good Source for more info
And we can also make this compond (Click for more info)
基本上,他们将右侧的一些变量与左侧的变量进行比较,然后将其分配回右侧。像这样x = x* y
=> x *= y
。
同样,我们有x &= y
,x |= y
和x ^= y
因此,对于以上内容-我们首先将其拆开-长时间手写以使其易于理解-
GIMSK |= (1 << PCIE)
GIMSK = GIMSK | (1 << PCIE) #OK! much easier to understand if your new.
#NOW we can lexigraphically analyze this
VarA {assignment} VarA OR ( 1 {Operator} VarB )
#Ignore the assignment side, for now, practice order of Operations
#Start with Parenthetical Exp.
1 {Operator} VarB
#It turns out this is defined.
#OP Didnt know but computer does. = 5 in this case.
#so 1, shift left 5. To bitwise shift, need bits
1 => 0b00000001 << 5 = 0b00100000
# shift left is really multiplied by 2 in base 10, divide by 2 in shift right. Beware Right Shift, esp in float.
现在我们有了:GIMSK = GIMSK OR 0b00100000
GIMSK | =(1 << PCIE); PCMSK | =(1 << PCINT4);
GIMSK = 0b00100000; PCMSK = 0b00010000; 您刚才所说的是。或多或少。尽管正如我在简短回答中上面提到的,第二个操作并不等效。多数民众赞成在最后覆盖。
这是汇编格式,GIMSK是8位寄存器。我们创建了一个位掩码,方法是将1移到要影响的寄存器,然后在要单独保留的位中放入0。 | =表示我们将把保存的两个对象比较回同一个寄存器。而已。 OR 1始终将其打开。这就是我们想要的。
考虑我们要开始做的事情。我们想将布尔值设置为HIGH或TRUE,或1,但是,您将其放置了。我们说“让我们设置您指定的寄存器位是您的值(0/1)还是我的值(1)为1”。好吧,我们知道我们的值是1,因为这就是我们的意思。因此,当您按位进行“或”运算(是动词吗?)时,您正在基于2个值之一(即1)写入值。它要么写入1要么留下1,除非您发送0且发送0它保持关闭。
它说:“我认为应该启用该功能。如果有其他进程认为应该启用该功能,即使我不需要它也可以将其保留(它发送一个0)。”值得在纸上仔细思考,然后思考通过每个操作数。制作一张彩色桌子,这就是我要了解它们的方式。并非所有操作数都会翻转值。 AND为您检查该值,使该寄存器保持不变-在每个reg上进行操作都会有此效果。我曾经有一个备忘单,本来希望包含在内,但我却输了它-但它为我的笨拙的大脑总结了每个操作数的行为。
记住-我们无法对单个位进行操作。这是您需要了解的关键位。您不能只更改一点。如果我有0010 0010,我想说,嘿,计算机,更改字节6。您不能!您必须将整个字或字节加载到寄存器或至少一半的寄存器中(MIPS中为16位,ATMEL 16位控制器中为8位**),然后对整个事物进行操作。您不能直接从内存操作(Ram,SSD,L2 Cacheway距离太远)。尽管有一些技巧可以使您想要的形状成为新的字节(8位),但是没有将单个位弹出到寄存器中以进行更改的事情。只需要第6位,以及{0100 000}
-用AND,将为您得到。然后,您可以向右移动,或除以2 ^ 6,依此类推。我们将回到这一点。首先,如果您想了解更多信息,比较器的操作:
*此芯片为8位。怀疑他们已经读了一半。位
Register(b) Me OR NOR XOR AND NAND N XNOR
1 0 1 0 1 0 1 0 0
0 0 0 1 0 0 1 1 1
1 1 1 0 0 1 0 0 1
0 1 1 0 1 0 1 1 0
因此,以上内容着眼于我们要实现的单个位。左2列是所有可能的情况(仅4列),我们在该字节中显示寄存器的位。 我一直在说字节。正如我通常提到的16或32位那样,一个寄存器实际上就是Word。我刚刚围绕一个假设的8位计算机组织了这个示例。 edit-这是一个8位芯片,32个寄存器。其中之一就是这个
现在!我们想做什么?我们要更改1个字节(代表一个布尔值),但我们不想弄乱其余的字节!如果您对所有8个字节进行“或”操作(在纸上执行此操作),则该值已经单独存在。完善!那就是我们想要的。
无论设置为什么,它们都会保留,如果为1,或者保留为1,如果为0,则保持不变。
啊,我要说为什么。
这是因为您以0000 0001(1)开头,所以除第一个位外,其他所有内容均为0。为什么我们从0000 0001开始?因为你告诉过 请参见语法Arduino Doc Bitwise Ops
因此,在不检查Binary的情况下,binary中的1是0000 0001
,应注意的是,在计算机中,它不能告诉11001100不是11,001,100(1100万)或204(binary) ),甚至是285,217,024(如果是十六进制),或2,359,872(八进制)。
编译器和计算机“知道”我们总是认为以10为底,但计算机却从来没有,只是以2为底或为了便于阅读而将其压缩为八进制(2 ^ 2)或十六进制(2 ^ 4) ),例如,每个“字符”为2位或4位。 0x0A是0b1010。恰恰是我要去的地方。我们指出这些值不是以10为底的前缀。 0b *****是二进制。 0x ****是十六进制。而且我永远不会记得八进制-没人会使用它。
所以!
如果需要,请参见此处:Another practical book I wrote on Bitwise Ops, that covers basic Binary a little. 然后您将其移位 PIN NUMBER 我不知道正确的术语,当然不是这样,但是您说要影响的寄存器是第五寄存器。好。
#take a 1,
0000 0001 = $temp
#shift it 5 spots "<<" , where 5 is the PCIE 'bit' value spot number.
1<<5 = 32
#binary equals 32.
您可以将GIMSK值替换为32,也可以,或者再次等于0x020
# 0010 0000
# Then OR this with whats in the register now:
1010 1010 (made up number, a mix of ones and 0s)
0010 0000 (Our Value)
OR=>
1010 1010 Result.
请注意,我们如何让其他位保持不变,只改变了我们想要的!有效位掩码!
现在,为什么要说PCIE,以及其他含义。这是因为在编译时的某个地方,有一个文件为这些变量分配值。这使代码可以在几种不同的芯片设计中兼容。 ATMEGA和ATTINY没有相同的中断引脚。尽管它可能会到达相同的内部寄存器。
#Take it bit by bit, no Pun intended
GIMSK |= (1 << PCIE);
PCMSK |= (1 << PCINT4);
GIMSK = 0b00100000;
PCMSK = 0b00010000;
再次从上方的第一位开始。
GIMSK- some variable
|= - bitwise OR
1 - the integer 1
`<`< - shift operation
PCIE - another var
因此,您要做的就是使用一个以10为底的整数-1,我们知道它等于0b0000 0001,然后将其推入1(现在以二进制形式显示到PCIE或PCINT4指示的位置。因此,后者2只是简单的包含位数的变量,因此,如果它发生变化,则代码不会中断。
从后两行可以推断出PCIE为5,PCINT4为4。GIMSK现在等于32,其他等于16。移位<<和>>具有乘或除2的效果。下降是有风险的,原因是我不愿讨论,但是如果您需要将数字乘以2,对于一台计算机,向左移1位要比通过多人游戏快得多。
我们已经讨论过OR。如果没有,则将其设置为1,否则将其他位保留为零,因为它们为0。
GIMSK | =(1 << PCIE);
GIMSK = 0b00100000;
GIMSK = GIMSK OR 0b00100000
PCMSK | =(1 << PCINT4);
PCMSK = 0b00010000;
PCMSK = PCMSK OR 0b00010000
因此,评估每个集合中的第一个表达式将得到第三个方程。但是请注意,它们看起来有些不同。但是,正如您所说的那样,它们不是等效的语句。这取决于其他那些位。
PCMSK = 0b00010000; #This sets the PCMSK register to be exactly
=> PCMSK = `0|0|0|1|0|0|0|0
#While
PCMSK = PCMSK OR 0b00010000; # yields PCMSK = `?|?|?|1|?|?|?|?`
#Obviously,
GIMSK = 0b00001000; # This sets the GIMSK register to be exactly
=> GIMSK = `0|0|0|0|1|0|0|0`
While`GIMSK = GIMSK OR 0b00001000; # yields
GIMSK = ` ?|?|?|?|1|?|?|? `
而OR语句则将其他位保留下来(如果它们是由其他方式设置的),并视情况更改5(或第4位)。 OR语句可能是更好的语句。但是,如果您发现后一个声明在一个有信誉的地方被建议,那可能还不错。
就这样。现在,不同的位有意义,这比您现在想像的要容易得多。我写了这篇文章,但希望它能提供一些持久的见识,而不仅仅是一个快速的答案。尽管实际上-这很复杂。在这两个陈述中埋藏着许多计算机科学概念,如果您不了解,那么它们可能也是象形文字。
如果您深入研究计算机的工作原理,那么所有这些都将更为有意义。
查阅《计算机组织和设计》(第5版)Patterson and Hennesy的第2章和第3章。这是标准。如果这很有趣,则可以略读。但是计算机已注册了定义的宽度-8、16、32和64或什至128(很少见,例如x86 AVX- Intel x86)。但通常是32位这些是处理器实际接触的手头的数据位。处理器只能在寄存器上运行。因此,引擎盖下的所有内容都将返回到那里。
现在正确使用中断是另一个主题。我再次推荐同一本书-第5章和附录A7
注:我的汇编类在MIPS中。我从未专门研究过该微控制器。如果我弄错了某些架构,请原谅我。