2013-05-26 2 views
2

나는 Arduino를 함수가 실행될 때마다 1 초 동안 잠자기 상태로 만들려고 노력하고있다.Arduino millis 기능이 예상보다 오래 걸림.

루프와 관련된 메서드는 실행 시간이 다를 수 있으므로 밀리 초를 구현 한 것입니다.

내가하고 있어요 다음

unsigned long ejecucionExcedida = 0; 

int calcularExceso(int tiempo) { 
    if (tiempo>1000) { 
     ejecucionExcedida = ejecucionExcedida + (tiempo-1000); 
     // TO DO agregar alarma si el exceso se incrementa mucho 
     if(ejecucionExcedida > 20000) { 
      alertas(9); 
     } 
     // Listo las alertas :D 
     return 1000; 
    } 
    else { 
     if(ejecucionExcedida == 0) { 
      return tiempo; 
     } 
     else { 
      if (ejecucionExcedida + tiempo < 1000) { 
       ejecucionExcedida = 0; 
       return ejecucionExcedida + tiempo; 
      } 
      else { 
       int exceso = ejecucionExcedida + tiempo - 1000; 
       ejecucionExcedida = exceso; 
       return 1000; 
      } 
     } 
    } 
} 

void loop() { 
    unsigned long comienzo = millis(); 

    // A couple of methods 

    unsigned long final = millis(); 

    delay(calcularExceso(final-comienzo)); 
} 

스케치는 각 실행에 정확히 하나의 초 지연 될 것으로 예상된다,하지만 난 시계와 그것을 초과하고 그것이 초당 실행보다 더 오래 복용 .

답변

5

루프 기능을 설명하지 않습니다.

void loop() { 
// B 

    unsigned long comienzo = millis(); 

    // a couple of methods 

    unsigned long final = millis(); 
// C 
    delay(calcularExceso(final-comienzo)); 
// A 
} 

귀하는 A에서 B까지 사용 된 시간을 고려하지 않았습니다. 측정과 지연 (C) 사이에 사용 된 시간도 고려하지 않았습니다.

가장 큰 원인은 A에서 B입니다. arduino/hardware/arduino/cores/arduino를 보면 main.cpp가 있습니다. 이 파일을 살펴보면 왜 이것이 오래 걸리는 지 명확 해집니다.

#include <Arduino.h> 

int main(void) 
{ 
     init(); 

#if defined(USBCON) 
     USB.attach(); 
#endif 

     setup(); 

     for (;;) { 
       loop(); 
       if (serialEventRun) serialEventRun(); 
     } 

     return 0; 
} 

사실 "단순한 것"이상입니다.

나는이 변수가 정적 시작 선언 코드와는 달리이

void loop() { 
    static unsigned long start = millis(); 

    // a couple of methods 

    while (millis() - start < 1000) { 
     // busy wating 
    } 
    // do NOT read again as this would cummulate the drift 
    // instead add just one second to start 
    start += 1000; 
} 

을 보상하기 위해 다음과 같은 접근 방식으로 전환하는 것이 좋습니다. 이것은 loop()의 첫 번째 통과 중에 start가 millis()에서 초기화된다는 것을 의미합니다. loop()의 각 패스 후에 그 값은 loop()의 다음 패스를 위해 유지됩니다. 후속 패스 중에는 더 이상 초기화되지 않습니다. 따라서 첫 번째 패스에서 start는 임의의 동시 값 (예 : 42)을 가질 수 있습니다. 마지막 1 초는 millis()가 1042에 도달 할 때까지 기다리고 1 초 런타임에 합계됩니다. 그러면 시작은 1000 씩 증가합니다. 따라서 두 번째 단계에서 1042가되고 마지막 단계는 millis()가 2042에 도달 할 때까지 기다립니다. 세 번째 단계에서 시작은 2042가되고 마지막 단계는 millis()가 도달 할 때까지 기다립니다. 3042 등등. 마지막으로 볼 수 있듯이 항상 1000ms 간격으로 배치됩니다. 따라서 serial()의 처리로 인해 발생할 수있는 지터를 제외하고는 loop()의 시작 간격이 평균 1000 ms가됩니다.

이 변경 후에도 여전히 많은 드리프트가 발생하면 코드에 인터럽트를 오래 동안 차단하는 것이 있습니다. Arduino의 시간은 인터럽트로 유지되므로 오래도록 차단해서는 안됩니다. 불행히도 인터럽트를 부작용으로 차단할 수있는 함수가 있습니다. 이 문제의 원인이되는 부분을 찾으려면 코드 조각을 제거해야합니다. 일반적으로 일부 LED를 추가하고 패스 당 한 번 상태를 전환하는 것이 좋습니다.

결국 결국 Arduino 모델에 따라 약간의 드리프트가 발생합니다. 구형 모델은 약 10ppm (일 초당 몇 초) 동안 표류하는 수정 시계를 가지고 있습니다. 최신 모델은 종종 수천 ppm (시간당 몇 초) 정도 표류 할 수있는 수정 공진기 (저렴한)를 사용합니다. 이 기사를 Arduino crystal deviation

0

코드는 실행 시간이 필요하지만 당신은 문제를 일으키는 코드와 함께 그

+0

안녕하세요 Eric!무엇보다도 먼저 응답 해 주셔서 감사합니다. 코드를 실행하는 데 시간이 필요하다는 것을 고려해야합니다. 코드 밀리 (코드) 맨 위와 코드 맨 아래에 다시 놓은 이유는 무엇입니까? 그 사이에 알고리즘을 실행하는 데 많은 시간이 걸렸습니다. 그 결과로 나는 calcularExceso() 함수를 호출하여 차이가 1000보다 작 으면 1000을 슬립합니다. 그러나 더 많은 경우 초과를 저장합니다. –

+0

하지만 delay()는 실행하는 데 시간이 걸리며 millis() 함수에도 시간이 걸립니다. – Eric

+0

기대하는 것과 표시되는 것의 차이가 얼마나 큰지, 지연을 측정하는 방법과 arduino 프로세서가 얼마나 빠릅니까? – Eric