2026年2月12日 星期四

LG Gram 筆電書籤備份 20260212

LG Gram 筆電的瀏覽器頁籤不知不覺又超過 50 個, 耗掉蠻多記憶體的, 備份存參 :

Chrome : 
Edge :

蝦皮購買 ESP32-S3 CAM 開發板 x 2

因為之前買的三片 ESP32-S3 CAM 板子有兩片有問題 (一個照片不全, 一個 OTG 埠無反應), 所以在蝦皮找到另一個賣家環島科技買兩片來測試, 他們的板子似乎較長且布局與 Freenove 的不同, 價錢也較貴一些 :





明華店自取 860 元. 

MicroPython 學習筆記 : ESP32-S3 CAM 開發板鏡頭慢速測試程式

之前買的兩片 ESP32-S3 CAM 開發板的其中一片拍的照片, 前面看來正常, 但後面卻糊掉或變成馬賽克 (燒錄的韌體與使用的拍照的程式均相同), 甚至將解析度降至 QVGA 狀況依舊. 本來懷疑是鏡頭模組問題, 只要將兩片開發板的 ov2640 交換測試即知, 但鏡頭的排線很密很脆弱, 過度曲折可能造成內部電線斷裂, 連接座的間隙也是每拆卸排線一次就變大, 鏡頭裝上去沒必要就盡量不要拆.  






我把以上不良照片上傳給 Gemini 分析, 它認為鏡頭與感光元件 (CMOS) 都沒有壞, 問題可能出在排線 (Ribbon Cable) 或連接座, 因為如果鏡頭破了或感光元件燒了, 畫面會是全黑, 全白, 或是充滿雜訊點, 絕對不會只壞下面. 相機的排線非常脆弱, 輕微的震動都可能導致 D0-D7 數據線接觸不良, 建議將 ov2640 排線拆下來用橡皮擦清潔接點, 清完後用下列 "龜速診斷模式" 測試 : 

import camera
import time
import gc

# 1. 強制回收記憶體
gc.collect()

print("========================================")
print("🚀 Vibe Cam - 龜速診斷模式")
print("========================================")

try:
    # 2. 關閉舊的相機實體
    try:
        camera.deinit()
    except:
        pass
    time.sleep(1.0) # 讓電容放電

    # 3. 初始化:關鍵參數全開
    print("📷 初始化相機 (設定最保守參數)...")
    
    # 嘗試 Freenove 的標準初始化,但強制覆寫頻率
    try:
        # xclk_freq=10000000 (10MHz) -> 讓時脈變慢一半
        camera.init(0, format=camera.JPEG, framesize=camera.FRAME_QVGA, xclk_freq=10000000)
        print("   -> ✅ 頻率已降至 10MHz")
    except:
        print("   -> ⚠️ 韌體不支援降頻參數,使用預設值")
        camera.init()

    # 4. 畫質設定:最差畫質 (High Compression)
    # quality=63 (這是 OV2640 的極限,畫質最爛,但數據量最小)
    try:
        camera.quality(63)
        print("   -> 📉 畫質設定為 63 (最高壓縮/最小檔案)")
    except:
        pass

    # 5. 暖身 (給它多跳幾下)
    print("🔥 暖身中 (連拍 5 張)...")
    time.sleep(2.0)
    for i in range(5):
        try:
            camera.capture()
            time.sleep(0.2)
        except:
            pass

    # 6. 正式拍照
    print("📸 拍攝診斷照片...")
    gc.collect()
    
    buf = camera.capture()

    if buf and len(buf) > 0:
        print(f"📦 取得影像: {len(buf)} bytes")
        
        # 檢查檔案完整性
        valid = False
        if len(buf) > 2 and buf[0] == 0xFF and buf[1] == 0xD8 and buf[-2] == 0xFF and buf[-1] == 0xD9:
            valid = True
            print("   -> ✅ 標頭尾完整 (傳輸成功)")
        else:
            print(f"   -> ❌ 標頭尾殘缺 (傳輸中斷, 結尾: {hex(buf[-1])})")

        filename = "vibe_slow.jpg"
        with open(filename, "wb") as f:
            f.write(buf)
            
        print(f"💾 已儲存: {filename}")
        print("👉 請打開這張圖。如果連這張 QVGA+畫質最爛的照片都還有撕裂,")
        print("   那就代表鏡頭排線真的斷了。")
    else:
        print("❌ 拍照失敗 (無數據)")

    camera.deinit()

except Exception as e:
    print(f"❌ 錯誤: {e}")

但即使以 10MHz 龜速與 QVGA 超低畫質設定去拍, 問題還是一樣 : 




 
我的零件箱應該還有很久以前採購的 ov2640 模組, 等找出來後再測試看看. 上面 Gemini 提供的慢速測試程式留著備用. 


2026-02-13 補充 : 

晚上從之前買的 5 片 ESP32-CAM 中開啟一片, 取出其中的 ov2640 裝在懷疑有問題的第二片 ESP32-S3 CAM 上測試, 拍攝的照片正常 :




這證明編號 2 的開發板沒問題, 是 ov2640 模組有問題, 可能排線有斷裂受損. 

MicroPython 學習筆記 : ESP32-S3 CAM 開發板 OTG 與 UART 槽的差別

ESP32-S3 CAM 開發板有兩個 Type C USB 槽, 一個是 UART, 一個是 OTG, 最近幾天測試發現測試發現燒錄時要用 UART, 燒錄完需斷電重開機, 然後改插 OTG 槽, 這樣按 Thonny 的 "執行/重新啟動" 才會順利進入 MicroPython 環境, 如果用 UART 會一直顯示 "Wainting for Bootloader", 我問 Gemini 原因, 回覆整理如下 :
  • UART 槽 (COM Port / USB-to-TTL) : 
    它是透過一顆中介晶片 (通常是 CH343/CH340/CP210x) 來連接電腦與 ESP32 :
    電腦 USB訊號 <-> 轉換晶片 <-> ESP32 的 TX/RX 腳位
    此槽特點是硬體強制力強, 連接著 ESP32 的重置電路 (EN pin) 啟動模式腳位 (IO0), 它能透過電路訊號 (DTR/RTS) 強制把 ESP32 踢進下載模式 (Download Mode), 所以燒錄韌體時用它是最穩定的.
  • OTG 槽 (Native USB / USB Serial JTAG) : 
    它是直通 ESP32-S3 內部的 USB 控制器 :
    電腦 USB訊號 <-> ESP32-S3 (沒有中間人)
    它需要等 ESP32 內部的韌體  (如 MicroPython) 跑起來之後才能被電腦辨識, ESP32-S3 MicroPython 韌體預設會把 REPL (互動介面) 和模擬磁碟機指定給這個 OTG 端口. 
當燒錄好支援 ESP32-S3 的 MicroPython 韌體後, 韌體啟動時會把 Python 的輸出視窗 (REPL) 導向到 Native USB (OTG) 端口而不是 UART 端口. 所以插 OTG 的話 Thonny 就能直接透過 USB 協定跟 MicroPython 對話. 如果插 UART 端口, 當在 Thonny 按下 "停止/重啟" 時, Thonny 會試圖透過 USB 送出一個訊號重置開發板, 並透過那顆 USB 中介晶片去控制硬體的 DTR 和 RTS 腳位, 使開發板進入 "等待燒錄模式" 而卡在 "Waiting for Bootloader"; 而在 OTG 槽, 這個重置是 "軟體重置 (Soft Reboot)", 效果與按 Ctrl+D 一樣而進入 MicroPython 互動執行環境. 

2026年2月11日 星期三

MicroPython 學習筆記 : ESP32-S3 CAM 開發板測試 (三)

在前一篇測試中使用 cnadler86 提供的 ESP32-S3 CAM 韌體一直無法拍攝到正常完整的照片, 今天在 GitHub 上找到 shariltumin 的 repo, 發現裡面有 Gemini 強烈建議下載的 2022 年版韌體, 雖然是較舊的 MicroPython 1.20 版, 但能用才是王道, 於是下載來試試. 

本系列之前的測試文章參考 :


雖然 repo 的標題是 2022, 但 2023 年有更新, 我是下載 20230717 的韌體 firmware.bin : 





我將第一片燒錄到 GENERIC 那片板子拿來洗掉重燒 :

D:\ESP32-S3-CAM>esptool --chip esp32s3 --port COM4 erase_flash   
esptool.py v4.6.2
Serial port COM4
Connecting...................
Chip is ESP32-S3 (revision v0.2)
Features: WiFi, BLE
Crystal is 40MHz
MAC: e0:72:a1:d7:dd:d4
Uploading stub...
Running stub...
Stub running...
Erasing flash (this may take a while)...
Chip erase completed successfully in 4.6s
Hard resetting via RTS pin...

燒錄新版韌體 : 

D:\ESP32-S3-CAM>esptool --chip esp32s3 --port COM4 write_flash -z 0 firmware.bin   
esptool.py v4.6.2
Serial port COM4
Connecting........................
Chip is ESP32-S3 (revision v0.2)
Features: WiFi, BLE
Crystal is 40MHz
MAC: e0:72:a1:d7:dd:d4
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Flash will be erased from 0x00000000 to 0x00151fff...
Compressed 1383856 bytes to 913906...
Wrote 1383856 bytes (913906 compressed) at 0x00000000 in 79.8 seconds (effective 138.7 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

注意, 以上指令都需在下達出現 .... 時按住 BOOT 鍵才會生效. 燒錄完需拔掉 USB 斷電重開, 這樣 在 Thonny 按重新執行才能進入 Bootloader, 首先檢查 Flash 記憶體 : 

MicroPython v1.20.0-206-g33b403dfb-kaki5 on 2023-07-10; ESP32S3-FREENOVE OV2640 w/BLE (KAKI5) with ESP32-S3

>>> import esp   
>>> print(f"Flash 大小: {esp.flash_size() / 1024 / 1024:.2f} MB")    
Flash 大小: 8.00 MB

N16R8 應該有 16MB 才對, 卻只能用到 8MB, 因為作者在製作這個韌體時為了相容性, 將分割表 (Partition Table) 設定為 8MB 之故. 8MB 足夠存幾千張照片或寫幾萬行程式, 剩下的 8MB 雖然看得到吃不到, 但也完全不影響效能. 

接下來檢視 RAM 資訊 : 

>>> import micropython   
>>> micropython.mem_info()   
stack: 736 out of 15360
GC: total: 6408320, used: 12560, free: 6395760
 No. of 1-blocks: 282, 2-blocks: 36, max blk sz: 24, max free sz: 399722

GC 欄顯示有 6.4MB 的巨量 RAM, 與前一篇測試使用之韌體的 64K RAM 相比, 提升了 100 倍! 這對拍照與處理影像資料有如神助, 之前的綠色雜訊, 畫面撕裂, 與緩衝區溢位應該都會消失了. 

先執行下列程式檢視 Flash 記憶體與 camera 模組 :

import gc   
import camera
import micropython

# 分配記憶體與整理
gc.collect()

print("="*30)
print("🚀 N16R8 Vibe Check")
print("="*30)

# 1. 檢查 RAM (關鍵指標)
# N16R8 成功驅動後,這裡應該要顯示 4MB ~ 8MB 之間的數值
free_ram_mb = gc.mem_free() / 1024 / 1024
print(f"✅ 剩餘 RAM: {free_ram_mb:.2f} MB")

if free_ram_mb > 4:
    print("   -> 狀態:完美!Octal PSRAM 已啟用。")
else:
    print("   -> 警告:RAM 過少,可能燒錄成 Non-Octal 版本。")

# 2. 檢查 Camera 模組
try:
    print(f"✅ Camera 模組版本: {camera}")
    print("   -> 驅動載入成功。")
except Exception as e:
    print(f"❌ Camera 模組載入失敗: {e}")

print("="*30)

輸出結果顯示有 camera 模組且 8MB PSRAM 有啟動 :

==============================
🚀 N16R8 Vibe Check
==============================
✅ 剩餘 RAM: 6.11 MB
   -> 狀態:完美!Octal PSRAM 已啟用。
✅ Camera 模組版本: <module 'camera'>
   -> 驅動載入成功。
==============================

接下來執行下列程式拍照 :

import camera
import time
import gc

# 1. 啟動與設定 (使用 Freenove 預設值)
gc.collect()
camera.init() 
time.sleep(2.0) # 給相機一點時間適應光線

# 2. 拍照
buf = camera.capture() # 使用標準指令即可

# 3. 存檔
if buf:
    with open("photo.jpg", "wb") as f:
        f.write(buf)
    print("拍照成功!")

# 4. 關閉
camera.deinit()

執行結果 :

True
28679
拍照成功!
True

這時重新整理 Thonny 左側的開發板資料夾, 會出現一個 photo.jpg 檔, 將其下載到 PC, 點擊開啟圖檔檢視軟體, 已成功拍攝了一張 800X600 的 JPG 照片 : 





可見燒對韌體很重要, 雖然是 2023 年的版本, 且 MicroPython 是較舊的 v1.20, 但可以正常拍照就行. 上面的程式固定將拍攝的照片存成 photo.jpg 會蓋掉原檔案, 下面修正版則會自動編號為 photo_x.jpg :

import camera
import time
import os
import gc

# 1. 記憶體大掃除 (確保拍照順暢)
gc.collect()
print("========================================")
print("🚀 Vibe Cam - 22.0 純淨拍照版")
print(f"🧠 可用記憶體: {gc.mem_free() / 1024:.2f} KB")
print("========================================")

try:
    # 2. 初始化相機
    # Freenove 專用韌體不需要參數,它會自動載入正確設定
    print("📷 初始化相機...")
    camera.init()
    
    # 【關鍵技巧】等待白平衡與自動曝光穩定
    # 剛啟動的前幾秒畫面顏色可能會偏綠或偏暗,給它 2 秒適應光線
    print("🔥 暖身中 (等待光線穩定)...")
    time.sleep(2.0)

    # 3. 拍照
    print("📸 拍攝中...")
    # 使用標準指令,Sharil 韌體會自動處理 JPEG 編碼
    buf = camera.capture()

    if buf and len(buf) > 0:
        print(f"📦 取得影像: {len(buf)} bytes")
        
        # 4. 智慧存檔 (存入內部 Flash)
        # 自動尋找沒用過的檔名,避免覆蓋
        i = 0
        while True:
            filename = f"photo_{i}.jpg"
            try:
                # 嘗試取得檔案資訊,如果檔案存在就不報錯,繼續下一號
                os.stat(filename)
                i += 1
            except OSError:
                # 檔案不存在 (報錯 ENOENT),代表這個名字可以用!
                break
        
        # 寫入檔案
        with open(filename, "wb") as f:
            f.write(buf)
            
        print(f"💾 已儲存至內部空間: {filename}")
        print("🎉 成功!請在 Thonny 左側檔案欄按右鍵 -> Refresh (重新整理) 查看。")

    else:
        print("❌ 拍照失敗 (數據為空)")

    # 5. 釋放資源
    # 養成好習慣,拍完就釋放,避免下次啟動衝突
    camera.deinit()
    print("✅ 相機已釋放")

except Exception as e:
    print(f"❌ 發生錯誤: {e}")
    # 嘗試強制釋放
    try:
        camera.deinit()
    except:
        pass

print("========================================")

輸出結果 :

========================================
🚀 Vibe Cam - 22.0 純淨拍照版
🧠 可用記憶體: 6225.03 KB
========================================
📷 初始化相機...
True
🔥 暖身中 (等待光線穩定)...
📸 拍攝中...
📦 取得影像: 51852 bytes
51852
💾 已儲存至內部空間: photo_0.jpg
🎉 成功!請在 Thonny 左側檔案欄按右鍵 -> Refresh (重新整理) 查看。
True
✅ 相機已釋放
========================================



市圖還書 2 本 : 慢富 & 外匯交易圖表分析入門

本周市圖還書 2 本 :
這兩本書都被預約需還, No.1 河堤有書, 周二去借; No.2 排隊預約. 

MicroPython 學習筆記 : ESP32-S3 CAM 開發板測試 (二)

前一篇測試使用了 cnadler86 的 Generic 的韌體, 裡面沒有 camera 模組無法拍照, 本篇改下載燒錄檔名有 CAM 的韌體 : 





同樣解壓縮 zip 檔後用 esptool 燒錄到 ESP32-S3 CAM 中 (最好先卸除鏡頭) :

D:\ESP32>esptool --port COM5 flash_id   
esptool.py v4.6.2
Serial port COM5
Connecting..................................
Detecting chip type... ESP32-S3
Chip is ESP32-S3 (revision v0.2)
Features: WiFi, BLE
Crystal is 40MHz
MAC: e0:72:a1:d7:e0:38
Uploading stub...
Running stub...
Stub running...
Manufacturer: 68
Device: 4018
Detected flash size: 16MB
Flash type set in eFuse: quad (4 data lines)
Hard resetting via RTS pin...

D:\ESP32>esptool --chip esp32s3 --port COM5 erase_flash   
esptool.py v4.6.2
Serial port COM5
Connecting...................
Chip is ESP32-S3 (revision v0.2)
Features: WiFi, BLE
Crystal is 40MHz
MAC: e0:72:a1:d7:e0:38
Uploading stub...
Running stub...
Stub running...
Erasing flash (this may take a while)...
Chip erase completed successfully in 3.5s
Hard resetting via RTS pin...

D:\ESP32>esptool --chip esp32s3 --port COM5 write_flash -z 0 firmware.bin
esptool.py v4.6.2
Serial port COM5
Connecting..............
Chip is ESP32-S3 (revision v0.2)
Features: WiFi, BLE
Crystal is 40MHz
MAC: e0:72:a1:d7:e0:38
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Flash will be erased from 0x00000000 to 0x001dbfff...
Compressed 1948208 bytes to 1238683...
Wrote 1948208 bytes (1238683 compressed) at 0x00000000 in 108.5 seconds (effective 143.7 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

燒錄完需拔掉 USB 斷電重插, 這樣 Thonny 的 "執行/重新啟動" 才會 Boot 進去 : 

MicroPython v1.27.0-dirty on 2026-01-12; Generic ESP32S3 module with Octal-SPIRAM with ESP32S3
Type "help()" for more information.
>>> import esp   
>>> print(f"Flash 大小: {esp.flash_size() / 1024 / 1024:.2f} MB")   
Flash 大小: 16.00 MB  

用下列程式檢查記憶體與 camera 模組 : 

import gc   
import camera
import micropython

# 分配記憶體與整理
gc.collect()

print("="*30)
print("🚀 N16R8 Vibe Check")
print("="*30)

# 1. 檢查 RAM (關鍵指標)
# N16R8 成功驅動後,這裡應該要顯示 4MB ~ 8MB 之間的數值
free_ram_mb = gc.mem_free() / 1024 / 1024
print(f"✅ 剩餘 RAM: {free_ram_mb:.2f} MB")

if free_ram_mb > 4:
    print("   -> 狀態:完美!Octal PSRAM 已啟用。")
else:
    print("   -> 警告:RAM 過少,可能燒錄成 Non-Octal 版本。")

# 2. 檢查 Camera 模組
try:
    print(f"✅ Camera 模組版本: {camera}")
    print("   -> 驅動載入成功。")
except Exception as e:
    print(f"❌ Camera 模組載入失敗: {e}")

print("="*30)
==============================
🚀 N16R8 Vibe Check
==============================
✅ 剩餘 RAM: 7.93 MB
   -> 狀態:完美!Octal PSRAM 已啟用。
✅ Camera 模組版本: <module 'camera'>
   -> 驅動載入成功。
==============================

可見此韌體有 camera 模組, 且 8MB 的 PSRAM 可用, 這巨量的 RAM 讓拍照不會 Out of memory. 

但用下列 Gemini 提供的程式拍照卻有馬賽克 :

import camera
import time
import os
import gc

gc.collect()

print("========================================")
print("🚀 Vibe Cam - 最終勝利存檔版")
print("========================================")

cam = None
try:
    # 1. 啟動
    cam = camera.Camera()
    cam.init()
    time.sleep(0.5)

    # 2. 設定 (使用剛剛驗證成功的 Keyword 方式)
    try:
        cam.reconfigure(pixel_format=camera.PixelFormat.JPEG, frame_size=camera.FrameSize.VGA)
        print("✅ 格式設定成功 (JPEG/VGA)")
    except:
        pass # 已經設過了或失敗都沒關係,反正數據看起來是對的

    time.sleep(1.5) # 等待緩衝區穩定

    # 3. 拍照
    print("📸 拍攝中...")
    # 為了清空舊緩衝區,建議空拍一張
    try:
        cam.capture()
        time.sleep(0.1)
    except:
        pass
        
    buf = cam.capture()
    print(f"📦 取得數據: {len(buf)} bytes")

    # 4. 【關鍵】不做任何檢查,直接暴力存檔!
    filename = "vibe_victory.jpg"
    with open(filename, "wb") as f:
        f.write(buf)
        
    print(f"💾 已強制儲存至: {filename}")
    print("🎉 請立刻用 Thonny 下載這張照片,它絕對是好的!")
    
    # 5. 釋放
    cam.deinit()

except Exception as e:
    print(f"❌ 錯誤: {e}")

print("========================================")

輸出結果如下 :

========================================
🚀 Vibe Cam - 最終勝利存檔版
========================================
✅ 格式設定成功 (JPEG/VGA)
📸 拍攝中...
<memoryview>
📦 取得數據: 28189 bytes
28189
💾 已強制儲存至: vibe_victory.jpg
🎉 請立刻用 Thonny 下載這張照片,它絕對是好的!
========================================

按 Thonny 左邊開發板資料夾框右上角的三條槓按鈕, 點選 "重新整理" 就會出現拍攝的照片 JPG 檔, 點選 "下載到 D:\ESP32-S3-CAM" 即可複製此 JPG 到 PC 瀏覽 :





來回試了好幾次都無法得到完整的照片只好放棄了. 


2026-02-12 補充 :

這幾天測試結果顯示, 照片不全可能不是 cnadler86 的韌體問題, 而是鏡頭模組排線問題. 尚待找到庫存的 ov2640 模組進一步測試後才能確認. 

2026年2月10日 星期二

momo 買書 1 本 (AI 時代的 Side Project 全攻略) + 威剛 64GB TF 卡


上次婷婷表妹幫我買的 3 支小米監視器還剩一支待安裝, 需要一片 TF 卡, 上 momo 看到威剛 64GB 特價 260 元, 但僅限購一片, 這樣得付運費, 所以加買一本上回放進購物車的書, 最近有打算退休後接案, 此書剛好合用 : 





合計 805 元, 用掉 momo 幣 133 元, 實付 672 元. 

好站 : codemee 的部落格

今天在測試 ESP32-S3 CAM 開發板時搜尋到 codemee 的部落格 :


作者是旗標的工程師, 其文章具有高度技術性, 所涉獵範圍與我頗多重疊, 故記錄在此有空好好來學習挖寶. 

2026年2月9日 星期一

蝦皮購買 Beston 9V 恆壓充電鋰電池 x2

我在蝦皮又找到一個 9V 充電鋰電池的賣家, 容量較低 (1000mAh), 比較續航力用 : 






明華智取店取付免運 330 元, 2/15 前保證到貨.