Build Log · 開發歷程

用一堆零件,做出一台會拍照的迷你相機

XIAO ESP32-S3 Sense(OV2640)+ 2.4″ ILI9341 顯示器 + 搖桿,從接線、寫韌體,到一路踩坑除錯,最後做出即時取景、拍照、濾鏡、相簿與錄影都能跑的手作相機。這頁記錄整個過程,特別是那些「畫面壞掉」的失敗與解法。

MCU XIAO ESP32-S3 Sense Camera OV2640 Display ILI9341 240×320 SPI Input 類比搖桿 Storage microSD FAT32 Power 行動電源

01專案概覽

目標:相機畫面即時顯示在小螢幕上,並用搖桿操作拍照、濾鏡、相簿、錄影。最終完成的功能:

02手上的零件

最右邊那顆帶鏡頭的就是 XIAO ESP32-S3 Sense;中間是 2.4″ ILI9341 顯示器;還有搖桿、麵包板、杜邦線。相機透過 Sense 底板內部走線,不佔外露排針。

專案使用的零件:搖桿、麵包板、ILI9341 顯示器、杜邦線、XIAO ESP32-S3 Sense
起點:搖桿 · 麵包板 · 2.4″ ILI9341 · 杜邦線 · XIAO ESP32-S3 Sense(含 OV2640)

03硬體:接腳不是想像的那樣

實體顯示器的絲印是 GND VCC SCL SDA RES DC CS BLK(8 pin、無 MISO)。SCL/SDA 不是 I2C,而是 SPI 的時脈/資料,只是廠商命名不同。SD 卡與顯示器共用同一組 SPI。

顯示器接腳絲印特寫 GND VCC SCL SDA RES DC CS BLK
關鍵發現:絲印 GND VCC SCL SDA RES DC CS BLK
絲印別名XIAO
GNDGNDGND
VCCVCC3V3
SCLSCK 時脈D8
SDAMOSI 資料D10
RESRESETD0
DCDCD3
CSCSD1
BLK背光3V3

04除錯歷程:六道關卡

從編譯不過,到畫面損毀、顏色錯亂——每一關的症狀、根因與解法。失敗畫面用程式重現當時的樣子(示意)。

1
Compile Error

找不到 esp32-hal-periman.h

fatal error: esp32-hal-periman.h: No such file or directory
根因
ESP32 Arduino 核心太舊(2.x);新版 Arduino_GFX 需要核心 3.x 才有的檔案。
解法
開發板管理員把 esp32 by Espressif 更新到 3.x。
2
Compile Error

'BLACK' was not declared

error: 'BLACK' was not declared in this scope
根因
新版 Arduino_GFX 移除了 BLACK/WHITE/RED 這些顏色名稱(避免與其他函式庫衝突)。
解法
自訂顏色常數,不依賴函式庫命名:
#define COL_BLACK 0x0000
#define COL_WHITE 0xFFFF
#define COL_RED   0xF800
3
Runtime · Photo

拍好的照片變迷幻塗抹

症狀
即時預覽正常,但存下的照片色彩糊成一片藍紫、有隱約輪廓。
推論
相機 RGB565 是大端序,預覽用 draw16bitBeRGBBitmap 沒事;但存檔用的 frame2jpg 需要小端序,顏色平面被打亂。
當時嘗試
存檔前先交換每個像素的位元組再編碼。(結果見下一關)
步驟3 實拍:照片糊成藍紫塗抹(相簿 2/5)
失敗畫面 · 實拍
結構還在,但色彩像融化的油畫。
4
Runtime · Photo

改了位元序,變成藍色雜訊

症狀
交換位元組後,照片反而變成整片藍色雜訊,結構全失。
結論
在這顆相機上,frame2jpg(RGB565→JPEG)這條路怎麼調都不可靠。
解法
改用相機的原生 JPEG 輸出拍照——按下時暫時切到 JPEG 模式直接存,存完切回取景。這條路和錄影相同,顏色天生正確。
步驟4 實拍:整片藍色雜訊(相簿 6/9)
失敗畫面 · 實拍
藍色雜訊,幾乎看不出內容。
5
Runtime · 關鍵根因

結構仍損毀 → 揪出真正兇手

症狀
用原生 JPEG 後,照片有時仍部分損毀。
查證
上網比對官方社群範例,發現 XIAO ESP32-S3 Sense 的相機 XCLK 時脈設 20MHz 太快,擷取時會 DMA 溢位(EV-VSYNC-OVF),產生損毀影格。預覽因一直刷新看不太出來,存成單張就定格了。
解法
把 XCLK 從 20MHz 降到 10MHz——結構立刻完全正確!
- config.xclk_freq_hz = 20000000;
+ config.xclk_freq_hz = 10000000;  // XIAO Sense 必須
步驟5 實拍:半屏結構損毀(相簿 2/2)
轉捩點
結構回來了(右半可辨識),只剩顏色問題。
6
Runtime · Color

最後一哩:紅藍互換

症狀
畫面結構完全正確,但藍色的烙鐵台顯示成紫紅色——典型紅藍通道互換。
根因
相簿/影片預覽用 TJpg 解碼,搭配 Arduino_GFX 的 draw16bitRGBBitmap 時,setSwapBytes(true) 造成位元組換位。
解法
改成 false 即可,純顯示端修正,照片本身不用重拍。
- TJpgDec.setSwapBytes(true);
+ TJpgDec.setSwapBytes(false);
步驟6 實拍:結構清楚但偏紫紅(相簿 8/8)
失敗畫面 · 實拍
結構對了,藍↔紅整片偏紫紅。
Solved

畫面正常,大功告成

結果
即時取景、拍照、濾鏡、相簿、錄影全部運作;顏色正確、影像清晰。
成功畫面 · 示意
清晰、色彩正確的即時取景。

05功能演進(相機能動之後)

畫面穩定後,把它從「會顯示的相機」一步步養成一台真正好用的裝置。

A
Feature

拍照存 SD + EXIF 時間

做了什麼
點按搖桿拍照,存 JPEG 到 microSD(FAT32)。拍照時暫時切到相機原生 JPEG輸出(顏色正確),並在檔頭注入 EXIF 拍攝時間。
踩到的雷
起初用 frame2jpg 轉檔,照片色彩損毀;真正根因是 XCLK 20MHz(見上面第 5 關),改 10MHz + 原生 JPEG 後解決。
B
Feature

搖桿功能表:濾鏡 / 相簿 / 錄影

做了什麼
長按進功能表,搖桿上下選、點按進入。濾鏡(黑白/負片/復古…+亮度)、相簿(TJpg 解碼翻看 SD 照片)、錄影(MJPEG 存 .avi,含 AVI 檔頭修補)。
狀態機
用單一狀態機管理 LIVE / MENU / FILTER / GALLERY / VIDEO / WIFI 各模式。
C
Feature

WiFi 傳照片(熱點 + 網頁 + OTA)

做了什麼
功能表開 WiFi 熱點,手機加入後 Captive Portal 自動彈出網頁相簿,可瀏覽/下載照片;還能上傳 .bin 做 OTA 無線更新。
對時
AP 模式沒網路無法 NTP → 改由手機瀏覽器連上時把時間傳給裝置,之後拍照就有 EXIF 時間。免 App。
D
Feature

螢幕自動關閉 + 搖桿喚醒

做了什麼
閒置 30 秒自動關螢幕,按搖桿喚醒(喚醒那一下只喚醒、不誤觸)。錄影/傳輸中不關。
真正省電
把顯示器 BLK 背光線從 3V3 改接 D6(GPIO43),用程式完全關背光,而非只是畫面變黑。
E
研究後放棄

BLE 開機自動對時(iPhone CTS)

構想
開機用藍牙自動跟 iPhone 對時,讓離線也有正確時間。
查證結論
iOS 不會穩定、免 App 地對任意 BLE 裝置提供系統時間(Espressif CTS 是「裝置當時間伺服器」,社群實測需自製 App 或改用 GPS)。
決定
誠實記錄:不硬做,改用已完成的「網頁對時」。避免白工也是一種工程判斷。
F
Upgrade

升級 OV5640(500 萬畫素 + 自動對焦)

好消息
OV5640 與 OV2640 同接頭,驅動自動偵測(PID=0x5640),接線與腳位檔完全不用改。
方向
XCLK 用 20MHz(OV5640 建議值);此模組裝上後畫面上下顛倒,把 CAM_VFLIP1 修正(若左右也反再把 HMIRROR 設 1)。
自動對焦
OV5640 有 VCM 對焦馬達。用函式庫 ESP32-OV5640-AF:開機 focusInit() 下載對焦韌體 → autoFocusMode() 連續對焦;拍照前等 getFWStatus()==0x10 鎖焦再擷取。硬體上 AF-VCC 要接 3.3V 馬達才會動。
Tap-to-focus
即時取景時搖桿移動準星,對焦到該點(韌體命令 0x81 + 座標 0x3024/0x3025),閒置 3 秒回全畫面連續對焦。
架構調整
切換 RGB565⇄JPEG 會重置感光元件、AF 韌體要重載,拍照因此卡頓。改成即時取景全程 JPEG(TJpg 解碼上螢幕),AF 開機載一次、拍照不再切格式,順又穩。
為何不用 YOLO
對焦是對比度問題,不是「認出物體」——OV5640 韌體靠影像銳利度自己收斂,YOLO 只給位置、幫不上對焦;何況 ESP32-S3 跑 YOLO <1fps、延遲太高。要主體對焦該用更輕的 ESP-DL 人臉偵測;物件辨識則留給「相簿離線標記」。
實測
已上板驗證:方向修正、連續對焦、拍照鎖焦、搖桿 tap-to-focus 準星均正常運作(觸控對焦區域座標視模組可再微調)。

06學到的重點

關於失敗畫面:本頁的損毀/雜訊/偏色畫面是用程式重現當時的樣子(示意),方便理解各關卡的症狀差異。若要換成實機拍下的真實照片,把照片放進 images/ 後替換對應區塊即可。