일반 ISR처럼 AVR 워치 독 사용


17

ATTinyX5 시리즈의 워치 독 타이머 주위에 머리를 감 으려고합니다. 그래서 내가 읽은 것은 프로그램이 N 초 동안 특정 작업을 수행하는 데 사용할 수있는 것처럼 보이지만 실제로는 결코 보여주지 못했습니다. 다른 사람들은 코드에서 무언가가 재설정되는 동안 칩을 리셋하지 않는 것처럼 보이게했다 ( "정상적인"사용으로 보인다).

TIMER1_COMPA_vect 또는 이와 유사한 방식으로 WDT를 사용하는 방법이 있습니까? 나는 그것이 1 초 타임 아웃 모드를 가지고 있음을 알아 차리고 그것을 사용하여 내 코드에서 1 초마다 어떤 일이 일어나도록하고 싶습니다 (그리고 바람직하게는 사이에서 잠을 자고 싶습니다).

생각?

* 업데이트 : * 요청 된 이후, 내가 말하는 것은 ATTinyX5 데이터 시트 의 섹션 8.4입니다 . 나는 그것을 완전히 이해하지 못하는데, 이것이 내 문제입니다 ...


1
상자 밖에서 생각하면 +1. AVR 용 데이터 시트에 링크를 추가하면 추가로 승인되지 않습니다.
jippie

답변:


23

당신은 가장 확실하게 할 수 있습니다. 데이터 시트에 따르면 워치 독 타이머는 MCU를 재설정하거나 트리거 될 때 인터럽트를 발생 시키도록 설정 될 수 있습니다. 인터럽트 가능성에 더 관심이있는 것 같습니다.

WDT는 실제로 일반 타이머보다 설정이 더 쉬운 이유는 덜 유용합니다. 적은 옵션입니다. 내부적으로 보정 된 128kHz 클록에서 실행되므로 타이밍은 MCU의 주요 클록 속도에 영향을받지 않습니다. 웨이크 업 소스를 제공하기 위해 가장 깊은 수면 모드 동안 계속 실행할 수도 있습니다.

몇 가지 데이터 시트 예제와 C에서 사용한 일부 코드를 살펴 보겠습니다.

포함 된 파일 및 정의

시작하려면 아마도 다음 두 가지 헤더 파일을 포함시켜 작업 할 수 있습니다.

#include <avr/wdt.h>        // Supplied Watch Dog Timer Macros 
#include <avr/sleep.h>      // Supplied AVR Sleep Macros

또한 표준 AVR 헤더 중 하나에 정의 된 매크로 <_BV (BIT)>를 다음과 같이 사용합니다 (더 친숙 할 수 있음).

#define _BV(BIT)   (1<<BIT)

코드의 시작

MCU가 처음 시작되면 일반적으로 I / O를 초기화하고 타이머를 설정하는 등의 작업을 수행해야합니다. 여기서 WDT가 다시 수행 할 수 있기 때문에 WDT로 인해 재설정이 발생하지 않도록하는 것이 좋습니다. 불안정한 루프.

if(MCUSR & _BV(WDRF)){            // If a reset was caused by the Watchdog Timer...
    MCUSR &= ~_BV(WDRF);                 // Clear the WDT reset flag
    WDTCSR |= (_BV(WDCE) | _BV(WDE));   // Enable the WD Change Bit
    WDTCSR = 0x00;                      // Disable the WDT
}

WDT 설정

그런 다음 나머지 칩을 설정 한 후 WDT를 다시 실행하십시오. WDT를 설정하려면 "시간 순서"가 필요하지만 실제로는 매우 쉽습니다 ...

// Set up Watch Dog Timer for Inactivity
WDTCSR |= (_BV(WDCE) | _BV(WDE));   // Enable the WD Change Bit
WDTCSR =   _BV(WDIE) |              // Enable WDT Interrupt
           _BV(WDP2) | _BV(WDP1);   // Set Timeout to ~1 seconds

물론이 코드 중에 인터럽트를 비활성화해야합니다. 나중에 다시 활성화하십시오!

cli();    // Disable the Interrupts
sei();    // Enable the Interrupts

WDT 인터럽트 서비스 루틴 다음으로 걱정할 것은 WDT ISR을 처리하는 것입니다. 이것은 다음과 같이 수행됩니다.

ISR(WDT_vect)
{
  sleep_disable();          // Disable Sleep on Wakeup
  // Your code goes here...
  // Whatever needs to happen every 1 second
  sleep_enable();           // Enable Sleep Mode
}

MCU 슬립

MCU를 WDT ISR 내부에서 휴면 상태로두기보다는 ISR 종료시 휴면 모드를 활성화 한 다음 MAIN 프로그램에서 MCU를 대기 상태로 전환하는 것이 좋습니다. 이렇게하면 프로그램이 실제로 절전 모드로 전환되기 전에 ISR을 떠나고 WDT ISR로 다시 돌아옵니다.

// Enable Sleep Mode for Power Down
set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // Set Sleep Mode: Power Down
sleep_enable();                     // Enable Sleep Mode  
sei();                              // Enable Interrupts 

/****************************
 *  Enter Main Program Loop  *
 ****************************/
 for(;;)
 {
   if (MCUCR & _BV(SE)){    // If Sleep is Enabled...
     cli();                 // Disable Interrupts
     sleep_bod_disable();   // Disable BOD
     sei();                 // Enable Interrupts
     sleep_cpu();           // Go to Sleep

 /****************************
  *   Sleep Until WDT Times Out  
  *   -> Go to WDT ISR   
  ****************************/

   }
 }

와우 ... 매우 상세합니다. 감사! 메인 루프를 표시하는 수면 섹션에 약간 혼란 스럽습니다 (if (MCUCR & _BV (SE)) {// 수면이 활성화 된 경우 ... 등) 나는 왜 주 모양에서 당신이 원하는지 혼란 스럽습니다. 지속적으로 비활성화하고 인터럽트를 활성화했습니다. 그리고 그 섹션의 상단에있는 부분 (set_sleep_mode (SLEEP_MODE_PWR_DOWN);) 어디에서 실행됩니까?
Adam Haile

"set_sleep_mode (MODE)"부분은 메인 루프 전에 메인에 있어야합니다. 이상적으로는 I / O 포트, 타이머 등을 설정하는 다른 초기화 코드에 있어야합니다. 실제로 enable_sleep ()을 사용할 필요는 없습니다. 이 시점에서 첫 번째 WDT 트리거 이후에 ​​수행되기 때문입니다. 메인 루프 내에서, 슬립 코드는 슬립이 활성화 된 경우에만 실행되며, sleep_bod_disable ()을 수행하는 경우에만 인터럽트를 비활성화 / 재 활성화 할 필요는 없습니다. 전체 IF 문은 다른 코드 실행 후 MAIN 루프의 맨 아래에 있지만 여전히 내부에있을 수 있습니다.
커트이 클로 이어

좋아 ... 이제 더 이해가 되네요. 내가 애매한 마지막 것은이 "시한 적 순서"가 무엇인가이다.
Adam Haile

사이드 노트 : 당신이 잠에 가고 싶은 이유를 알아,하지만 난 당신이하지 않는 가정 WDT를를 사용하는 경우에?
Adam Haile

데이터 시트의이 작은 섹션을 살펴보십시오. 8.4.1. 기본적으로 WDT 레지스터를 변경하려면 변경 비트를 설정 한 다음 너무 많은 클럭 사이클 내에서 적절한 WDTCR 비트를 설정해야합니다. WDT 설정 섹션에서 제공 한 코드는 먼저 WD 변경 비트를 활성화하여이 작업을 수행합니다. WDT와 함께 절전 기능을 전혀 사용할 필요는 없습니다. 원하는 이유에 관계없이 표준 시간 인터럽트 소스가 될 수 있습니다.
커트이 클로 이어

1

데이터 시트에 따르면 가능합니다. 인터럽트와 리셋을 모두 활성화 할 수도 있습니다. 둘 다 활성화 된 경우 첫 번째 워치 독 시간 초과는 인터럽트를 트리거하여 인터럽트 활성화 비트가 설정되지 않도록합니다 (인터럽트 비활성화). 다음 타임 아웃은 CPU를 재설정합니다. 인터럽트가 실행 된 직후에 인터럽트를 활성화하면 다음 타임 아웃은 인터럽트 만 트리거합니다.

인터럽트를 활성화하고 리셋을 전혀 활성화하지 않을 수도 있습니다. 인터럽트가 트리거 될 때마다 WDIE 비트를 설정해야합니다.


흠 .. 말이되는 것 같아. 나는 그것을 줄 것이다. 나는 그들이 의도하지 않은 것을 위해 물건을 사용하는 것을 항상 좋아합니다 :)
Adam Haile

실제로 나는 그것이 영리한 디자인이라고 생각합니다. 감시 기능을 유지하면서 타이머를 절약합니다.
Tom L.

2
WDT의 초기 시간 초과 및 후속 인터럽트는 또한 실제 중단 복구를 위해 WDT를 활성화하는 일부 응용 프로그램에 유리하게 사용될 수 있습니다. WDT ISR에서 스택 리턴 주소를보고 "예기치 않은 시간 초과"가 발생했을 때 코드가 수행하려는 작업을 유추 할 수 있습니다.
Michael Karas

1

이것은 위와 다른 곳에서 제안한 것보다 훨씬 쉽습니다.

만큼으로 WDTON퓨즈가 (이 기본적으로 프로그램되지 않음) 프로그램되어 있지 않은 경우, 당신은 단지 필요 ...

  1. 워치 독 인터럽트 활성화 비트와 워치 독 제어 레지스터에서 타임 아웃을 설정하십시오.
  2. 인터럽트를 활성화하십시오.

다음은 16ms 당 한 번 ISR을 실행하는 코드 예제입니다.

ISR(WDT_vect) {
   // Any code here will get called each time the watchdog expires
}

void main(void) {
   WDTCR =  _BV(WDIE);    // Enable WDT interrupt, leave existing timeout (default 16ms) 
   sei();                                           // Turn on global interrupts
   // Put any code you want after here.
   // You can also go into deep sleep here and as long as 
   // global interrupts are eneabled, you will get woken 
   // up when the watchdog timer expires
   while (1);
}

정말 그렇습니다. 워치 독 리셋을 활성화하지 않기 때문에, 타임 드 시퀀스를 사용하지 않도록 설정하지 않아도됩니다. ISR이 호출되면 워치 독 인터럽트 플래그가 자동으로 지워집니다.

1 초마다 다른주기를 원하는 경우 여기에서이 값을 사용하여 적절한 비트를 설정할 수 있습니다 WDTCR.

여기에 이미지 설명을 입력하십시오

시간 초과를 변경하려면 시간 순서를 실행해야합니다. 다음은 시간 초과를 1 초로 설정하는 코드입니다.

   WDTCR = _BV(WDCE) | _BV(WDE);                   // Enable changes
   WDTCR = _BV(WDIE) | _BV( WDP2) | _BV( WDP1);    // Enable WDT interrupt, change timeout to 1 second

설정하는 동안 시간 순서를 지정하지 않으면 한 줄의 코드 (읽기-수정-쓰기 작업)가 저장됩니다. 데이터 시트에서 "워치 독이 우연히 활성화 된 경우 (예 : 런 어웨이 포인터 또는 브라운 아웃 조건)"데이터 시트에 초기 시퀀스가 ​​권장되며 나머지 코드는 WDT를 슬립 모드와 함께 사용하여 요청한대로 OP. 귀하의 솔루션은 더 간단하지 않으며 권장 / 필요한 보일러 플레이트 코드를 무시했습니다.
Kurt E. Clothier

@ KurtE.Clothier 죄송합니다. 가장 간단한 작업 예제를 제공하려고합니다!
bigjosh
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.