이 블로그는 Web 환경을 이용한 원격 제어 기술에 필요한 지식을 공유 하기 위한 블로그 입니다.
실제 개발과 프로그램 예를 위하여 WiFi Module과 Raspberry Pi, Raspberry Pi Pico, ATmega128 보드, Arduino Mega 보드(ATmega2560)를 사용 합니다.

python-timer-pwm

ESP8266/ESP32 Timer와 PWM - MicroPython
ESP8266/ESP32 Timer와 PWM(Pulse width modulation) - MicroPython


  • ESP8266/ESP32 Timer와 PWM(Pulse width modulation)
    • Timer object(class Timer) – control hardware timers
      • Timer object 생성자(Constructors): class machine.Timer(id, ...)
        • id: Timer 식별자로 필수 인수(다른 인수는 선택 사항)이다.
        • id 가 -1인 경우에는 Virtual timer(Software Timer)를 생성(보드에서 지원하는 경우)한다. ESP8266 보드는 Virtual timer 기능을 지원하고 ESP32 보드(Hardware timer가 4개 있음)에서는 지원하지 않는다. ESP32 보드에서 id 가 -1인 경우 Timer 3 가 선택(-1 -> 0b1111_1111에서 우측 2Bit를 취하면(0b0000_0011 로 Masking 하면) 0b11 -> 3이)된다. ESP8266 보드는 2개의 Timer(Timer0, Timer1)가 있지만 Timer0는 WiFi function에서 사용하기 때문에 WiFi를 사용하는 경우 Timer1만 사용할 수 있기 때문에 Virtual timer를 사용한다.
      • Methods
        • Timer.init(*, mode=Timer.PERIODIC, period=- 1, callback=None)
          • mode: Timer 동작 모드를 지정한다.
          • period: Timer 주기를 설정하는 mSec 단위의 정수
          • callback: Timer event 가 발생할 때 실행되는 callback function를 지정하다.
        • Timer.deinit()
          • Timer를 중지하고 Timer를 비 활성화 한다.
        • Constants
          • Timer 동작 mode를 설정하기 위한 상수 이다.

          • Timer.ONE_SHOT
          • Timer.PERIODIC
        • Timer 초기화 예
          • tim.init(period=100) : Timer 주기를 100ms로 설정한다.
          • tim.init(mode=Timer.ONE_SHOT, period=1000) : 1000ms 후에 One shot 펄스가 발생한다.
    • 프로그램 예: LED 점멸 주기 제어
      • 이 예는 Timer를 이용하여 일정한 주기의 Interrupt를 발생 시키는 방법과 Callback function의 이해를 위한 것이다. 또한 버튼 스위치를 이용하여 Timer의 주기를 변경한다.

        LED는 개발보드(GPIO2)에 내장된 LED를 이용한다. 회로 구성을 위한 개발보드 Pin 배열은 "ESP8266/ESP32 개발보드 Pin"을 참고하기 바람.

        실험 회로 구성 예

      • LED 점멸 주기 제어 프로그램 예: timer_int_period_led.py
      • 실험을 위한 준비
        • LED: 개발보드에 내장(GPIO2)되어 있기 때문에 별도의 회로를 필요로 하지 않는다.
        • Button switch: 위 "실험 회로 구성 예"와 같이 GPIO4와 GPIO5에 switch를 연결한다.
      • 실험 방법
        • Thonny IDE를 실행하고 Thonny IDE의 사용 환경(Thonny 실행에 사용할 장치와 COM Port 선택)이 바르게 되어 있는지 확인한다.
        • Thonny IDE의 Python shell 창에 prompt( >>> )가 출력되었는 확인한다.
        • 위 프로그램을 복사하여 Thonny IDE의 Script 편집 창에 복사한다.
        • Script 편집 창의 프로그램을 File name "timer_int_period_led.py"로 저장 한다.
        • 실험
          • "실행 -> 현재 스크립트 실행"을 실행하거나 Toolbar의 "실행" Icon을 클릭하면 스크립트가 개발보드에 전송되고 프로그램이 실행된다.
          • GPIO4 버튼을 누르고 있으면 LED의 점멸 속도가 점점 빨라지고 GPIO5 버튼을 누르고 있으면 LED의 점멸 속도가 점점 느려진다.

    • 프로그램 예: SW Debouncing
      • 이 예는 Timer를 이용하여 일정한 시간 후에 Interrupt를 발생는 방법과 Callback function의 이해를 위한 것이다. 이 예는 일정한 시간이 지난 다음 발생하는 Interrupt를 이용하여 스위치에서 발생하는 Bouncing 문제를 해결(Debouncing) 하는 예 이다.

        아래 그림은 Switch의 금속 접점이 이상적이지 않기 때문에 Switch를 Closed 하거나 Open 하는 순간에 발생하는 Bouncing 현상 예 이다. Bouncing은 Switch의 상태에 따라 대략 5mSec - 10mSec 사이에 발생 한다.

        소프트웨어로 Bouncing 문제를 해결(Debouncing) 하는 방법은 처음 Switch 누름을 인지한 다음 약 15mSec - 30mSec 후, Switch 상태를 다시 확인하여 이 떄 까지 누름 상태가 지속되는 경우 누름 상태로 판단하는 것 이다.

      • SW Debouncing 프로그램 예: sw_debounc_counter_interrupt.py
      • 
        from machine import Pin, Timer
        swCounter = 0
        
        # Debouncing timer callback function
        # 이 callback function는 External interrupt 발생 후 20mSec 후에 실행된다.
        def on_pressed(timer):
          global swCounter
          # Button을 누른 상태가 계속(20mSec 이상)되고 있으면 버튼을 누른 것으로 판단한다.
          if button.value() == 0:
            swCounter += 1
            print("Counter: " + str(swCounter))
        
        # Switch를 누르면 발생하는  external interrupt handler
        def debounce(pin):
          # 20ms 후에 Timer interrupt(One_shot)이 발생한다. 
          timer.init(mode=Timer.ONE_SHOT, period=20, callback=on_pressed)
        
        # Register a new hardware timer.
        timer = Timer(0)
        
        # GPIO0을 Button 입력 핀으로 설정한다.
        button = Pin(0, Pin.IN, Pin.PULL_UP)
        
        # 버튼을 누룰 때 External interrupt(Falling edge)이 발생하도록 설정
        button.irq(handler=debounce, trigger=Pin.IRQ_FALLING)
                
      • 실험을 위한 준비
        • Button switch: 개발보드에 내장(GPIO0)되어 있기 때문에 별도의 회로를 필요로 하지 않는다.
      • 실험 방법
        • Thonny IDE를 실행하고 Thonny IDE의 사용 환경(Thonny 실행에 사용할 장치와 COM Port 선택)이 바르게 되어 있는지 확인한다.
        • Thonny IDE의 Python shell 창에 prompt( >>> )가 출력되었는 확인한다.
        • 위 프로그램을 복사하여 Thonny IDE의 Script 편집 창에 복사한다.
        • Script 편집 창의 프로그램을 File name "sw_debounc_counter_interrupt.py"로 저장 한다.
        • 실험
          • "실행 -> 현재 스크립트 실행"을 실행하거나 Toolbar의 "실행" Icon을 클릭하면 스크립트가 개발보드에 전송되고 프로그램이 실행된다.
          • 스위치 버튼(GPIO0)을 누르면서 콘솔창에 출력되는 카운트 값를 확인한다. Bouncing 문제가 해결되었으면 버튼을 누를 때 마다 카운터 값이 1 씩 증가 하여야 한다.

  • ESP8266/ESP32 PWM(Pulse width modulation)
    • PWM은 일정한 주기의 펄스 신호에서 신호가 High 상태인 비율을 조정(제어)하여 부하(예: LED, DC 모터 등)에 가하는 전력을 제어하는 기술이다. 신호 주기 동안 계속 High 상태인 경우 부하에 최대 전력이 공급되고, 주기의 50% 동안 High 인경우 최대 전력의 50%가 공급된다. 신호 주기 동안 계속 Low 상태인 경우 부하에 전력은 0 이 된다.

    • PWM object(class PWM)
      • PWM object 생성자(Constructors): machine.PWM(id, freq, duty)
        • id: Pin 식별자로 필수 인수(다른 인수는 선택 사항)이다.
        • freq: PWM 신호의 Toggling 주기(fq)를 frequency로 설정한다. ESP8266인 경우 fq는 0 - 78125 사이로 설정하여야 한다.
        • duty: duty_cycle은 0(All off) - 1023(ALL on) 사이의 값을 갖는다. 예: duty_cycle이 521 인 경우 Duty는 50% 가 된다.
      • Methods
        • freq(fq): PWM 신호의 Toggling 주기(frequency)를 설정한다.
        • duty(duty_cycle): duty를 설정한다.
        • pwm-id.deinit(): PWM Mode 상태를 해제한다.
          • pwm12 = machine.PWM(p12) 와 같이 PWM Object를 생성한 경우
          • pwm12.deinit() 를 실행할 때까지 PWM Mode 상태를 지속한다.

    • 프로그램 예: LED 밝기 제어(PWM)
      • 이 예는 PWM을 이용한 DC 전력제어(예: LED 밝기제어, DC 모터 속도제어 등) 기술를 이해하기 위한 것이다.

      • LED 밝기 제어(PWM) 프로그램 예: pwm_led_brigth_cont.py
      • 실험을 위한 준비
        • LED: 개발보드에 내장(GPIO2)되어 있기 때문에 별도의 회로를 필요로 하지 않는다.
        • Button switch: 위 "실험 회로 구성 예"와 같이 GPIO4와 GPIO5에 switch를 연결한다.
      • 실험 방법
        • Thonny IDE를 실행하고 Thonny IDE의 사용 환경(Thonny 실행에 사용할 장치와 COM Port 선택)이 바르게 되어 있는지 확인한다.
        • Thonny IDE의 Python shell 창에 prompt( >>> )가 출력되었는 확인한다.
        • 위 프로그램을 복사하여 Thonny IDE의 Script 편집 창에 복사한다.
        • Script 편집 창의 프로그램을 File name "pwm_led_brigth_cont.py"로 저장 한다.
        • 실험
          • "실행 -> 현재 스크립트 실행"을 실행하거나 Toolbar의 "실행" Icon을 클릭하면 스크립트가 개발보드에 전송되고 프로그램이 실행된다.
          • GPIO4 버튼을 누르고 있으면 LED가 점점 밝아지고, GPIO5 버튼을 누르고 있으면 LED가 점점 어두워 진다.

    • 프로그램 예: time_pulse_us() 함수를 이용한 Pulse Width 측정
      • 펄스폭 측정을 위한 회로 구성 예

        이 예는 펄스 신호의 펄스폭 측정기술 이해하기 위한 예로 machine.time_pulse_us() 함수를 사용한다.

      • machine.time_pulse_us() 함수
        • 이 함수에서 활당된 핀에 입력되는 펄스의 폭(펄스 지속 시간)을 측정(uSec 단위)하여 그 값을 반환하는 함수이다.
        • 함수의 기본형: machine.time_pulse_us(pin, pulse_level, timeout_us)
          • pin: 피 측정 신호(Pulse)기 입력되는 핀 번호
          • pulse_level: 이 값이 1이면 펄스가 High인 시간을 측정하고, 이 값이 0이면 펄스가 Low인 시간을 측정한다.
          • timeout_us: 이 값보다 측정 소요 시간이 길어지면 함수를 강제로 종료(Timeout) 시킨다. 피 측정 신호를 기다리는 동안 Timeout이 발생하면 -2가 Return 되고, 신호를 측정하는 동안 Timeout이 발생하면 -1이 Return 된다.
      • time_pulse_us() 함수를 이용한 Pulse Width 측정 프로그램 예: pulse_width_measure_time_us.py
      • 실험을 위한 준비
        • 피 측정 Pulse 신호(GPIO2)와 측정 신호 입력(GPIO16) Pin을 연결 한다.
        • Button switch: 위 "실험 회로 구성 예"와 같이 GPIO4와 GPIO5에 switch를 연결한다.
      • 실험 방법
        • Thonny IDE를 실행하고 Thonny IDE의 사용 환경(Thonny 실행에 사용할 장치와 COM Port 선택)이 바르게 되어 있는지 확인한다.
        • Thonny IDE의 Python shell 창에 prompt( >>> )가 출력되었는 확인한다.
        • 위 프로그램을 복사하여 Thonny IDE의 Script 편집 창에 복사한다.
        • Script 편집 창의 프로그램을 File name "pulse_width_measure_time_us.py"로 저장 한다.
        • 실험
          • "실행 -> 현재 스크립트 실행"을 실행하거나 Toolbar의 "실행" Icon을 클릭하면 스크립트가 개발보드에 전송되고 프로그램이 실행된다.
          • 콘솔 창에 측정값이 1초 간격으로 출력된다. GPIO4 버튼을 누르면 펄스폭이 증가하고, GPIO5 버튼을 누르면 펄스폭이 감소한다.

    • 프로그램 예: utime.ticks_us() 함수를 이용한 Pulse Width 측정
      • 이 예는 utime.ticks_us()(or utime.ticks_ms()) 함수의 이해를 위한 예 이다.

      • utime.ticks_us() 와 utime.ticks_ms()함수
        • 이 함수가 실행되는 임의 순간 Increasing microseconds(or millisecond) counter의 값을 반환하는 함수이다. utime.ticks_us()와 utime.ticks_ms() 함수는 기능은 같고 반환되는 시간 단위만 uSec와 mSec로 다르다.
      • 측정된 Ticks 값의 연산을 위하여 utime.ticks_add(ticks, delta) 함수와 utime.ticks_diff(ticks1, ticks2) 함수를 이용할 수 있다.
      • utime.ticks_us() 함수를 이용한 Pulse Width 측정 프로그램 예: pulse_width_measure_utime_tick.py
      • 실험을 위한 준비
        • 피 측정 Pulse 신호(GPIO2)와 측정 신호 입력(GPIO16) Pin을 연결 한다.
        • Button switch: 위 "실험 회로 구성 예"와 같이 GPIO4와 GPIO5에 switch를 연결한다.
      • 실험 방법
        • Thonny IDE를 실행하고 Thonny IDE의 사용 환경(Thonny 실행에 사용할 장치와 COM Port 선택)이 바르게 되어 있는지 확인한다.
        • Thonny IDE의 Python shell 창에 prompt( >>> )가 출력되었는 확인한다.
        • 위 프로그램을 복사하여 Thonny IDE의 Script 편집 창에 복사한다.
        • Script 편집 창의 프로그램을 File name "pulse_width_measure_utime_tick.py"로 저장 한다.
        • 실험
          • "실행 -> 현재 스크립트 실행"을 실행하거나 Toolbar의 "실행" Icon을 클릭하면 스크립트가 개발보드에 전송되고 프로그램이 실행된다.
          • 콘솔 창에 측정값이 1초 간격으로 출력된다. GPIO4 버튼을 누르면 펄스폭이 증가하고, GPIO5 버튼을 누르면 펄스폭이 감소한다.

          주: Callback function를 이용하여 측정을 실행하기 때문에 250uSec 이하의 펄스 폭을 측정하는 것은 어렵다. 펄스 폭 측정이 목적인 경우 time_pulse_us() 함수를 이용하기 바람.

    • DC Motor를 이용한 Event counting과 Pulse width 측정
      • 실험에서 기대하는 목표
        • PWM을 이용한 전력제어(이 예에서는 DC Motor의 속도 제어에 이용 함)
        • DC Motor의 속도에 비례한 Event(Pulse) 신호 발생
        • 모터 속도 측정은 아래와 같이 Event(Pulse) 신호를 Counting 하는 방법과 신호의 Pulse width 측정하는 두가지 방법으로 실행한다.
          • Event(Pulse) 신호 Counting: 일정한 시간 동안 발생한 Event를 counting
          • Event(Pulse) 신호의 Pulse width 측정: 현재 센서에서 다음 센서 까지 도달하는 시간이 펄스 폭으로 측정 된다.

        Event counting과 Pulse width 측정을 위한 시스텀 구성

        Motor speed detector 회로 예(LED는 Hall sensor의 동작을 확인하기 위한 것임. LED를 사용하지 않는 경우에는 LED를 제거하고 330Ω 저항을 VCC에 따라 2K - 5K 사이의 저항으로 변경한다.)

      • DC Motor를 이용한 Pulse width 측정(Motor 속도 측정) 프로그램 예: dc_motor_speed_pulse_width.py
        • 실험을 위한 회로 구성
          • GPIO2: PWM Output, DC Motor 제어기 입력신호(En 신호)를 연결한다.
          • GPIO16: Pulse 폭 측정 입력 Pin, Motor speed detector의 Output(Hall Sensor(WSH131)의 Output)를 연결 한다.
          • GPIO4: Motor speed up Button를 연결한다.
          • GPIO5: Motor speed down Button를 연결한다.
        • 실험 방법
          • "dc_motor_speed_pulse_width.py" 프로그램 파일을 Download하여 저장한다.
          • Thonny IDE를 실행하고 Thonny IDE의 사용 환경(Thonny 실행에 사용할 장치와 COM Port 선택)이 바르게 되어 있는지 확인한다.
          • Thonny IDE의 Python shell 창에 prompt( >>> )가 출력되었는 확인한다.
          • Thonny IDE의 "파일 -> 열기"를 실행하여 dc_motor_speed_pulse_width.py 파일을 Open 한다.
          • 실험
            • "실행 -> 현재 스크립트 실행"을 실행하거나 Toolbar의 "실행" Icon을 클릭하면 스크립트가 개발보드에 전송되고 프로그램이 실행된다.
            • 프로그램 전송이 종료되면 Python shell 창에 prompt( >>> )가 출력되고, 콘솔 창에 측정 결과 1초 간격으로 출력된다.
              • pulseWidthUsec: uSec 단위로 측정된 Pulse Width.
              • eventCounter: 1 Sec 동안 Count한 Event 수
            • GPIO4 버튼을 누르면 Motor speed 가 빨라지고, GPIO5 버튼을 누르면 Motor speed 가 느려진다.
            • 실행 중인 프로그램 정지하기: Toolbar의 "Stop" Icon을 클릭하면 프로그램이 종료된다.

            주: 측정 결과는 실험 장치의 정밀도와 Bouncing 현상 등의 영향으로 오차가 발생할 수 있다.


      • Pulse width 측정 기술을 이용한 초음파 거리 센서(HC-SR04) 예

  • ESP8266/ESP32 Timer 관련 페이지 보기