我尝试制作一个简单的电路,每隔30秒切换一次LED。定时器/计数器中断标志寄存器(TIFR)是一个8位寄存器,具有以下规范:
请注意,这是一个典型的AVR芯片,与此问题无关。发生定时器溢出时,TOV0位将由硬件置1。这让我知道计时器的状态。然后我将通过向TIFR寄存器写入逻辑1来清除它。这是代码:
#include <avr/io.h>
#define LED PB0
int main(void)
{
uint16_t timerOverflowCount=0;
DDRB=0xff; //configure PORTD as output
TCNT0=0x00; //set counter to 0
TCCR0B=(1<<CS00) | (1<<CS02);
while(1)
{
while ((TIFR & 0x01) == 0);
TCNT0 = 0x00;
TIFR=0x01;
timerOverflowCount++;
if (timerOverflowCount>=919)
{
PORTB ^= (0x01 << LED);
timerOverflowCount=0;
}
}
}
我对此代码的理解是第二个while
的条件检查:
while ((TIFR & 0x01) == 0);
显然,看起来循环会导致延迟,直到发生计数器溢出。然后控件转到下一个语句。
我不是一位经验丰富的C用户,所以我不明白&
语句检查while
语句中的&
操作数。我的理解是在C &
中是一个运算符地址,它找到一个典型对象的地址。我不确定ArrayList<Project> projects=new ArrayList<>();
运算符的含义。
答案 0 :(得分:4)
这是一个按位AND。在这里,它用于过滤除最后一位之外的所有内容:
nnnnnnnn
00000001 (0x01)
-------- &
0000000n
这意味着只要最右边的位不设置,while ((n & 0x01) == 0)
就会循环。
答案 1 :(得分:0)
&
是按位和运算符:当且仅当TIFR & 1
的最低有效位为1
时,表达式TIFR
才会计算为1
。< / p>
完整语句while ((TIFR & 0x01) == 0);
称为忙循环:只要失败,它就会重复测试。 while
循环的主体是空语句;
。应将TIFR
定义为一个表达式,该表达式返回最终将其低位设置的某个硬件寄存器的值,通常是内存映射硬件寄存器的volatile
限定地址。
程序将以100%CPU运行,耗尽电池,等待此值更改,因此表达式忙等待。使用nanosleep()
函数调用在此循环体中有效等待可能会更好。
答案 2 :(得分:0)
&
运算符有一些用途。在这种情况下,它对两个数据进行操作。这与AND门非常相似。如果两个输入均为1,则输出1,否则输出0。
在您的示例中,我们使用&
运算符来获取某个位的状态:
nnnnnnnn
00000001
-------- &
0000000n
一个例子:说nnnnnnnn的值是00001011.我们只想要最后一位的状态,所以我们用{00}保证&
这个值。因为如果输入是逻辑AND操作,它将只输出1当且仅当最后一位为1时,1 {,&
我们的值与00000001将输出00000001。
在C中,&
运算符也可以在指针前面使用,表示你想要指针的值,而不是指针包含的值(与*
一起使用的值)这两个语法不同。
0xNN & 0xKK /* Logical AND */
uint32_t valueOfPointer = &ptr; /* Value of pointer */
答案 3 :(得分:0)
如果你查看一个C运算符优先级图表,例如C Operator Precedence,你会注意到有几个符号,&
就是其中之一,这意味着不同的东西取决于符号出现在上下文中。
在某些情况下,为了创建一个操作符,例如+=
或<<
,可以组合多个符号,这样我就能理解为什么你可能会遇到一些混乱。
使用while
语句,C编译器将查看括号之间的内容,并尽力将其转换为表达true
的语句(由非零表示)值虽然显式布尔语句将返回值为1)或false
(由值0表示)。
因此语句while ((TIFR & 0x01) == 0);
是一个while
循环,它具有条件但没有实际正文。结果是该循环将继续循环,直到条件从非零(true
)变为零(false
)。当寄存器的最低有效位变为1并且寄存器和0x01的值之间的按位和变为非零时,将满足该条件。
C编译器在此上下文中使用符号&符号(&
)作为按位And运算符。那么机器代码生成的是用TIFR代表的值来执行按位和十六进制常量1。
在您的情况下,TIFR代表定时器/计数器中断标志寄存器,因此条件正在执行与寄存器的按位和0x01。我假设寄存器的低位,即图中的TOV0位,将被设置为零或关闭,直到发生某些外部事件,然后将该位设置为1或接通。当这种情况发生时,按位并且计算结果为非零,并且逻辑相等性在退出循环时失败。
只要TOV0位按位关闭,并且使用0x01将导致零值,while()
然后将其与零值进行比较。一旦该位设置为1或on,则按位And将导致非零值while()
与零比较,此时循环将退出,因为比较失败。
一元与二元&
运算符
单个&符号(&
)的基本规则是当它是一元运算符时,它被视为Address Of运算符。当它被视为二元运算符时,它被视为按位运算符。
如果它与&=
中的一个赋值运算符变体一起使用,那么它被视为评估右侧然后获取该值并按位运算与运算符左侧的内容相同并将结果值分配给左侧变量。
一些例子。
int myInt = 1;
int *pInt = &myInt; // unary operator so this is the Address Of use
int myInt2 = myInt & 3; // binary operator so this is the bitwise And use
int aInt[] = {1,3,2,4,5,7,8};
int *pLast = &aInt[sizeof(aInt)/sizeof(aInt[0]) - 1]; // unary operator so Address Of use
while (pLast >= &aInt[0] && ! (*pLast & 0x01)) pLast--;
if (pLast >= aInt) {
*pLast &= ~0x01; // clear the least significant bit of value pointed to
}
请注意,在while语句中,我们使用&符号作为Address Of运算符和按位And运算符。另外,我们使用两个&符号&&
作为逻辑And运算符。我们还在&=
语句的主体中使用了按位和赋值运算符if
(并且在一个符号和下一个符号之间不能有任何空格,因此&=
是有效,但& =
不是。)
这个循环的作用是从末尾遍历数组,直到找到奇数编号的值,这个值确实设置了最低有效位。如果找到这样的值,那么我们使用按位和分配关闭最低有效位。