문제

내가 사용하고 마이크로 컨트롤러 C51 핵심입니다.나는 공정하게 일정하지 않고 시간이 많이 소요되는 큰 서브루틴 호출되어야 하는 모든 500ms.는 RTOS 은 사용되지 않습니다.

방법 나는 그것을 하고 있는 지금 나가는 기존 타이머를 인터럽트 10ms.나는 플래그를 설정 후에는 모든 50 개의 인터럽트는 체크에 대한 진실에서 주요 프로그램이다.는 경우 이 플래그가 진정한 서브 루틴이라고합니다.문제는 시간에 의해 프로그램 loop 온운 서비스 플래그,그것은 이미 이상 500ms,때로는 심지어>515ms 의 경우에는 특정 코드의 경로입니다.데 걸리는 시간은 정확하게 예측할 수 있습니다.

물론,서브루틴 호출할 수 없습니다 안에서 타이머는 인터럽트 인에는 큰 걸리는 시간을 실행합니다.서브루틴 걸리는 50ms 을 89ms 에 따라 다양한 조건입니다.

하는 방법이 있는지 확인 루틴이라고 정확히 500ms 각 시간입니까?

도움이 되었습니까?

해결책

이것이 필요한 것을할까요?

#define FUDGE_MARGIN 2    //In 10ms increments

volatile unsigned int ticks = 0;

void timer_10ms_interrupt( void )  { ticks++; }

void mainloop( void )
{
    unsigned int next_time = ticks+50;

    while( 1 )
    {
        do_mainloopy_stuff();

        if( ticks >= next_time-FUDGE_MARGIN )
        {
            while( ticks < next_time );
            do_500ms_thingy();
            next_time += 50;
        }
    }
}

NB : 500ms의 모든 작업을 서비스하는 데 뒤처진 경우,이를 대기열으로 이끌어 낼 수 있습니다.

다른 팁

나는 당신이 여기에 상충/생각하지 않는 요구 사항이 있다고 생각합니다. 당신은 타이머 ISR 에서이 코드를 호출 할 수 없다고 말합니다 (실행하는 데 너무 오래 걸리기 때문에 (지연 될 다른 것보다 우선 순위가 낮다는 것을 암시하지만), 당신은 무언가가 무언가에 부딪 히고 있습니다. 우선 순위가 낮아야했던 그렇지 않으면 전경 경로 ( '프로그램 루프')에서 실행할 때 지연됩니다.

이 일이 작동한다면 ~ 해야 하다 정확히 500ms에서 발생한 다음 타이머 루틴에서 실행하고 그로부터 낙진을 처리하십시오. 이것은 효과적으로 선제 적 RTO가 어쨌든 할 일입니다.

'프로그램 루프'에서 실행되기를 원한다면 해당 루프에서 실행되는 다른 것보다 견딜 수있는 최대 지연보다 더 많은 것을 취해야합니다. 루프를 통과하는 패스 당 약간의 작업을 수행 할 수있는 상태 대기업.

나는 그것을 보장 할 방법이 없다고 생각하지만이 솔루션은 수용 가능한 대안을 제공 할 수 있습니다.

제안 할 수 있습니다 ~ 아니다 깃발을 설정하고 대신 값을 수정 하시겠습니까?

작동하는 방법은 다음과 같습니다.

1/ 0에서 값을 시작하십시오.

2/ 10ms 인터럽트마다 ISR 에서이 값을 10 씩 증가시킵니다 (인터럽트 서비스 루틴).

3/ 메인 루프에서 값이> = 500 인 경우 값에서 500을 빼고 500ms 활동을 수행하십시오.

값을 수정할 때 타이머와 메인 프로그램 사이의 레이스 조건을주의해야합니다.

이는 대기 시간 또는 지속 시간에 관계없이 함수가 500ms 경계에 최대한 가깝게 실행된다는 이점이 있습니다.

어떤 이유로 든 한 반복에서 기능이 20ms 늦게 시작되면 값은 이미 520이므로 기능이 20으로 설정되므로 다음 반복 전에 480ms 만 기다립니다.

그것은 당신이 원하는 것을 성취하는 가장 좋은 방법 인 것 같습니다.

나는 수년간 8051을 만지지 않았지만 (C51이 당신의 설명을 감안할 때 안전한 내기로 보이는 C51이 목표라고 가정 할 때) 인터럽트가 가능하지 않고 50을 빼는 지침이있을 수 있습니다. 그러나 아키텍처가 매우 간단하다는 것을 기억하는 것 같습니다. 하중/수정/저장 작업을 수행하는 동안 인터럽트를 비활성화하거나 지연시켜야 할 수도 있습니다.

volatile int xtime = 0;
void isr_10ms(void)  {
    xtime += 10;
}
void loop(void) {
    while (1) {
        /* Do all your regular main stuff here. */
        if (xtime >= 500) {
            xtime -= 500;
            /* Do your 500ms activity here */
        }
    }
}

"사전 액션"플래그와 "트리거"플래그 (Mike F를 시작점으로 사용)라는 두 개의 플래그를 사용할 수도 있습니다.

#define PREACTION_HOLD_TICKS (2)
#define TOTAL_WAIT_TICKS (10)

volatile unsigned char pre_action_flag;
volatile unsigned char trigger_flag;

static isr_ticks;
interrupt void timer0_isr (void) {
   isr_ticks--;
   if (!isr_ticks) {
      isr_ticks=TOTAL_WAIT_TICKS;
      trigger_flag=1;
   } else {
      if (isr_ticks==PREACTION_HOLD_TICKS)
          preaction_flag=1;
   }
}

// ...

int main(...) {


isr_ticks = TOTAL_WAIT_TICKS;
preaction_flag = 0;
tigger_flag = 0;
// ...

   while (1) {
      if (preaction_flag) {
          preaction_flag=0;
          while(!trigger_flag)
             ;
          trigger_flag=0;
          service_routine();
      } else {
          main_processing_routines();
      }
   }
 }

좋은 선택은 RTO를 사용하거나 간단한 RTO를 작성하는 것입니다.

귀하의 요구를 충족시키기위한 RTO는 다음을 수행하면됩니다.

  • 정기적 인 작업을 예약하십시오
  • 라운드 로빈 작업을 예약하십시오
  • 컨텍스트 전환 사전 형식

귀하의 요구 사항은 다음과 같습니다.

  • 500ms마다 정기적 인 작업을 실행하십시오
  • Round Robin 작업 실행 사이의 여분의 시간 (시간 비 치명적 운영 수행)

이와 같은 RTO는 코드가 제 시간에 실행될 99.9%의 확률을 보장합니다. ISR에서 수행하는 작업이 RTO를 방해 할 수 있기 때문에 100% 말할 수 없습니다. 이것은 한 번에 하나의 명령을 실행할 수있는 8 비트 마이크로 컨트롤러의 문제입니다.

RTO를 작성하는 것은 까다 롭지 만 가능합니다. 다음은 Atmel의 8 비트 AVR 플랫폼을 대상으로하는 작은 (900 라인) RTO의 예입니다.

다음은 보고 및 코드 클래스 CSC 460 용으로 만들어졌습니다 : 실시간 운영 체제 (빅토리아 대학교).

간단한 솔루션 중 하나는 500ms에서 발사되는 타이머 인터럽트를 갖는 것입니다.
하드웨어 설계에 약간의 유연성이 있다면 한 타이머의 출력을 두 번째 단계 카운터에서 캐스케이드하여 오랜 기간을 확보 할 수 있습니다. 나는 잊어 버렸지 만 X51에서 계단식 타이머를 할 수 있다는 것을 모호하게 기억합니다.

아, 고려를위한 또 하나의 대안 - X51 아키텍처는 두 가지 수준의 인터럽트 우선 순위를 허용합니다. 하드웨어 유연성이 있으면 타이머 ISR에 의해 외부 인터럽트 핀 중 하나를 500ms 간격으로 올릴 수 있으며, 모든 500ms 코드의 하위 수준 인터럽트 처리가 발생할 수 있습니다.

특정 X51에 따라 장치 내부에 완전히 우선 순위가 낮은 인터럽트를 생성 할 수도 있습니다.

웹에서 찾은이 문서에서 11.2 부를 참조하십시오. http://www.esacademy.com/automation/docs/c51primer/c11.htm

왜 실행하는 데 시간이 오래 걸리는 시간이 걸리는 이유는 무엇입니까?

나는 여기에 건축 문제가있을 수 있다는 것에 동의합니다.

정확한 500ms (또는 무엇이든) 간격을 갖는 목적이 특정 시간 간격으로 신호 변경이 발생하는 경우, 이전 계산을 기반으로 새 신호를 제공하는 빠른 ISR로 더 나을 수 있습니다. 새로운 계산이 ISR 외부에서 실행됩니다.

이 장기 실행 루틴이 무엇을하고 있는지, 특정 간격에 대한 필요성이 무엇인지 더 잘 설명 할 수 있습니까?


의견을 바탕으로 추가 :

서비스 루틴의 시간이 예측 가능한 기간임을 보장 할 수 있다면 타이머 인터럽트 게시물이 누락 된 상태에서 벗어날 수 있습니다 ...

예를 들어, 타이머 인터럽트가 10ms 기간으로 설정되어 있고 서비스 루틴이 89ms가 걸릴 것이라는 것을 알고 있다면 41 개의 타이머 인터럽트를 계산 한 다음 89ms 활동을 수행하고 8 개의 타이머 인터럽트를 놓치십시오 (42 번째 ~ 42 번 49 일).

그런 다음 ISR이 종료 될 때 (그리고 보류중인 인터럽트를 지울 때) 다음 500ms 라운드의 "첫 번째"인터럽트는 나중에 MS에 대해 발생합니다.

"자원 최대"가 있다는 점을 감안할 때 다른 타이머와 인터럽트 소스도 사용하고 있음을 시사합니다. 이는 다른 인터럽트 소스가 발사 될 수 있기 때문에 메인 루프에 정확하게 의존하는 것이 작동하지 않을 것임을 의미합니다. 잘못된 순간에.

면 나는 interpretting 당신의 질문을 제대로,당신은:

  • 메인 루프
  • 일부는 우선 순위가 높은 작업을 실행해야하는 모든 500ms,한 기간까지 89ms
  • 10ms 타이머는 수행한 작은 수의 작업입니다.

세 가지 옵션이 있습니다 내가 그것을 참조하십시오.첫 번째는 사용하는 두 번째 타이머의 낮은 우선순위에 대한 귀하의 500ms 작업입니다.할 수 있습 프로세스의 10ms 인터럽트 및 완료되면 계속한 서비스 500ms 타이머를 인터럽트.

두 번째 옵션-doe 실제 필요한 서비스 10ms 인터럽트의 모든 10ms?그것은 아무것도 다른 것보다 시간 유지?지 않은 경우,하드웨어를 허용,당신의 수를 결정하 10ms 틱 전달을 처리하는 동안 당신의 500ms op s(ie.여 사용하지 않는 인터럽트를 스스로)다음 시작할 수 있습니다 당신의 500ms op 의 내 10ms 인터럽트 처 10ms 틱는 당신이 놓칠 때 당신은 끝났어.

세 번째 옵션:따라서 저스틴 Tanner 의 답변,그것은 당신 같은 소리를 생산할 수 있는 자신의 선제 멀티태스킹 커널을 채우기 위해 요구 사항없이 너무 많은 문제입니다.그것은 소리처럼 당신이 필요로하는 모든 두 가지 작업을 중 하나에 대한 기본 슈퍼 루프에 관한 것이고 다른 하나는 500ms 작업입니다.

코드 교환 사이에 두 개의 컨텍스트(ie.두 가지의 모든 복사본의 레지스터를 사용하여 다른 스택은 포인)은 매우 간단하며,일반적으로 이루어져 있는 시리즈의 푸시 등록(을 저장하는 현재의 컨텍스트),시리즈의 등록 나타납(을 복원하는 새로운 맥락)에서 인터럽트 명령입니다.면 500ms op 의 완료되면,당신은 원래 context.

(나는 엄격 하이브리드의 선점 및 협력 멀티태스킹이지만,그 중요하지 않다가 지금)


편집:거기에 간단한 네 번째 옵션입니다.자유롭게 고추의 기본 슈퍼와 루프를 확인할지 여부를 500ms 이 경과하기 전과 후의 모든 긴 작업입니다.지 정확히 500ms,하지만 당신을 줄일 수 있습니다 대기 시간을 허용 수준입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top