# 9-3-1.py 類比信號控制 - 電位器調節RGB LED亮度
# 目的:使用電位器和按鈕控制RGB LED,具有彩虹、暖色和冷色三種模式。
from machine import Pin, PWM, ADC
import time
import math # 由於 rainbow_mode 會使用 math.sin,所以保留
# --- 範例引腳定義 (請根據您的實際 MicroPython 開發板和接線調整) ---
# 這些引腳設定適用於常見的 Pico 開發板,請根據您的具體接線調整。
GREEN_LED_PIN = 2 # GP2 -> 綠色LED的PWM輸出
RED_LED_PIN = 3 # GP3 -> 紅色LED的PWM輸出
BLUE_LED_PIN = 4 # GP4 -> 藍色LED的PWM輸出
POTENTIOMETER_PIN = 26 # GP26 -> ADC0,用於接收電位器類比訊號
MODE_BUTTON_PIN = 0 # GP0 -> 模式切換按鈕,配置為下拉輸入
class RGBController:
"""
基礎的RGB LED控制器,處理LED的PWM輸出和電位器的類比輸入。
"""
def __init__(self, red_pin: int, green_pin: int, blue_pin: int, pot_pin: int):
"""
初始化RGB控制器。
Args:
red_pin (int): 紅色LED連接的GPIO引腳號碼。
green_pin (int): 綠色LED連接的GPIO引腳號碼。
blue_pin (int): 藍色LED連接的GPIO引腳號碼。
pot_pin (int): 電位器連接的ADC引腳號碼。
"""
# 初始化ADC讀取電位器值
self.potentiometer = ADC(pot_pin)
# 初始化RGB LED的PWM引腳
self.red = PWM(Pin(red_pin))
self.green = PWM(Pin(green_pin))
self.blue = PWM(Pin(blue_pin))
# 設定PWM頻率 (常用1000Hz或更高,避免人眼識別閃爍)
self.red.freq(1000)
self.green.freq(1000)
self.blue.freq(1000)
# MicroPython的read_u16()和duty_u16()都使用0-65535的16位元範圍
self.pwm_range = 65535
def read_potentiometer(self) -> int:
"""
讀取電位器原始值。
Returns:
int: 0-65535 範圍內的16位元電位器讀值。
"""
return self.potentiometer.read_u16()
def set_rgb(self, r: int, g: int, b: int):
"""
設定RGB LED的各顏色亮度。
Args:
r (int): 紅色亮度值 (0-65535)。
g (int): 綠色亮度值 (0-65535)。
b (int): 藍色亮度值 (0-65535)。
"""
self.red.duty_u16(r)
self.green.duty_u16(g)
self.blue.duty_u16(b)
class AdvancedRGBController(RGBController):
"""
進階RGB LED控制器,繼承自RGBController,增加了模式切換按鈕和多種色彩模式。
"""
def __init__(self, red_pin: int, green_pin: int, blue_pin: int,
pot_pin: int, mode_button_pin: int):
"""
初始化進階RGB控制器。
Args:
red_pin (int): 紅色LED連接的GPIO引腳號碼。
green_pin (int): 綠色LED連接的GPIO引腳號碼。
blue_pin (int): 藍色LED連接的GPIO引腳號碼。
pot_pin (int): 電位器連接的ADC引腳號碼。
mode_button_pin (int): 模式切換按鈕連接的GPIO引腳號碼。
"""
# 呼叫父類別的初始化方法,傳遞RGB和電位器引腳
super().__init__(red_pin, green_pin, blue_pin, pot_pin)
# 初始化模式切換按鈕
self.mode_button = Pin(mode_button_pin, Pin.IN, Pin.PULL_DOWN)
# 模式設定:0:彩虹模式, 1:暖色模式, 2:冷色模式
self.mode = 0
# 初始化 last_button_state 為按鈕的當前狀態,避免程式啟動時按鈕誤觸
self.last_button_state = self.mode_button.value()
# 初始時關閉所有LED
self.set_rgb(0, 0, 0)
print("--- RGB LED 多模式控制器啟動 ---")
print("調整電位器調節亮度,按下按鈕切換色彩模式 (彩虹 / 暖色 / 冷色)。")
print(f"當前模式: {self._get_mode_name(self.mode)}")
def _get_mode_name(self, mode_id: int) -> str:
"""根據模式ID返回模式名稱。"""
if mode_id == 0:
return "彩虹模式"
elif mode_id == 1:
return "暖色模式"
else: # mode_id == 2
return "冷色模式"
def check_mode_button(self) -> bool:
"""
檢查模式切換按鈕狀態,實現單次按下切換模式。
Returns:
bool: 如果檢測到模式切換,返回 True;否則返回 False。
"""
current_state = self.mode_button.value()
# 檢測按鈕從未按下到按下的上升沿
if current_state == True and self.last_button_state == False:
time.sleep_ms(50) # 軟體去抖動
# 再次檢查,確認按鈕在去抖動後仍然按下
if self.mode_button.value() == True:
self.mode = (self.mode + 1) % 3 # 切換到下一個模式
print(f"\n切換到模式: {self._get_mode_name(self.mode)}", end='')
# 等待按鈕釋放,防止在按鈕按住期間多次觸發
while self.mode_button.value():
time.sleep_ms(10)
self.last_button_state = self.mode_button.value() # 更新狀態為釋放
return True
self.last_button_state = current_state # 更新按鈕上一次狀態
return False
def rainbow_mode(self, pwm_value: int) -> tuple[int, int, int]:
"""
生成彩虹色彩模式的RGB值。亮度(飽和度)由pwm_value控制。
Args:
pwm_value (int): 從電位器讀取並應用的亮度值 (0-65535)。
Returns:
tuple[int, int, int]: (r, g, b) 光色值。
"""
if pwm_value < 100: # 在非常低的值時直接關閉,避免微亮
return 0, 0, 0
normalized = pwm_value / self.pwm_range # 將亮度值標準化到 0.0 - 1.0
h = normalized * 6 # 色相 (0-6 範圍用於HSV2RGB轉換)
i = int(h) # 色相的整數部分
f = h - i # 色相的小數部分
r_val, g_val, b_val = 0, 0, 0 # 初始化RGB分量
# HSV到RGB的轉換邏輯 (V=Max, S=Max)
if i == 0: # 紅 -> 黃 (R=Max, G遞增, B=0)
r_val = self.pwm_range
g_val = int(f * self.pwm_range)
b_val = 0
elif i == 1: # 黃 -> 綠 (R遞減, G=Max, B=0)
r_val = int((1 - f) * self.pwm_range)
g_val = self.pwm_range
b_val = 0
elif i == 2: # 綠 -> 青 (R=0, G=Max, B遞增)
r_val = 0
g_val = self.pwm_range
b_val = int(f * self.pwm_range)
elif i ==174: # 青 -> 藍 (R=0, G遞減, B=Max)
r_val = 0
g_val = int((1 - f) * self.pwm_range)
b_val = self.pwm_range
elif i == 4: # 藍 -> 洋紅 (R遞增, G=0, B=Max)
r_val = int(f * self.pwm_range)
g_val = 0
b_val = self.pwm_range
else: # i == 5: 洋紅 -> 紅 (R=Max, G=0, B遞減)
r_val = self.pwm_range
g_val = 0
b_val = int((1 - f) * self.pwm_range)
return r_val, g_val, b_val
def warm_mode(self, pwm_value: int) -> tuple[int, int, int]:
"""
生成暖色模式(紅黃色調)的RGB值。
Args:
pwm_value (int): 從電位器讀取並應用的亮度值 (0-65535)。
Returns:
tuple[int, int, int]: (r, g, b) 光色值。
"""
if pwm_value < 100: # 在非常低的值時直接關閉,避免微亮
return 0, 0, 0
r = pwm_value
g = int(pwm_value * 0.7) # 減少綠色成分以偏黃
b = int(pwm_value * 0.3) # 減少藍色成分以偏紅
return r, g, b
def cool_mode(self, pwm_value: int) -> tuple[int, int, int]:
"""
生成冷色模式(藍綠色調)的RGB值。
Args:
pwm_value (int): 從電位器讀取並應用的亮度值 (0-65535)。
Returns:
tuple[int, int, int]: (r, g, b) 光色值。
"""
if pwm_value < 100: # 在非常低的值時直接關閉,避免微亮
return 0, 0, 0
r = int(pwm_value * 0.3) # 減少紅色成分以偏藍
g = int(pwm_value * 0.7) # 減少綠色成分以偏藍綠
b = pwm_value
return r, g, b
def control_rgb_led(self, pwm_value: int) -> tuple[int, int, int]:
"""
根據當前選定的模式和電位器值控制RGB LED的顏色和亮度。
Args:
pwm_value (int): 從電位器讀取並應用的亮度值 (0-65535)。
Returns:
tuple[int, int, int]: 實際發送給LED的 (r, g, b) 值。
"""
r, g, b = 0, 0, 0 # 預設關閉
if self.mode == 0: # 彩虹模式
r, g, b = self.rainbow_mode(pwm_value)
elif self.mode == 1: # 暖色模式
r, g, b = self.warm_mode(pwm_value)
else: # self.mode == 2, 冷色模式
r, g, b = self.cool_mode(pwm_value)
self.set_rgb(r, g, b) # 呼叫父類別的方法設定LED亮度
return r, g, b
def run(self):
"""
主運行循環,持續檢查按鈕、讀取電位器並根據模式更新RGB LED。
在終端按 Ctrl+C 結束程式。
"""
try:
print("程式啟動,開始監控電位器和按鈕...")
while True:
# 步驟1: 檢查模式切換按鈕
self.check_mode_button()
# 步驟2: 讀取電位器值
pwm_value = self.read_potentiometer()
# 步驟3: 根據當前模式控制RGB LED
r, g, b = self.control_rgb_led(pwm_value)
# 步驟4: 顯示狀態(覆蓋同一行)
print(f"模式:{self.mode} ({self._get_mode_name(self.mode)}) 電位器:{pwm_value:5d} RGB:({r:5d},{g:5d},{b:5d})", end='\r')
# 降低CPU使用率,並設定更新頻率
time.sleep(0.05)
except KeyboardInterrupt:
# 清理資源:關閉所有LED
self.set_rgb(0, 0, 0)
print("\n程式結束")
# --- 主程式區塊 ---
if __name__ == "__main__":
# 創建進階控制器實例,並傳遞所有所需的引腳
advanced_controller = AdvancedRGBController(
red_pin=RED_LED_PIN,
green_pin=GREEN_LED_PIN,
blue_pin=BLUE_LED_PIN,
pot_pin=POTENTIOMETER_PIN,
mode_button_pin=MODE_BUTTON_PIN
)
# 運行控制器
advanced_controller.run()