"""
AUTOMATED CYLINDER SYSTEM WITH RESET COUNTER
GREEN = EXTEND ONLY | RED = RETRACT ONLY
Tambah function untuk reset cycle counter
"""
from machine import Pin, I2C
import time
print("\n" + "="*60)
print("CYLINDER SYSTEM - WITH RESET COUNTER")
print("GREEN = EXTEND | RED = RETRACT")
print("="*60)
# ============================================
# 1. PIN SETUP
# ============================================
# Relay Control
relay = Pin(14, Pin.OUT) # GPIO14 → Relay
# LED Indicators
led_green = Pin(13, Pin.OUT) # GPIO13 → GREEN (EXTEND)
led_red = Pin(11, Pin.OUT) # GPIO11 → RED (RETRACT)
led_ready = Pin(10, Pin.OUT) # GPIO10 → YELLOW (READY)
# Buttons
start_btn = Pin(15, Pin.IN, Pin.PULL_UP) # START
estop_btn = Pin(12, Pin.IN, Pin.PULL_UP) # E-STOP
reset_btn = Pin(9, Pin.IN, Pin.PULL_UP) # RESET
# Initialize
relay.off()
led_green.off()
led_red.off()
led_ready.on()
print("✓ System initialized")
print(" Start: GPIO15, E-Stop: GPIO12, Reset: GPIO9")
# ============================================
# 2. LCD SETUP
# ============================================
lcd = None
try:
i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=100000)
devices = i2c.scan()
if devices:
class SimpleLCD:
def __init__(self, i2c, addr):
self.i2c = i2c
self.addr = addr
self.init()
def init(self):
cmds = [0x33, 0x32, 0x28, 0x0C, 0x06, 0x01]
for cmd in cmds:
self.write(cmd, 0)
time.sleep_ms(5)
def write(self, data, rs):
high = (data & 0xF0) | 0x04 | (rs & 0x01) | 0x08
self.i2c.writeto(self.addr, bytes([high]))
time.sleep_us(1)
self.i2c.writeto(self.addr, bytes([high & ~0x04]))
time.sleep_us(50)
low = ((data << 4) & 0xF0) | 0x04 | (rs & 0x01) | 0x08
self.i2c.writeto(self.addr, bytes([low]))
time.sleep_us(1)
self.i2c.writeto(self.addr, bytes([low & ~0x04]))
time.sleep_us(50)
def clear(self):
self.write(0x01, 0)
time.sleep_ms(2)
def print(self, line1="", line2=""):
self.clear()
if line1:
self.write(0x80, 0)
for char in line1[:16]:
self.write(ord(char), 1)
if line2:
self.write(0xC0, 0)
for char in line2[:16]:
self.write(ord(char), 1)
lcd = SimpleLCD(i2c, devices[0])
print(f"✓ LCD at 0x{devices[0]:02x}")
except:
print("✗ No LCD")
lcd = None
# ============================================
# 3. SYSTEM VARIABLES WITH COUNTER
# ============================================
TOTAL_CYCLES = 100 # Target cycles
CYCLE_ON_TIME = 2
CYCLE_OFF_TIME = 2
# System states
STATE_READY = 0
STATE_RUNNING = 1
STATE_EMERGENCY = 2
STATE_COMPLETE = 3
STATE_PAUSED = 4
# COUNTER VARIABLES - untuk reset
current_cycle = 0
cycle_target = TOTAL_CYCLES # Boleh diubah dengan reset
completed_cycles = 0 # Total cycles completed since last reset
system_state = STATE_READY
# ============================================
# 4. LED CONTROL FUNCTIONS
# ============================================
def show_extend():
led_green.on()
led_red.off()
led_ready.off()
def show_retract():
led_green.off()
led_red.on()
led_ready.off()
def show_ready():
led_green.off()
led_red.off()
led_ready.on()
def show_emergency():
led_green.off()
led_ready.off()
for _ in range(5):
led_red.on()
time.sleep(0.1)
led_red.off()
time.sleep(0.1)
led_red.on()
def show_paused():
# Blink green LED when paused
if int(time.time() * 2) % 2 == 0:
led_green.on()
else:
led_green.off()
led_red.off()
led_ready.off()
# ============================================
# 5. COUNTER RESET FUNCTIONS
# ============================================
def reset_counter_to(new_count):
"""Reset cycle counter to new value"""
global current_cycle, cycle_target, completed_cycles
print(f"\nResetting counter to {new_count} cycles")
if new_count > 0 and new_count <= 1000: # Limit max cycles
cycle_target = new_count
current_cycle = 0
completed_cycles = 0
if lcd:
lcd.print(f"SET TO {new_count}", "Cycles")
print(f" Counter reset: {cycle_target} cycles")
print(f" Current: {current_cycle}/{cycle_target}")
return True
print(" Error: Invalid cycle count")
return False
def reset_to_default():
"""Reset counter to default (100 cycles)"""
global cycle_target, current_cycle, completed_cycles
cycle_target = TOTAL_CYCLES
current_cycle = 0
completed_cycles = 0
print(f"\nCounter reset to default: {cycle_target} cycles")
if lcd:
lcd.print("RESET TO DEFAULT", f"{cycle_target} cycles")
return True
def increment_completed():
"""Increment completed cycles counter"""
global completed_cycles
completed_cycles += 1
print(f" Total completed: {completed_cycles} cycles")
def get_counter_status():
"""Get current counter status"""
return {
'current': current_cycle,
'target': cycle_target,
'completed': completed_cycles,
'progress': (current_cycle / cycle_target * 100) if cycle_target > 0 else 0
}
# ============================================
# 6. SYSTEM CONTROL FUNCTIONS
# ============================================
def emergency_stop():
"""Emergency stop"""
global system_state
print("\n!!! EMERGENCY STOP !!!")
relay.off()
system_state = STATE_EMERGENCY
show_emergency()
if lcd:
lcd.print("!!! EMERGENCY !!!", "Press RESET")
def reset_system():
"""Full system reset"""
global system_state, current_cycle
print("\n=== SYSTEM RESET ===")
relay.off()
system_state = STATE_READY
current_cycle = 0
show_ready()
# Show counter status
status = get_counter_status()
if lcd:
lcd.print("SYSTEM RESET", f"Target: {status['target']}")
print(f" System reset complete")
print(f" Target cycles: {status['target']}")
print(f" Total completed: {status['completed']}")
def reset_and_start(new_count=None):
"""Reset counter and start immediately"""
print("\n=== RESET & START ===")
if new_count:
reset_counter_to(new_count)
else:
reset_to_default()
time.sleep(1)
start_operation()
def pause_system():
"""Pause current operation"""
global system_state
if system_state == STATE_RUNNING:
print("\nSystem PAUSED")
system_state = STATE_PAUSED
relay.off()
show_paused()
if lcd:
status = get_counter_status()
lcd.print("SYSTEM PAUSED", f"Cycle: {status['current']}")
return True
return False
def resume_system():
"""Resume from pause"""
global system_state
if system_state == STATE_PAUSED:
print("\nResuming operation...")
system_state = STATE_RUNNING
if lcd:
status = get_counter_status()
lcd.print("RESUMING...", f"Cycle: {status['current']+1}")
return True
return False
# ============================================
# 7. MAIN OPERATION WITH COUNTER
# ============================================
def start_operation():
"""Start operation with current counter"""
global system_state, current_cycle
if system_state != STATE_READY:
print(f"Cannot start: System in state {system_state}")
return False
print(f"\n=== STARTING OPERATION ===")
status = get_counter_status()
print(f"Target cycles: {status['target']}")
print(f"Progress: {status['current']}/{status['target']}")
system_state = STATE_RUNNING
current_cycle = status['current'] # Start from current position
show_extend() # Initial state
if lcd:
lcd.print(f"RUNNING", f"0/{status['target']}")
# Run cycles
while current_cycle < status['target']:
if system_state != STATE_RUNNING:
break
current_cycle += 1
# Update display
if lcd and current_cycle % 10 == 0:
progress = int((current_cycle / status['target']) * 100)
lcd.print(f"Cycle: {current_cycle}", f"Progress: {progress}%")
# Check E-Stop
if estop_btn.value() == 0:
emergency_stop()
return False
# ===== EXTEND =====
print(f"Cycle {current_cycle}: EXTEND")
show_extend()
relay.on()
start_time = time.ticks_ms()
while time.ticks_diff(time.ticks_ms(), start_time) < CYCLE_ON_TIME * 1000:
if estop_btn.value() == 0:
relay.off()
emergency_stop()
return False
time.sleep(0.01)
# ===== RETRACT =====
print(f"Cycle {current_cycle}: RETRACT")
show_retract()
relay.off()
start_time = time.ticks_ms()
while time.ticks_diff(time.ticks_ms(), start_time) < CYCLE_OFF_TIME * 1000:
if estop_btn.value() == 0:
emergency_stop()
return False
time.sleep(0.01)
# COMPLETION
if current_cycle >= status['target']:
complete_operation()
return True
def complete_operation():
"""Complete operation sequence"""
global system_state, completed_cycles
print(f"\n=== OPERATION COMPLETE ===")
print(f"Completed {current_cycle} cycles")
system_state = STATE_COMPLETE
relay.off()
# Increment completed counter
increment_completed()
# Celebration
for _ in range(3):
show_extend()
time.sleep(0.2)
show_retract()
time.sleep(0.2)
show_ready()
status = get_counter_status()
if lcd:
lcd.print("COMPLETE!", f"Total: {status['completed']}")
time.sleep(3)
reset_system()
# ============================================
# 8. BUTTON HANDLING WITH SPECIAL FUNCTIONS
# ============================================
def handle_reset_button():
"""Handle reset button with special functions"""
print("\n=== RESET BUTTON PRESSED ===")
print("Options:")
print(" 1. Short press (< 1s): Normal reset")
print(" 2. Long press (1-3s): Reset counter to 50")
print(" 3. Very long press (> 3s): Reset counter to 10")
# Wait to see how long button is pressed
press_start = time.ticks_ms()
while reset_btn.value() == 0: # Button still pressed
time.sleep(0.1)
press_duration = time.ticks_diff(time.ticks_ms(), press_start)
if press_duration < 1000: # Short press
print(" Short press: Normal system reset")
reset_system()
elif press_duration < 3000: # Medium press (1-3s)
print(" Medium press: Reset to 50 cycles")
reset_counter_to(50)
else: # Long press (> 3s)
print(" Long press: Reset to 10 cycles")
reset_counter_to(10)
# ============================================
# 9. DISPLAY COUNTER STATUS
# ============================================
def display_counter_status():
"""Display current counter status on LCD"""
if not lcd:
return
status = get_counter_status()
lcd.print(f"Target: {status['target']}", f"Completed: {status['completed']}")
# ============================================
# 10. MAIN PROGRAM LOOP
# ============================================
print("\n" + "="*60)
print("SYSTEM WITH RESET COUNTER")
print("="*60)
print("RESET BUTTON FUNCTIONS:")
print(" Short press: Reset system")
print(" Press 1-3s: Set to 50 cycles")
print(" Press >3s: Set to 10 cycles")
print("\nPress START to begin")
# Initial display
if lcd:
display_counter_status()
time.sleep(2)
reset_system()
# Button states
last_start = 1
last_estop = 1
last_reset = 1
reset_pressed_time = 0
# Main loop
while True:
# ========== EMERGENCY STOP ==========
current_estop = estop_btn.value()
if last_estop == 1 and current_estop == 0:
time.sleep(0.05)
if estop_btn.value() == 0:
emergency_stop()
# ========== RESET BUTTON ==========
current_reset = reset_btn.value()
# Button pressed
if last_reset == 1 and current_reset == 0:
reset_pressed_time = time.ticks_ms()
# Button released
elif last_reset == 0 and current_reset == 1:
press_duration = time.ticks_diff(time.ticks_ms(), reset_pressed_time)
if press_duration > 50: # Debounce
handle_reset_button()
# ========== START BUTTON ==========
current_start = start_btn.value()
if last_start == 1 and current_start == 0:
time.sleep(0.05)
if start_btn.value() == 0:
if system_state == STATE_READY:
start_operation()
elif system_state == STATE_PAUSED:
resume_system()
elif system_state == STATE_RUNNING:
pause_system()
elif system_state == STATE_COMPLETE:
reset_and_start()
elif system_state == STATE_EMERGENCY:
print("Press RESET first")
# ========== UPDATE BUTTON STATES ==========
last_start = current_start
last_estop = current_estop
last_reset = current_reset
# ========== STATUS INDICATORS ==========
if system_state == STATE_READY:
if int(time.time()) % 2 == 0:
led_ready.on()
else:
led_ready.off()
elif system_state == STATE_RUNNING:
# No special indicator - LEDs controlled by cycle
pass
elif system_state == STATE_EMERGENCY:
if int(time.time() * 3) % 2 == 0:
led_red.on()
else:
led_red.off()
elif system_state == STATE_PAUSED:
show_paused()
# ========== UPDATE DISPLAY ==========
if lcd and int(time.time()) % 5 == 0: # Update every 5 seconds
if system_state == STATE_READY:
status = get_counter_status()
lcd.print(f"READY", f"Target: {status['target']}")
time.sleep(0.01)