ESP32

ESP32 Timers & Timer Interrupts

기하 2023. 12. 22. 14:03

https://circuitdigest.com/microcontroller-projects/esp32-timers-and-timer-interrupts

 

ESP32 Timers & Timer Interrupts

There are times when you need something to happen on time and that’s where timers and timer interrupts come to play. A timer is a kind of interrupt. It is like a simple clock that is used to measure and control time events providing a precise time delay

circuitdigest.com

 

제 시간에 어떤 일이 일어나야 할 때가 있는데,
이때 타이머타이머 인터럽트가 작동합니다. 

 

타이머는 일종의 인터럽트이다. 

이는 정확한 시간 지연을 제공하는 시간 이벤트를 측정하고 제어하는 ​​데 사용되는 간단한 시계와 같습니다. 

대부분의 마이크로 컨트롤러에는 시간 지연을 생성할 뿐만 아니라

카운터로도 사용되는 타이머가 내장되어 있습니다. 

 

타이머의 이러한 특성은 많은 애플리케이션에 사용됩니다. 

마이크로컨트롤러의 타이머는 타이머 작동을 위해 할당된 특수 기능 레지스터에 의해 제어됩니다.

ESP32 칩에는

두 개의 하드웨어 타이머 그룹이 포함되어 있습니다. 

각 그룹에는 두 개의 범용 하드웨어 타이머가 있습니다. 

이들은 모두 16비트 프리스케일러와 자동 재로드가 가능한

64비트 업/다운 카운터를 기반으로 하는 64비트 일반 타이머입니다.

 

타이머 인터럽트

타이머 인터럽트

시간이 지정된 이벤트가
밀리초 단위로 발생하도록 하는 효과적인 방법으로,

클럭 또는 PWM 작동을 미세 조정하거나

LED에 안정적인 펄스를 공급할 수 있습니다. 

 

타이머 인터럽트는

타이머에 의해 생성된 소프트웨어 인터럽트입니다. 

 

타이머 인터럽트를 사용하면

코드에서 무슨 일이 일어나고 있는지에 관계없이

매우 구체적인 시간 간격으로 작업을 수행할 수 있습니다. 

 

외부 인터럽트와 유사하지만

외부 이벤트에 의해 트리거되는 대신 타이머에 의해 트리거됩니다. 

트리거되면 현재 명령어가 완료된 후 실행 스레드를 중단하고

ISR을 호출하며

 

하드웨어나 외부 인터럽트와 마찬가지로 완료되면

중단된 위치에서 다음 명령어로 돌아갑니다. 

다음은 타이머 개념을 보여주는 이미지입니다.

이러한 타이머는 하드웨어 기반이므로

모든 타이밍은 타이머의 시계와 관련됩니다. 

타이머 속도는 다음 공식으로 결정할 수 있습니다.

timer speed (Hz) = Timer clock speed (Mhz) / prescaler

 

예를 들어,

80MHz의 클록 주파수에서 실행되는 ESP32의 타이머 속도는

프리스케일러 값이 1로 설정된 경우 80MHz 또는 8000000MHz이고

프리스케일러 값이 80인 경우 1MHz 또는 1000000Hz입니다.

 

프리스케일러는

위의 주파수를 나누어 타이머의 "틱"을 형성하는 것입니다(카운터 증가). 

그런 다음 ISR은 특정 틱 수 후에 트리거되도록 구성됩니다. 

다음 이미지는 타이머 인터럽트가 포함된 프로세스 흐름을 보여줍니다.

하드웨어 인터럽트와 마찬가지로

타이머 인터럽트도 특정 간격으로 비차단 기능을 실행하는 가장 좋은 방법입니다. 

이를 위해 설정 기능에서 특정 타이머 인터럽트를 특정 ISR에 구성하고 연결합니다. 

컨트롤러는 메인 루프를 지속적으로 실행합니다. 

타이머 인터럽트가 생성될 때마다

마이크로컨트롤러는 메인 루프를 일시 중지하고

인터럽트 서비스 루틴(ISR) 실행을 진행합니다. 

ISR 실행이 완료되면 마이크로컨트롤러는

일시 중지된 위치에서 메인 루프를 다시 시작합니다. 

이 프로세스는 모든 타이머 인터럽트에 대해 반복됩니다.

ESP32 타이머 인터럽트에 대해 자주 묻는 질문

Q. ESP32에는 몇 개의 타이머가 있습니까?

ESP32는 4개의 64비트 타이머를 제공합니다.

Q. ESP32에서 타이머 인터럽트를 어떻게 사용하나요?

원하는 타이머를 인터럽트에 연결하고 동일한 타이머에 ISR을 할당할 수 있습니다.

Q. ESP32 타이머는 어떻게 작동하나요?

타이머는 클럭 주파수와 프리스케일러 값에 따라 특정 속도로 계산되는 카운터를 사용합니다. 이 카운터는 설정된 값에 도달하면 재설정되고 인터럽트가 트리거됩니다. 이 카운트 값을 변경하여 타이머 간격을 변경할 수 있습니다.

ESP32 타이머 인터럽트 예 – LED 깜박임

이 예에서는 LED 깜박임 프로그램을 테스트해 보겠습니다. 하지만 지연을 사용하는 대신 타이머 인터럽트를 사용하겠습니다. 그렇게 하려면 아래 회로도에 표시된 대로 브레드보드에 연결하십시오.

다음은 회로도에 따라 브레드보드에 연결된 실제 회로입니다.

LED의 양극을 GPIO21에 연결하고 음극을 220Ω 저항을 통해 GND에 연결합니다.

타이머 인터럽트로 LED를 깜박이는 ESP32 코드

이 글 하단에 첨부된 코드를 다운로드하여 ESP32에 업로드하세요. LED가 1Hz의 속도로 깜박이는 것을 볼 수 있습니다. 코드의 각 부분에 대해 논의해 보겠습니다.

#define LED 21
hw_timer_t *My_timer = NULL;

전역 변수 영역에서는 LED 핀을 GPIO21로 정의했습니다. 

그런 다음 타이머를 구성하기 위해 

hw_timer_t 유형의 My_timer 라는 포인터 변수를 만들었습니다 .

 

void IRAM_ATTR onTimer(){
digitalWrite(LED, !digitalRead(LED));
}

그런 다음 타이머 인터럽트를 위한 ISR을 만들었습니다. 
ISR에서 우리는 GPIO21의 상태를 반전시키는 함수를 작성했습니다. 

이 ISR은 타이머 인터럽트가 발생할 때 실행됩니다.

 

void setup() {
	pinMode(LED, OUTPUT)
	My_timer = timerBegin(0, 80, true);
	timerAttachInterrupt(My_timer, &onTimer, true);
	timerAlarmWrite(My_timer, 1000000, true);
	timerAlarmEnable(My_timer);
}
void loop() {
}

 

그리고 설정 기능에서 pinMode 매크로를 사용하여 GPIO21을 출력으로 초기화했습니다.

 

My_timer = timerBegin(0, 80, true);

타이머를 초기화하기 위해

다음 변수와 함께 timebegin 함수를 사용하고 있습니다. 

첫 번째는 사용하려는 타이머의 번호(하드웨어 타이머가 4개 있으므로 0에서 3까지)이고,

두 번째는 프리스케일러의 값이고

마지막은 카운터가 카운트업되어야 하는지를 나타내는 플래그입니다. (true) 또는 아래로 (false). 

이 예에서는 타이머 0과 프리스케일러 80 및 카운터를 사용하여 카운트합니다.

 

timeAttachInterrupt(My_timer, &onTimer, true);

타이머를 활성화하기 전에

인터럽트가 생성될 때 실행될 ISR에 타이머를 연결해야 합니다. 

이는 timeAttachInterrupt 함수를 호출하여 수행됩니다. 

이 예에서는 onTimer라는 ISR 함수를 타이머 인터럽트에 연결했습니다.

 

timerAlarmWrite(My_timer, 1000000, true);

timeAlarmWrite 함수는

타이머 인터럽트가 생성되어야 하는 카운터 값을 지정하는 데 사용됩니다. 

따라서 이 예에서는 매초마다 인터럽트를 생성한다고 가정하고

1초에 해당하는 1000000마이크로초 값을 전달합니다. 

세 번째 인수에는 true 값을 전달하므로 카운터가 다시 로드되어 인터럽트가 주기적으로 생성됩니다.

timerAlarmEnable(My_timer);

마지막으로, timeAlarmEnable 함수를 사용하여 타이머 인터럽트를 활성화합니다.

 

 

#define LED 21
hw_timer_t *My_timer = NULL;
void IRAM_ATTR onTimer(){
digitalWrite(LED, !digitalRead(LED));
}
void setup() {
pinMode(LED, OUTPUT);
My_timer = timerBegin(0, 80, true);
timerAttachInterrupt(My_timer, &onTimer, true);
timerAlarmWrite(My_timer, 1000000, true);
timerAlarmEnable(My_timer); //Just Enable
}
void loop() {
}