from machine import Pin, I2C, Timer
import ssd1306
import font_bitmap
# 字體列表
font_list = [font_bitmap.font_HunInn, font_bitmap.font_Kai, font_bitmap.font_Li, font_bitmap.font_NSansTC_L, font_bitmap.font_NSerifTC_EB, font_bitmap.font_NSerifTC_M]
font_index = 0
# 設定字元間隔
line_spacing = 8 # 行與行之間的上下間隔
char_spacing = 0 # 字元與字元之間的左右間隔
# 根據 bitmap 決定應該點亮哪些像素
def draw_bitmap(oled, x, y, bitmap, width, height):
# 遍歷 bitmap 的每一行 (y 方向)
for j in range(height):
# 遍歷 bitmap 的每一列 (x 方向)
for i in range(width):
# 根據行與列位置,取出 bitmap 中對應的 byte
byte = bitmap[j * (width // 8) + (i // 8)]
# 從 byte 中提取出對應的 bit,確認該像素是否發亮
bit = (byte >> (7 - (i % 8))) & 1
# 設定該像素的亮暗狀態
oled.pixel(x + i, y + j, bit)
# 顯示一個字符在 OLED 上,並自動處理半形和全形
def display_chinese_char(oled, x, y, char, font):
if char == '\n':
return "newline" # 偵測到換行符,回傳換行訊息
# 判斷是否為半形字元(空格與數字)
half_width = char == ' ' or char.isdigit()
width = 8 if half_width else 16
height = 16
bitmap = font.get(char)
if bitmap:
draw_bitmap(oled, x, y, bitmap, width, height)
oled.show()
return width + char_spacing # 回傳寬度以便計算下個字元位置
else:
print(f"字元 '{char}' 的點陣圖資料不存在")
return 0 # 如果找不到字元,回傳 0
# 初始化按鈕
button = Pin(19, Pin.IN, Pin.PULL_UP) # 按鈕接在 GPIO 19
button_debounced = False # 去彈跳 flag
# ESP32 Pin assignment
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
oled.fill(0)
# 初始化 Timer
timer = Timer(0)
def button_callback(timer):
global font_index, button_debounced
if button.value() == 0 and not button_debounced: # 檢查按鈕是否按下且沒有去抖動
font_index = (font_index + 1) % len(font_list) # 切換字型
display_text(oled, font_list[font_index]) # 顯示當前字型的內容
button_debounced = True # 設置去彈跳 flag
elif button.value() == 1: # 當按鈕釋放時重置 flag
button_debounced = False
# 中斷設定
button.irq(trigger=Pin.IRQ_FALLING, handler=lambda pin: timer.init(mode=Timer.ONE_SHOT, period=100, callback=button_callback))
# 定義顯示文字的函數
def display_text(oled, font):
oled.fill(0)
current_x, current_y = 0, 0 # 追蹤 OLED 上的位置
line_height = 16 # 每行高度
text = "姓名 黃宥書\n系級 材料四" # 要顯示的字串
for char in text:
if char == '\n':
current_x = 0 # 換行後重置 x
current_y += line_height + line_spacing # 移到下一行,上下行間隔 8 像素
if current_y >= 64: # 如果到達螢幕底部,跳出
break
continue
# 顯示字符並取得字符寬度
width = display_chinese_char(oled, current_x, current_y, char, font)
# 更新 x 座標
current_x += width
if current_x >= 128: # 如果 x 超出螢幕寬度,換行
current_x = 0
current_y += line_height + line_spacing
if current_y >= 64: # 如果到達螢幕底部,跳出
break
# 顯示所有文字
oled.show()
# 初次顯示
display_text(oled, font_list[font_index])