3.2. 타이밍¶
time 모듈은 잠자기(스크립트를 알려진 시간 동안 일시 정지) 및 어떤 작업이 얼마나 걸리는지 측정하는 함수들을 한데 묶습니다. 마이크로컨트롤러에서 이것들은 있으면 좋은 정도가 아니라, 스크립트가 바깥 세계와의 상호작용 속도를 조절하는 방법 그 자체입니다. 핀을 얼마나 오래 하이로 유지할지, 샘플 사이를 얼마나 기다릴지, 버튼이 마지막으로 눌린 지 얼마나 지났는지 같은 것들 말입니다.
3.2.1. 잠자기¶
세 가지 잠자기 함수가 요청한 시간 동안 스크립트를 블로킹합니다:
time.sleep(s)–s초 동안 일시 정지. 부동소수점을 받으므로time.sleep(0.5)는 0.5초를 기다립니다.time.sleep_ms(ms)–ms밀리초 동안 일시 정지. 인수는 정수여야 합니다.time.sleep_us(us)–us마이크로초 동안 일시 정지.
import time
print("now")
time.sleep_ms(500)
print("half a second later")
일반적인 “잠깐 기다리기” 용도에는 time.sleep_ms() 를 쓰고, 타이밍이 빡빡해야 할 때만 time.sleep_us() 를 쓰십시오. 평범한 time.sleep() 도 괜찮지만, 정수 인수 변형은 부동소수점 변환을 피하고 짧은 간격에 더 자연스럽게 읽힙니다.
잠자기는 블로킹 호출입니다. 스크립트가 잠자는 동안에는 다른 어떤 일도 하지 않습니다 – 핀을 읽지도, UART를 처리하지도, LED를 갱신하지도 않습니다. 블로킹이 원하는 동작일 때 sleep 을 사용하고, 그렇지 않을 때는 아래의 논블로킹 패턴을 사용하십시오.
3.2.2. 클럭 읽기¶
코드 한 조각이 얼마나 걸리는지 측정하려면, 전후로 클럭을 읽으십시오:
time.ticks_ms()– 밀리초 단위의 현재 틱 값.time.ticks_us()– 마이크로초 단위의 같은 값.
import time
start = time.ticks_ms()
do_work()
elapsed = time.ticks_ms() - start
print("took", elapsed, "ms")
이 방법은 대부분의 경우 동작합니다. 틱 카운터는 크지만 유한한 틱 수 후에 롤오버(0으로 되돌아감)되며, 그 롤오버를 가로지른 단순한 뺄셈은 엉뚱하게 잘못된 음수나 양수를 만들어냅니다.
틱 카운터는 정수 한계에 도달하면 0으로 되돌아갑니다. 그 래핑을 가로지른 단순한 뺄셈은 잘못된 값을 냅니다.¶
3.2.3. ticks_diff¶
래핑을 가로질러서도 경과한 틱을 올바르게 구하려면 time.ticks_diff() 를 사용하십시오:
import time
start = time.ticks_ms()
do_work()
elapsed = time.ticks_diff(time.ticks_ms(), start)
print("took", elapsed, "ms")
인수 순서는 ticks_diff(later, earlier) 입니다 – 이 식은 “later 가 earlier 보다 얼마나 뒤인가”로 읽힙니다. 결과는 부호 있는 정수로, 양수는 later 가 실제로 더 뒤임을, 음수는 과거임을 뜻합니다. 함수는 래핑을 내부적으로 처리합니다.
팁
항상 time.ticks_ms() / time.ticks_us() 를 time.ticks_diff() 와 짝지어 쓰십시오. 원시 뺄셈은 대부분의 경우 올바르며, 잘못되는 시점은 스크립트가 오랫동안 실행되었을 때입니다 – 보통 타이밍 결함을 디버깅하기 가장 어려운 때이죠.
3.2.4. 논블로킹 타이밍¶
마이크로컨트롤러 스크립트는 보통 “동시에” 해야 할 일이 둘 이상 있습니다. 버튼 읽기, LED 깜빡이기, 센서 폴링, UART 처리 등이죠. sleep 은 그런 데 적합하지 않습니다 – 하나의 sleep 이 실행되는 동안 다른 작업들은 멈춰 있게 됩니다.
표준 패턴은 작업마다 데드라인을 두고, 매 루프마다 데드라인이 지났는지 확인하는 것입니다. 행동할지에 대한 결정은 sleep 이 아니라 항상 time.ticks_diff() 위에 세워집니다:
import time
next_blink = time.ticks_ms()
next_poll = time.ticks_ms()
state = False
while True:
now = time.ticks_ms()
if time.ticks_diff(now, next_blink) >= 0:
state = not state
# update LED here
next_blink = time.ticks_add(next_blink, 500)
if time.ticks_diff(now, next_poll) >= 0:
# read sensor here
next_poll = time.ticks_add(next_poll, 100)
LED는 500 ms마다 토글되고 센서는 100 ms마다 폴링되며, 두 작업 어느 쪽도 다른 쪽을 블로킹하지 않습니다. time.ticks_add() 는 래핑에 걸려 넘어지지 않으면서 알려진 증분만큼 데드라인을 전진시킵니다.
이 형태 – 단일 루프, 여러 타이밍 작업, 본문에 sleep 없음 – 는 하드웨어 코드가 가는 곳마다 등장합니다. 스위치의 소프트웨어 디바운싱, 모터 시퀀싱, UART 읽기 타임아웃 등에서요. 동일한 세 함수(time.ticks_ms(), time.ticks_diff(), time.ticks_add())가 모든 경우를 다룹니다.