Skip to content

Instantly share code, notes, and snippets.

@aphlysia
Last active Oct 1, 2020
Embed
What would you like to do?
'''
micro:bit の 25 分タイマー
使い方
A ボタンを押すとタイマーがスタート。
タイマーが動いているときに A を押すと一時停止する。
一時停止から復帰するには A を押す。
一時停止中に B を押すと、リセット。
更新内容
リセットした状態で sleep になってから B を押しても描画がリセットされない問題を修正。
'''
from microbit import *
import utime
height = 5
width = 5
goal_t = 25 * 60 # [s]
sleep_t = 5 * 60 # [s]
dt = 0.1 # 処理間隔 [s]
led_update_interval = 5 # dt をこの回数繰り返すと LED を更新
off_level = '0' # LED 消灯の強度
debug = False
def update_LED(start_time, image, on_level, force=False):
now = utime.ticks_ms()
t = utime.ticks_diff(now, start_time) / 1000
if t >= goal_t:
image = off_level * (height * width)
else:
m = int(t // 60)
i = m # 今の[分]を表す画像の位置
c = on_level if (force or image[i] == off_level) else off_level # 今の[分]を点滅
if i > 0:
image = image[:i-1] + off_level + c + image[i+1:]
else:
image = image[:i] + c + image[i+1:]
show_image(image)
return image
def show_image(image):
img = ':'.join([image[i*width: i*width+width] for i in range(width)]) # width 毎に : を加える
display.show(Image(img))
class Timer:
STOP = 0
WORKING = 1
SUSPENDING = 2
DONE = 3
def __init__(self):
self.reset()
def reset(self):
self.update_on_level()
self.image = self.initial_image()
self.start_time = utime.ticks_ms()
self.count = 0
self.status = self.STOP
self.blink_status = 0
self.sleep = False
self.show()
def update_on_level(self):
# 周囲の明るさに合わせて光らせる強さを調整する
self.on_level = str(round(display.read_light_level() * 4 / 255 + 5))
def initial_image(self):
return self.on_level * (height * width)
def start(self):
if self.status == self.DONE:
self.reset()
elif self.status != self.STOP: return
if self.sleep:
'''
sleep 時はここで明るさを調整。
そうでないときは直前の reset 時に取得した明るさを使う。
そうしている理由は、タイマースタート時に LED が一瞬消えるのを防ぐため。
(明るさを取得するときに一瞬 LED が消える)
'''
self.update_on_level()
self.image = self.initial_image()
self.start_time = utime.ticks_ms()
self.status = self.WORKING
self.show()
def suspend(self):
if self.status != self.WORKING: return
self.status = self.SUSPENDING
self.count = 0
self.blink_status = 0
self.suspend_start_time = utime.ticks_ms()
self.suspend_image = update_LED(self.start_time, self.image, self.on_level, force=True)
def restart(self):
if self.status != self.SUSPENDING: return
now = utime.ticks_ms()
diff = utime.ticks_diff(now, self.suspend_start_time)
self.start_time = utime.ticks_add(self.start_time, diff)
self.status = self.WORKING
def show(self):
show_image(self.image)
def tick(self):
if self.status == self.STOP and self.sleep == False:
now = utime.ticks_ms()
t = utime.ticks_diff(now, self.start_time) / 1000
if t >= sleep_t:
self.sleep = True
display.clear()
if self.status == self.WORKING:
self.count += 1
if self.count == led_update_interval:
# LED を更新
self.image = update_LED(self.start_time, self.image, self.on_level)
self.count = 0
now = utime.ticks_ms()
t = utime.ticks_diff(now, self.start_time) / 1000
if t >= goal_t:
self.status = self.DONE
display.clear()
elif self.status == self.SUSPENDING:
# 一時停止中は全体を点滅
self.count += 1
if self.count == led_update_interval:
# LED を更新
if self.blink_status == 0:
display.clear()
self.blink_status = 1
else:
show_image(self.suspend_image)
self.blink_status = 0
self.count = 0
timer = Timer()
while True:
# ボタン操作
n_a = button_a.get_presses()
n_b = button_b.get_presses()
if n_a > 0 and n_b > 0 and timer.status == timer.WORKING:
if debug:
# 最後の 10 秒へ飛ばす
timer.image = off_level * 24 + timer.on_level
diff = (24 * 60 + 50) * 1000
now = utime.ticks_ms()
timer.start_time = utime.ticks_add(now, -diff)
elif n_a > 0 and n_b == 0:
'''
停止中またはタイマーが終了した後にボタンAを押すと、タイマーを作動。
タイマーが作動中にボタンAを押すと、一時停止 (タイマーが進まなくなる)。
一時停止中にボタンAを押すと、作動中に戻す。
'''
if timer.status in (timer.STOP, timer.DONE):
timer.start()
elif timer.status == timer.WORKING:
timer.suspend()
else:
timer.restart()
elif n_a == 0 and n_b > 0 and (
timer.status in (timer.SUSPENDING, timer.DONE, timer.STOP)):
'''
一時停止中またはタイマーが終了した後にボタンBを押したらリセット
'''
timer.reset()
timer.tick()
sleep(int(dt * 1000))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment