타이머를 사용하여 시간을 유지하면 임베디드 마이크로 컨트롤러가 포함됩니다

StackOverflow https://stackoverflow.com/questions/892661

문제

이 질문은 OS가없는 작은 마이크로 컨트롤러를 프로그래밍하는 것입니다. 특히, 나는 현재 사진에 관심이 있지만 질문은 일반적입니다.

시간을 유지하기위한 다음 패턴을 여러 번 보았습니다.

타이머 인터럽트 코드 (매 초마다 타이머가 발사) :

...
if (sec_counter > 0)
  sec_counter--;
...

메인 라인 코드 (무기력) :

sec_counter = 500; // 500 seconds

while (sec_counter)
{
  // .. do stuff
}

메인 라인 코드는 반복 될 수 있으며 카운터를 다양한 값 (초뿐만 아니라) 등으로 설정할 수 있습니다.

이 과제가 여기에 인종 조건이있는 것 같습니다. sec_counter 메인 라인 코드에서는 원자가가 아닙니다. 예를 들어, PIC18에서 할당은 4 개의 ASM 문으로 변환됩니다 (시간에 각 바이트를로드하고 그 전에 메모리 뱅크에서 오른쪽 바이트를 선택). 인터럽트 코드 가이 중간에 오면 최종 값이 손상 될 수 있습니다.

흥미롭게도 지정된 값이 256 미만인 경우 과제는 ~이다 원자, 따라서 문제가 없습니다.

이 문제에 대해 옳습니까? 이러한 동작을 올바르게 구현하기 위해 어떤 패턴을 사용합니까? 몇 가지 옵션이 있습니다.

  • SEC_COUNTER에 각 할당하기 전에 인터럽트를 비활성화하고 이후에 활성화합니다.
  • 인터럽트를 사용하지 말고 시작한 다음 투표 한 별도의 타이머를 사용하십시오. 이것은 깨끗하지만 전체 타이머를 사용합니다 (이전의 경우 1- sec 발사 타이머도 다른 목적으로도 사용할 수 있습니다).

다른 아이디어가 있습니까?

도움이 되었습니까?

해결책

PIC 아키텍처는 원자가 된 것만 큼 원자입니다. 메모리 파일에 대한 모든 read-modify-write 작업이 '원자'임을 보장합니다. 전체 읽기 모형 쓰기를 수행하는 데 4 개의 클록이 필요하지만 모든 4 개의 클록은 단일 명령으로 소비되며 다음 명령어는 다음 4- 클록주기를 사용합니다. 파이프 라인이 작동하는 방식입니다. 8 클록에서는 파이프 라인에 두 가지 지침이 있습니다.

값이 8 비트보다 큰 경우 그림이 8 비트 기계이고 더 큰 오페라는 여러 지침으로 처리되므로 문제가됩니다. 원자 문제가 발생합니다.

다른 팁

값을 작성한 다음 필요한 값이 가장 간단한 대안 인 것 같다는 점을 확인하십시오.

do {
 sec_counter = value;
} while (sec_counter != value);

BTW C를 사용하는 경우 변수 변동성을 만들어야합니다.

값을 읽어야한다면 값을 두 번 읽을 수 있습니다.

do {
    value = sec_counter;
} while (value != sec_counter);

카운터를 설정하기 전에 인터럽트를 비활성화해야합니다. 못 생겼을 수도 있습니다. ISR 메소드에 영향을 미치는 하드웨어 레지스터 또는 소프트웨어 변수를 구성하기 전에 항상 인터럽트를 비활성화하는 것이 좋습니다. C로 작성하는 경우 모든 작업을 비 원자로 간주해야합니다. 생성 된 어셈블리를 너무 많이 살펴 봐야한다는 것을 알게되면 C와 프로그램을 어셈블리에 포기하는 것이 좋습니다. 내 경험에 따르면, 이것은 거의 그렇지 않습니다.

논의 된 문제와 관련하여 이것이 내가 제안한 것입니다.

ISR:
if (countDownFlag)
{
   sec_counter--;
}

카운터 설정 :

// make sure the countdown isn't running
sec_counter = 500;
countDownFlag = true;

...
// Countdown finished
countDownFlag = false;

추가 변수가 필요하며 함수로 모든 것을 랩핑하는 것이 좋습니다.

void startCountDown(int startValue)
{
    sec_counter = 500;
    countDownFlag = true;
}

이렇게하면 시작 방법을 추상화하고 (필요한 경우 추악함을 숨 깁니다). 예를 들어, 메소드의 발신자에게 영향을 미치지 않고 하드웨어 타이머를 시작하기 위해 쉽게 변경할 수 있습니다.

SEC_COUNTER 변수에 대한 액세스는 원자가 아니기 때문에, 메인 라인 코드 에서이 변수에 액세스하고 결정 론적 동작을 원할 경우 액세스 후 인터럽트 상태를 복원하기 전에 인터럽트를 비활성화하는 것을 피할 수있는 방법이 없습니다. 이것은 아마도이 작업에 대한 HW 타이머를 바치는 것보다 더 나은 선택 일 것입니다 (타이머의 잉여가 없으면 하나를 사용할 수 있습니다).

Microchip의 무료 TCP/IP 스택을 다운로드하면 타이머 오버플로를 사용하여 경과 시간을 추적하는 루틴이 있습니다. 구체적으로 "tick.c"및 "tick.h". 해당 파일을 프로젝트에 복사하기 만하면됩니다.

해당 파일 내에서 어떻게하는지 알 수 있습니다.

256 미만의 동작이 원자 인 것에 대해 호기심이 없습니다. 8 비트 값을 움직이는 것은 하나의 OPCODE이므로 원자력이 있습니다.

PIC와 같은 마이크로 컨트롤러에서 가장 좋은 솔루션은 타이머 값을 변경하기 전에 인터럽트를 비활성화하는 것입니다. 기본 루프의 변수를 변경할 때 인터럽트 플래그의 값을 확인하고 원하는 경우 처리 할 수도 있습니다. 변수의 값을 변경하는 함수로 만들면 ISR에서도 호출 할 수도 있습니다.

글쎄, 비교 어셈블리 코드는 어떻게 생겼습니까?

아래쪽으로 계산되고 비교가 0이라는 점을 고려하여 먼저 MSB를 확인한 다음 LSB를 확인하면 안전해야합니다. 부패가있을 수 있지만 0x100에서 0xff 사이의 중간에오고 있으면 실제로는 중요하지 않으며 손상된 비교 값은 0x1ff입니다.

지금 당신이 당신의 타이머를 사용하는 방식은 타이머를 순환하는 중간에 변경할 수 있기 때문에 몇 초를 계산하지 않습니다. 따라서 신경 쓰지 않으면. 내 생각에 가장 좋은 방법은 그 가치를 읽은 다음 차이를 비교하는 것입니다. 몇 개의 OPS가 더 필요하지만 멀티 스레딩 문제는 없습니다. (타이머가 우선 순위가 있기 때문에)

시간 값에 대해 더 엄격한 경우 타이머가 0으로 계산되면 자동으로 타이머를 비활성화하고 타이머의 내부 카운터를 지우고 필요에 따라 활성화합니다.

Main ()에있는 코드 부분을 적절한 함수로 이동하고 ISR이 조건부로 호출하십시오.

또한 진드기가 지연되거나 누락되지 않도록이 타이머 ISR을 선택하여 고 프리오 인터럽트로 선택하십시오 (PIC18에는 두 가지 레벨이 있습니다).

한 가지 방법은 인터럽트가 바이트 변수를 유지하는 것이며, 카운터가 256 번에 걸쳐 최소한 한 번에 호출되는 다른 것을 갖는 것입니다. 다음과 같은 일을하십시오 :

// ub==unsigned char; ui==unsigned int; ul==unsigned long
ub now_ctr; // This one is hit by the interrupt
ub prev_ctr;
ul big_ctr;

void poll_counter(void)
{
  ub delta_ctr;

  delta_ctr = (ub)(now_ctr-prev_ctr);
  big_ctr += delta_ctr;
  prev_ctr += delta_ctr;
}

약간의 변형, 인터럽트 카운터가 큰 카운터의 LSB와 동기화되도록 강요하지 않으면 :

ul big_ctr;
void poll_counter(void)
{
  big_ctr += (ub)(now_ctr - big_ctr);
}

아무도 문제를 해결하지 못했습니다 독서 멀티 바이트 하드웨어 레지스터 (예 : 타이머. 타이머가 롤오버하여 두 번째 바이트를 읽을 수 있습니다.

0x0001ffff라고 말하면 읽으십시오. 0x0010ffff 또는 0x00010000을 얻을 수 있습니다.

16 비트 주변 장치 레지스터는 다음과 같습니다 휘발성 물질 코드에.

어떠한 것도 휘발성 물질 "변수", 나는 이중 읽기 기술을 사용합니다.

do {
       t = timer;
 } while (t != timer);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top