-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path09_combined_example.py
More file actions
162 lines (140 loc) · 6.15 KB
/
Copy path09_combined_example.py
File metadata and controls
162 lines (140 loc) · 6.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# ==============================================================================
# 09_combined_example.py - Integrated Titration Monitor
# ==============================================================================
# Week 1 Core: Combining LED + Button + TempSensor + Display
# Demonstrates "Composition" - combining multiple objects
# ==============================================================================
from machine import Pin, SPI
import time
import onewire
import ds18x20
from ili9341 import Display, color565
from xglcd_font import XglcdFont
# MicroPad firmware interop (no-op on standard MicroPython):
# release_tft() - yield the TFT SPI bus the firmware owns at boot
# stop_requested() - let the Student/Instructor app stop this script
# การทำงานร่วมกับเฟิร์มแวร์ MicroPad (ข้ามอย่างปลอดภัยบน MicroPython มาตรฐาน)
try:
from scilabpro import release_tft
except ImportError:
release_tft = None
try:
from scilabpro import stop_requested
except ImportError:
stop_requested = None
# Simplified inline classes (คลาสแบบย่อ)
class LED:
def __init__(self, pin):
self._pin = Pin(pin, Pin.OUT)
self._pin.value(0)
def on(self): self._pin.value(1)
def off(self): self._pin.value(0)
class Button:
def __init__(self, pin, debounce=200):
self._pin = Pin(pin, Pin.IN)
self._debounce = debounce
self._last = 0
self._was = False
def is_pressed(self):
now = time.ticks_ms()
active = self._pin.value() == 1
if active and not self._was and time.ticks_diff(now, self._last) > self._debounce:
self._last, self._was = now, True
return True
if not active: self._was = False
return False
class TempSensor:
def __init__(self, pin=16):
self._ds = ds18x20.DS18X20(onewire.OneWire(Pin(pin)))
roms = self._ds.scan()
if not roms: raise RuntimeError("DS18B20 not found!")
self._rom = roms[0]
def read(self):
self._ds.convert_temp()
time.sleep_ms(750)
return self._ds.read_temp(self._rom)
# Colors
WHITE, BLACK = color565(255,255,255), color565(0,0,0)
GREEN, RED = color565(0,255,0), color565(255,0,0)
YELLOW, BLUE = color565(255,255,0), color565(0,0,255)
# ==============================================================================
# Titration Monitor (ระบบติดตามการไทเทรชัน)
# ==============================================================================
class TitrationMonitor:
"""Simple titration monitor - shows temp, button toggles state, LEDs show status"""
def __init__(self):
print("Initializing Titration Monitor...")
self.led_green, self.led_red = LED(4), LED(2)
self.btn = Button(34)
try:
self.sensor = TempSensor(16)
self.sensor_ok = True
except RuntimeError:
print("Warning: No temp sensor")
self.sensor_ok = False
# ปลดจอ TFT จากเฟิร์มแวร์ MicroPad ก่อนสร้าง SPI ของเราเอง
# Yield the TFT from MicroPad firmware before creating our own SPI bus.
if release_tft is not None:
release_tft()
spi = SPI(1, baudrate=40000000, sck=Pin(14), mosi=Pin(13))
self.display = Display(spi, dc=Pin(27), cs=Pin(15), rst=Pin(0),
width=320, height=240, rotation=90)
# ฟอนต์อยู่ใน /workspace/fonts/ (CWD = /workspace บนเฟิร์มแวร์ MicroPad)
# Font lives in /workspace/fonts/ (CWD is /workspace on MicroPad firmware)
self.font = XglcdFont('fonts/EspressoDolce18x24.c', 18, 24)
self.running = False
print("Ready! Button 1 to toggle, Ctrl+C to exit")
def draw_ui(self):
self.display.clear()
self.display.fill_rectangle(0, 0, 320, 35, BLUE)
self.display.draw_text(60, 8, "Titration Monitor", self.font, WHITE)
self._draw_status()
def _draw_status(self):
self.display.fill_rectangle(0, 180, 320, 60, BLACK)
status, color = ("MONITORING", GREEN) if self.running else ("STOPPED", RED)
self.display.draw_text(100, 200, status, self.font, color)
def _draw_temp(self, temp):
self.display.fill_rectangle(50, 80, 220, 80, BLACK)
if temp:
self.display.draw_text(100, 100, f"{temp:.2f} C", self.font, GREEN)
self.display.draw_text(90, 130, f"({temp+273.15:.1f} K)", self.font, YELLOW)
else:
self.display.draw_text(80, 100, "No Sensor", self.font, RED)
def toggle(self):
self.running = not self.running
if self.running:
self.led_green.on(); self.led_red.off()
else:
self.led_green.off(); self.led_red.on()
self._draw_status()
def run(self):
self.draw_ui()
self.led_red.on() # Start stopped
last_update = 0
try:
while True:
if stop_requested is not None and stop_requested():
print("Stop requested by app")
break
if self.btn.is_pressed():
self.toggle()
now = time.ticks_ms()
if self.running and time.ticks_diff(now, last_update) > 2000:
last_update = now
temp = self.sensor.read() if self.sensor_ok else None
if temp: print(f"Temp: {temp:.2f} C")
self._draw_temp(temp)
time.sleep_ms(50)
except KeyboardInterrupt:
pass
def cleanup(self):
self.led_green.off(); self.led_red.off()
self.display.clear()
# ==============================================================================
if __name__ == "__main__":
monitor = TitrationMonitor()
try:
monitor.run()
finally:
monitor.cleanup()
print("Done!")