ESP32

ESP32 MicroPython: Timer interrupts

기하 2021. 8. 16. 04:11

소개

이 게시물의 목적은 ESP32에서 실행되는 MicroPython에 대한 타이머 인터럽트를 구성하는 방법을 설명하는 것입니다. ESP32의 하드웨어 타이머에 대한 자세한 내용은  이전 게시물 의 두 번째 섹션을 참조하세요  .

테스트는 ESP32 FireBeetle 보드에  통합된 DFRobot의 ESP-WROOM-32 장치를  사용하여 수행되었습니다  . 사용된 MicroPython IDE는  uPyCraft 입니다.


코드

우선 , 타이머 인터럽트를 구성하고 처리하는 데 필요한 기능에 액세스할 수 있는 기계 모듈 을 가져올 것 입니다 .

1 import machine

다음으로 우리는 인터럽트가 발생했음을 메인 코드에 알리기 위해 인터럽트 처리 기능에 사용될 카운터를 선언할 것입니다. 인터럽트는 가능한 한 빨리 실행되어야 하므로 내부에서 인쇄와 같은 함수를 호출하지 않아야 하므로 이 접근 방식을 사용합니다.

따라서 인터럽트가 발생하면 처리 기능은 단순히 카운터를 증가시킨 다음 인터럽트 기능 외부에 루프를 갖게 되며 해당 값을 확인하고 그에 따라 작동합니다.

1 interruptCounter = 0

또한 프로그램이 시작된 이후 발생한 모든 인터럽트를 저장할 카운터를 선언하여 각각의 새 인터럽트에 대해 이 값을 인쇄할 수 있습니다.

1 totalInterruptsCounter = 0

다음으로 machine 모듈 에서 사용할 수 있는 Timer 클래스의 개체를 만듭니다 . 이 개체를 사용하여 타이머 인터럽트를 구성합니다.

이 클래스의 생성자는 사용할 하드웨어 타이머를 나타내는 0에서 3 사이의 숫자 값을 입력으로 받습니다(ESP32에는 4개의 하드웨어 타이머가 있음). 이 예에서는 타이머 0을 사용합니다.

1 timer = machine.Timer(0)

이제 핸들링 함수를 선언해야 합니다 . 이 함수를 handleInterrupt 라고 합니다 . 이 함수는 인터럽트가 트리거될 때 Timer 클래스의 개체 가 전달될 입력 인수를 수신 하지만 코드에서는 사용하지 않습니다.

함수 논리의 경우 interruptCounter 변수 를 증가시키는 것만 큼 간단 합니다. 이 전역 변수에 액세스하고 수정할 것이기 때문에 먼저 global 키워드로 선언 한 다음 사용해야 합니다.

1
2
def handleInterrupt(timer):
  global interruptCounter
  interruptCounter = interruptCounter+1

이제 핸들링 함수 선언을 마쳤 으므로 이전에 만든 Timer 객체  init 메서드를 호출하여 타이머를 초기화 합니다.

이 함수의 입력은 인터럽트가 발생할 기간(밀리초로 지정), 타이머 모드(원샷 또는 주기적) 및 인터럽트를 처리할 콜백 함수입니다.

간단한 예에서는 매초 주기적으로 타이머가 실행되도록 설정할 것입니다. 따라서 period 인수의 경우 값 1000 을 전달하고 mode 인수 의 경우 Timer 클래스  PERIODIC 상수를 전달합니다 . 원샷 타이머 의 경우 동일한 클래스  ONE_SHOT 상수를 대신 사용할 수 있습니다 .

마지막으로 콜백 인수에서 이전에 선언된 처리 함수를 전달합니다.

1 timer.init(period=1000, mode=machine.Timer.PERIODIC, callback=handleInterrupt)

이제 타이머를 시작했으므로 코드를 계속 진행하겠습니다. 이전에 말했듯이 ISR이 발생 신호를 보낼 때 메인 코드에서 인터럽트를 처리합니다. 예제 프로그램은 매우 간단하기 때문에 인터럽트 카운터 변수를 폴링하여 0보다 큰지 확인 하는 무한 루프로 구현 합니다. 그렇다면 처리할 인터럽트가 있다는 의미입니다.

당연히 실제 사례 응용 프로그램에서는 이 변수를 폴링하는 대신 수행할 다른 계산이 있을 가능성이 큽니다.

따라서 인터럽트를 감지하면 인터럽트 를 처리한다는 신호 를 보내기 위해 interruptCounter 변수를 감소시켜야 합니다. 이 변수는 ISR과 공유되고 경주 조건을 피하기 위해 임계 섹션에서 이 감소를 수행해야 합니다. 이 감소는 단순히 인터럽트를 비활성화하여 구현할 것입니다.

당연히 이 중요한 섹션은 인터럽트를 다시 활성화하기 위해 가능한 한 짧아야 합니다. 따라서 여기서 변수 감소만 수행되고 나머지 모든 처리는 인터럽트가 다시 활성화된 상태에서 외부에서 수행됩니다.

따라서  기계 모듈  disable_irq 함수를 호출하여 인터럽트를 비활성화 합니다. 이 함수는 변수에 저장할 이전 IRQ 상태를 반환합니다. 인터럽트를 다시 활성화하려면  기계 모듈에서도 enable_irq 함수 를 호출 하고 이전에 저장된 상태를 입력으로 전달하면 됩니다. 이 두 호출 사이에 공유 변수에 액세스하여 감소시킵니다.

1
2
state = machine.disable_irq()
    interruptCounter = interruptCounter-1
    machine.enable_irq(state)

그런 다음 전체 인터럽트 카운터를 증가시키고 인쇄하여 인터럽트 처리를 마칩니다. 스크립트의 최종 코드는 아래에서 볼 수 있습니다. 여기에는 이미 이러한 인쇄물과 인터럽트를 확인할 루프가 포함되어 있습니다.

1
2

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import machine


interruptCounter = 0
totalInterruptsCounter = 0


timer = machine.Timer(0) 


def handleInterrupt(timer):
  global interruptCounter
  interruptCounter = interruptCounter+1


timer.init(period=1000, mode=machine.Timer.PERIODIC, callback=handleInterrupt)


while True:
  if interruptCounter>0:
    state = machine.disable_irq()
    interruptCounter = interruptCounter-1
    machine.enable_irq(state)


    totalInterruptsCounter = totalInterruptsCounter+1
    print("Interrupt has occurred: " + str(totalInterruptsCounter))


코드 테스트

코드를 테스트하려면 이전 스크립트를 ESP32 보드에 업로드하고 실행하기만 하면 됩니다. 1초의 주기적인 간격으로 메시지가 프린터로 표시되는 그림 1과 유사한 출력이 표시되어야 합니다.

그림 1 - ESP32에서 실행되는 MicroPython용 타이머 인터럽트 프로그램의 출력.