from machine import Pin
import uasyncio as asyncio
STEP_PIN = Pin(18, Pin.OUT)
DIR_PIN = Pin(19, Pin.OUT)
EN_PIN = Pin(21, Pin.OUT)
BTN_PLUS = Pin(13, Pin.IN, Pin.PULL_UP) # +
BTN_MINUS = Pin(14, Pin.IN, Pin.PULL_UP) # -
BTN_OK = Pin(12, Pin.IN, Pin.PULL_UP) # OK
EN_PIN.value(1)
STEP_PIN.value(0)
DIR_PIN.value(1)
GRAMS_PER_ROTATION = 5
STEPS_PER_ROTATION = 533
MIN_DOSE_GRAMS = 5
MAX_DOSE_GRAMS = 100
motor_busy = False
async def read_button_async():
checks = [
(BTN_PLUS, 'plus'),
(BTN_MINUS, 'minus'),
(BTN_OK, 'ok'),
]
for pin, name in checks:
if pin.value() == 0:
await asyncio.sleep_ms(30)
if pin.value() == 0:
while pin.value() == 0:
await asyncio.sleep_ms(5)
await asyncio.sleep_ms(20)
return name
return None
async def rotate_one_portion(direction=1):
start_delay_ms = 8
min_delay_ms = 2
ramp_steps = 80
steps = STEPS_PER_ROTATION
EN_PIN.value(0)
DIR_PIN.value(direction)
await asyncio.sleep_ms(10)
for i in range(steps):
if i < ramp_steps:
ratio = i / ramp_steps
elif i > (steps - ramp_steps):
ratio = (steps - i) / ramp_steps
else:
ratio = 1.0
delay_ms = int(start_delay_ms - (start_delay_ms - min_delay_ms) * ratio)
half = max(1, delay_ms // 2)
STEP_PIN.value(1)
await asyncio.sleep_ms(half)
STEP_PIN.value(0)
await asyncio.sleep_ms(half)
EN_PIN.value(1)
await asyncio.sleep_ms(200)
def draw_dose(grams):
bar_max = 20
filled = int((grams - MIN_DOSE_GRAMS) /
(MAX_DOSE_GRAMS - MIN_DOSE_GRAMS) * bar_max)
bar = "[" + "#" * filled + "-" * (bar_max - filled) + "]"
print(" Dose : {:3d} g {}".format(grams, bar))
def draw_menu(grams):
print("\n=== Distributeur croquettes ===")
print(" [+] Augmenter [-] Diminuer [OK] Distribuer")
print("=" * 35)
draw_dose(grams)
async def main_task():
global motor_busy
grams = MIN_DOSE_GRAMS
draw_menu(grams)
while True:
btn = await read_button_async()
if btn == 'plus':
if motor_busy:
print(" ! Moteur occupé")
elif grams < MAX_DOSE_GRAMS:
grams += GRAMS_PER_ROTATION
draw_dose(grams)
else:
print(" ! Maximum {}g".format(MAX_DOSE_GRAMS))
elif btn == 'minus':
if motor_busy:
print(" ! Moteur occupé")
elif grams > MIN_DOSE_GRAMS:
grams -= GRAMS_PER_ROTATION
draw_dose(grams)
else:
print(" ! Minimum {}g".format(MIN_DOSE_GRAMS))
elif btn == 'ok':
if motor_busy:
print(" ! Distribution déjà en cours")
else:
motor_busy = True
rotations = grams // GRAMS_PER_ROTATION
print("\n >> {} g ({} rotations)".format(grams, rotations))
print(" " + "-" * 30)
for i in range(rotations):
print(" Rotation {}/{}... ".format(i + 1, rotations), end="")
await rotate_one_portion(direction=1)
print("{} g".format((i + 1) * GRAMS_PER_ROTATION))
print(" " + "-" * 30)
print(" OK ! {} g distribués\n".format(grams))
motor_busy = False
grams = MIN_DOSE_GRAMS
await asyncio.sleep_ms(500)
draw_menu(grams)
await asyncio.sleep_ms(10)
# ═════════════════════════════════════════════════════════════════════════════
# Point d'entrée
# ═════════════════════════════════════════════════════════════════════════════
try:
asyncio.run(main_task())
except KeyboardInterrupt:
EN_PIN.value(1) # sécurité : désactiver le driver
print("\nInterrompu — driver désactivé")