소개
이 게시물의 목적은 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용 타이머 인터럽트 프로그램의 출력.
'ESP32' 카테고리의 다른 글
ESP32 Arduino: External interrupts (0) | 2021.08.16 |
---|---|
ESP32 Arduino: Timer interrupts (0) | 2021.08.16 |
ESP32 MicroPython: Getting started with the uPyCraft IDE (0) | 2021.08.16 |
ESP32 Arduino: Getting started with WiFi (0) | 2021.08.16 |
ESP32: HTTP GET Requests (0) | 2021.08.16 |