C 代码中的其他部分是什么意思?

C 代码中的其他部分是什么意思?,c,arm,embedded,C,Arm,Embedded,我在浏览一些嵌入式编程链接 [请注意,上述链接中代码的作者已经更新了代码,本文中的delay_ms()实现不再使用下面所示的解决方案。] 并以下面的代码结束。这是针对ARM架构的,但基本上这是一个函数,它会导致作为参数传递的特定毫秒的延迟。所以我可以理解if条件,但为什么这里需要else条件?谁能给我解释一下吗 void delay_ms (uint32_t t) { uint32_t start, end; start = millis();//This millis functio

我在浏览一些嵌入式编程链接

[请注意,上述链接中代码的作者已经更新了代码,本文中的
delay_ms()
实现不再使用下面所示的解决方案。]

并以下面的代码结束。这是针对ARM架构的,但基本上这是一个函数,它会导致作为参数传递的特定毫秒的延迟。所以我可以理解if条件,但为什么这里需要else条件?谁能给我解释一下吗

void delay_ms (uint32_t t)
{
  uint32_t start, end;
  start = millis();//This millis function will return the system clock in 
                   //milliseconds
  end = start + t;
  if (start < end) {
     while ((millis() >= start) && (millis() < end))
     { // do nothing } 
  }
 else{
     while ((millis() >= start) || (millis() < end)) 
     {
      // do nothing
    };
  }
}
void delay\u ms(uint32\t)
{
uint32_t开始、结束;
start=millis();//此millis函数将返回系统时钟
//毫秒
结束=开始+t;
如果(开始<结束){
而((毫秒()>=开始)和(&(毫秒()<结束))
{//什么也不做}
}
否则{
while((毫秒()>=start)| |(毫秒()
请注意,第二个while循环是
|
而不是
&&
。这是为了处理溢出。如果
start+t
的数值大于
end
所能容纳的数值,会发生什么情况?答案是你会得到一个溢出。将1添加到保留其最大值的无符号整数时,它将溢出为0

下面是一个简短的片段,显示溢出的影响:

uint8_t c = 255;
uint8_t d = c+1;
printf("%d %d", c, d);
这将打印
255 0

在这种情况下,这种溢出甚至不是不可能发生的情况。
uint32\t
可容纳的最大值约为4*10⁹. 这是46天内经过的毫秒数

下面是一段代码片段,您可以自己测试它:

#include <stdio.h>
#include <stdint.h>
int main()
{
uint32_t s = -2; // Initialize s to it's maximum number
                 // minus one via overflow
uint32_t e, t;
    scanf("%d", &t);
    e = s+t;
    if(s<e) 
        printf("foo\n");
    else
        printf("bar\n");
}

然而,代码很糟糕。有关原因的解释,请参见。

如果
start+t
导致溢出,
end
将小于
start
,因此
If
部分处理该问题,而
else
部分处理“正常”情况

老实说,这需要一些思考来确定它是否真的是正确的,但它几乎不值得,因为它是一种解决简单问题的有点过于复杂的方法。所需要的只是以下几点:

void delay_ms( uint32_t t )
{
    uint32_t start = millis() ;

    while( (uint32_t)millis() - start < t )
    { 
        // do nothing 
    } 
}
void delay\u ms(uint32\t)
{
uint32_t start=millis();
而((uint32_t)millis()-start
要了解其工作原理,请想象
start
0xffffff
t
0x00000002
,两毫秒后,
millis()
将是
0x00000001
millis()-start
将是
2


millis()-start==3
时,循环将终止。可以说,您可能更喜欢
millis()-start此代码试图处理滚动。取一个8位计数器/计时器进行计数,比如从0x00到0xFF,然后再次滚动到0x00。如果我想使用此计时器等待16个计时器刻度(0x10)(使用轮询),并且当我启动该延迟时,计时器处于0x1B,那么我想等待0x1B+0x10=0x2B。
Start=0x1B,end=0x2B,对于我们想要延迟的值0x1B,0x1C 0x1D…0x29,0x2A,Start小于end,因此只要t不大于我们基于此代码假设的计时器,此代码中就没有计数器滚动,因此:

while((now>=start)&&(now<end)) continue;
工作完美,我们只需要现在减去-开始一个向上计数器,并掩盖数学到计数器和/或变量的大小,以较小者为准

while((现在开始)&0xFF) 对于下行计数器,请使用“立即开始”

代码的作者试图在不理解两个补码的情况下处理翻滚。早在我学会这一点的前一天,我的代码就更糟糕了,我可能是在计算翻滚前的计数数,然后是翻滚后的计数数,不管发生什么,我都相信翻滚数学是有效的只要你把它掩饰好

那么说

如果您的计时器没有在“全1”到“全0”或“全0”到“全1”之间滚动,这是许多微控制器计时器可以编程实现的,并且您没有完全使用计时器功能,那么上述功能将不起作用。如果您有一个8位计时器,它从0x00计数到0x53,然后滚动到0x00,因为这是设置“全1”的方式出于某种原因,或者您正在使用为周期性中断设置的计时器作为轮询计时器,那么您必须以更好的方式执行该代码的作者所做的操作:

而(现在)继续

现在对每个循环进行采样

但是end的数学不是自然滚动的,你必须将end计算为

end = start + t; 
if(end>0x53) end = end - 0x54;
在这种情况下,尽管人们可能会想,为什么要使用这样的计时器来进行轮询超时,但使用一个对所有位进行计数并对轮询超时进行滚动的计时器,使用一个对常规周期性中断计数为N或从N计数为零的计时器,或者也可以对这些中断进行轮询,但在这种情况下,您不需要进行常规延迟嗯……你可以……将计时器设置为一毫秒,然后计算滚动标志,直到到达t。比现在开始的数学更容易。并且可以计算到你想要的高度

Millis()在您和计时器之间放置了一个抽象层,我们假设Millis从全1滚动到全0

例如,如果您有一个从0x00000000计数到0x555555的计时器,并且该计时器会滚动,那么您也无法对其进行剪裁,以使该数学运算正常进行

while(((start-now)&0xFFFF)<t) continue;
出于同样的原因,您不必返回并再次读取寄存器,以查看这是否是循环中断的原因。取决于该寄存器

是的,有些人可能讨厌这里的编码风格,如果你重复使用那个时间戳不止一次,那么你也可以把你的定时器的采样次数减少到最小,在你写的代码的情况下,C应该被评估为左到右

millis() >= start
then
millis() < end
millis()>=开始
然后
米利斯()
是不是写好了

 while ((millis() < end) && (millis() >= start))
 while ((millis() < end) || (millis() >= start)) 
while
while((timer()-start)<timeout)
{
    if(read_register(n)&0x10) break;
}
if((timer()-start)>=timeout)
{
   printf("Timed out\n");
   return 1;
} 
return 0;
while(1)
{
   delta=timer()-start;
   if(delta>t) break;
   if(register_read(n)&0x10) break;
}
if(delta>t) 
{
   printf(...
   return 1;
}
return 0;
millis() >= start
then
millis() < end
 while ((millis() < end) && (millis() >= start))
 while ((millis() < end) || (millis() >= start)) 
if(start<end)
{
   while(millis()<end) continue;
}
else
{
   while(millis()>=start) continue;
   while(millis()<end) continue;
}