2024/5/12
PicoGame 有一片 2.8" 的彩色螢幕
把之前一些出遊玩的照片,放上來當小型的數位相框使用,看看之前的照片回憶一下,也是蠻不錯的應用
以下範例用的是副廠 Pico 開發板,有內建 4MB flash。 而原廠為內建 2MB flash。
照片是放在 Little FS 裏,請先轉成最大 320x240 的 jpg,壓縮後每張約 50kB。 實際可放幾張,依不同的照片及開發板 flash 會有所不同.
我使用副廠 Pico,FS: 3MB,約可放 60-80 張 JPG 照片
若用原廠 Pico,FS: 1MB,可放張數約 1/3
Arduino-Pico 設定如左圖:
副廠 4MB flash 的話,可選 Waveshare RP2040 Plus 4MB 型號
Flash Size 選最大的,Sketch:1MB, FS:3MB
用 XnConvert 轉好的 jpg 檔,放在程式的 data 目錄下
上傳程式後,請用 Arduino 內的 Pico LittleFS Data Upload 工具來上傳照片至開發板內
以下為完整程式及相關說明.
// Pico-Game 當數位相框範例 (Pico) by Mason 2024/5/12
// 這是使用副廠的 Pico 開發板,有內建 4MB flash
//
// Arduino setting
// - 開發板選 Waveshare RP2040 Plus 4MB
// - Flash size 選 (Sketch:1MB, FS: 3MB)
//
// 1. 先用 XnConvert 轉成高為 240 的 jpg, 一張照片約 50kB
// 2. 照片放至程式 data 目錄下,3MB 的 little FS 空間約可放 60-80 張照片
// 3. 照片再用 Pico LittleFS 工具上傳至 flash 內
// 4. 程式會先讀取檔名後,自動播放,間隔為 5 秒
//
// Reference :
// https://github.com/Bodmer/TJpg_Decoder example
// https://mischianti.org/raspberry-pi-pico-and-rp2040-boards-integrated-littlefs-filesystem-2/
String folder_name = "/";
// Include the jpeg decoder library
#include <TJpg_Decoder.h>
// Include the TFT library https://github.com/Bodmer/TFT_eSPI
#include "SPI.h"
#include "LittleFS.h"
#include <FS.h>
File root;
int max_num = 500;
#include <TFT_eSPI.h> // Hardware-specific library
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
#define TJPGD_LOAD_FFS
// This next function will be called during decoding of the jpeg file to
// render each block to the TFT. If you use a different TFT library
// you will need to adapt this function to suit.
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
// Stop further decoding as image is running off bottom of screen
if ( y >= tft.height() ) return 0;
// This function will clip the image block rendering automatically at the TFT boundaries
tft.pushImage(x, y, w, h, bitmap);
// This might work instead if you adapt the sketch to use the Adafruit_GFX library
// tft.drawRGBBitmap(x, y, bitmap, w, h);
// Return 1 to decode next block
return 1;
}
String file_list[500];
int file_num = 0;
int file_index = 0;
void setup() {
// Initialise the TFT
tft.begin();
tft.setTextColor(0xFFFF, 0x0000);
tft.setRotation(1);
tft.invertDisplay(false); // 顏色若反,請改為 true
tft.fillScreen(TFT_BLACK);
tft.setSwapBytes(true); // We need to swap the colour bytes (endianess)
Serial.begin(115200);
// while (!Serial) {delay(100);}
Serial.println(F("Inizializing FS..."));
if (LittleFS.begin()){
Serial.println(F("done."));
}else{
Serial.println(F("fail."));
}
// To format all space in LittleFS
// LittleFS.format()
// Get all information of your LittleFS
FSInfo *info;
LittleFS.info(*info);
int i = 0;
File root =LittleFS.open(folder_name, "r");
if (!root) {
Serial.println("Failed to open directory");
}
if (!root.isDirectory()) {
Serial.println("Not a directory");
}
File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
} else{
String temp = file.name();
if (temp.endsWith(".jpg")) {
if (i < max_num) {
file_list[i] = folder_name+temp;
i++;
}
}
}
file = root.openNextFile();
}
file_num = i;
Serial.print("Total jpg file count:");
Serial.println(file_num);
Serial.println("jpg file name:");
for (int i = 0; i < file_num; i++) {
Serial.println(file_list[i]);
}
// The jpeg image can be scaled by a factor of 1, 2, 4, or 8
TJpgDec.setJpgScale(1);
// The decoder must be given the exact name of the rendering function above
TJpgDec.setCallback(tft_output);
}
void loop() {
tft.fillScreen(TFT_BLACK);
// Time recorded for test purposes
uint32_t t = millis();
// Get the width and height in pixels of the jpeg if you wish
uint16_t w = 0, h = 0;
TJpgDec.getFsJpgSize(&w, &h, file_list[file_index].c_str());
Serial.print("Width = "); Serial.print(w); Serial.print(", height = "); Serial.println(h);
int ratio = 1;
TJpgDec.setJpgScale(ratio);
uint16_t offset = 0;
offset = floor((320-w/ratio)/2);
// Draw the image, top left at 0,0
TJpgDec.drawFsJpg(offset, 0, file_list[file_index].c_str());
file_index++;
if (file_index >= file_num){
file_index = 0;
}
// How much time did rendering take
t = millis() - t;
Serial.print(t); Serial.println(" ms");
// Wait before drawing again
delay(5000);
}