將 Volos 大的 project 轉至 PicoGame 上玩
原始 project link
https://www.youtube.com/watch?v=50uPv7tsVIc
計算機部分 :
左邊按鈕可控制游標,A 鍵為確認
B 鍵為清除
// Porting CalcCalendar to Picogame (Pico_W)
// Reference : https://github.com/VolosR/TdsipalyS3CalcCalendar/blob/main/TdsipalyS3CalcCalendar.ino
// 原先 ESP32 NTP 寫法不適用於 Pico_W,這部分重新修正
// 2024/5/2 by Mason
#include <TFT_eSPI.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite img = TFT_eSprite(&tft);
const unsigned short bright[676] PROGMEM={
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0010 (16) pixels
0x0000, 0x0000, 0x0000, 0x0841, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0020 (32) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8C51, 0x3186, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0030 (48) pixels
0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0000, 0x0000, 0x0020, 0x0000, 0x0000, // 0x0040 (64) pixels
0xFFFF, 0x6B6D, 0x0000, 0x0000, 0x0020, 0x0000, 0x0000, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0050 (80) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF79E, 0x738E, 0x0020, 0x0000, 0x0000, 0x0000, // 0x0060 (96) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2945, 0x2965, 0x0000, 0x0000, // 0x0070 (112) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0xFFDF, 0x6B4D, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x630C, 0x0000, 0x0000, 0x0000, // 0x0080 (128) pixels
0x0000, 0x0000, 0x0000, 0x0020, 0x0000, 0x0000, 0x8410, 0xFFFF, 0x2124, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFDF, 0x632C, // 0x0090 (144) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xAD55, 0xFFFF, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, // 0x00A0 (160) pixels
0x0000, 0x94B2, 0xFFFF, 0x2124, 0x0000, 0x0000, 0x0000, 0x1082, 0x4228, 0x3186, 0x0000, 0x0000, 0x0000, 0x0020, 0xA534, 0xFFFF, // 0x00B0 (176) pixels
0x10A2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0000, 0x0000, 0x0020, 0x0000, 0x94B2, 0xFFFF, 0x0000, 0x4228, // 0x00C0 (192) pixels
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xC638, 0x0000, 0x7BEF, 0xFFFF, 0x18C3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00D0 (208) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3186, 0x94B2, 0xFFFF, 0x8C51, 0x0020, 0x0000, 0x0000, 0x2965, 0xDEFB, // 0x00E0 (224) pixels
0xFFFF, 0x39E7, 0x10A2, 0x0000, 0x0000, 0x0000, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0020, 0x0000, 0x0000, // 0x00F0 (240) pixels
0x0000, 0x52AA, 0xFFDF, 0x2104, 0x0020, 0x0000, 0x0000, 0x0020, 0x0000, 0x0000, 0xAD55, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0100 (256) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x6B6D, 0x0000, 0x0000, 0x0000, // 0x0110 (272) pixels
0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFDF, 0x9CF3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0000, 0x0000, // 0x0120 (288) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x4208, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x630C, // 0x0130 (304) pixels
0xFFDF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8C51, 0xC618, 0xB5B6, 0xBDD7, 0xA534, 0x630C, 0xEF7D, // 0x0140 (320) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFDF, 0x0000, 0x0000, 0x2104, 0xFFFF, 0x18C3, 0xC638, 0xBDD7, 0xBDD7, 0xC638, // 0x0150 (336) pixels
0x2965, 0x0000, 0x0000, 0x73AE, 0xB596, 0xAD75, 0xB596, 0x94B2, 0x6B4D, 0xF79E, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, // 0x0160 (352) pixels
0xFFFF, 0x0000, 0x0000, 0x10A2, 0xFFFF, 0x18E3, 0xB596, 0xB596, 0xAD55, 0xBDD7, 0x2965, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0170 (368) pixels
0x0000, 0x0000, 0x39C7, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x632C, 0xFFDF, 0x0000, // 0x0180 (384) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x73AE, 0x0000, // 0x0190 (400) pixels
0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x94B2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x01A0 (416) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4A49, 0xFFFF, 0x2945, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x01B0 (432) pixels
0xAD75, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x01C0 (448) pixels
0x0000, 0x39E7, 0x8430, 0xFFFF, 0x9CD3, 0x1082, 0x0000, 0x0000, 0x3186, 0xEF7D, 0xFFFF, 0x39E7, 0x18E3, 0x0000, 0x0020, 0x0000, // 0x01D0 (464) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xA534, 0xFFFF, 0x0000, 0x39C7, 0xFFDF, 0xFFFF, // 0x01E0 (480) pixels
0xFFFF, 0xFFDF, 0xFFFF, 0xBDD7, 0x0000, 0x7BCF, 0xFFFF, 0x2104, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x01F0 (496) pixels
0x0000, 0x0000, 0x0000, 0xA534, 0xFFFF, 0x18E3, 0x0020, 0x0000, 0x0000, 0x0841, 0x4208, 0x2945, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0200 (512) pixels
0x9CD3, 0xFFFF, 0x2104, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8C51, 0xFFFF, 0x18C3, 0x0000, // 0x0210 (528) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x6B4D, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9CD3, 0xFFFF, 0x0841, 0x0000, 0x0000, // 0x0220 (544) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2124, 0x2104, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF7BE, 0x6B6D, // 0x0230 (560) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x52AA, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0841, 0x0000, 0x0000, // 0x0240 (576) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF7BE, 0x738E, 0x0000, 0x0000, 0x0000, 0x0020, 0x0000, 0x0000, // 0x0250 (592) pixels
0x0000, 0x0000, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0260 (608) pixels
0x0000, 0x0000, 0xFFFF, 0x73AE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0270 (624) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7BEF, 0x2945, 0x0000, 0x0000, // 0x0280 (640) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0290 (656) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x02A0 (672) pixels
};
// 請換成自己的 wifi ap
const char* ssid = "xxxx";
const char* password = "xxxx";
unsigned long currentSec;
WiFiClient wifiClient;
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org"); // NTP 得到時間
String currentTime, hour, minute,second;
int flag = 1;
int week_day;
// 儲存日期及時間的變數
String formattedDate;
String dayStamp;
String timeStamp;
int tm_Year,tm_Month,monthDay;
int tm_Hour,tm_Minute,tm_Second;
int daysInMonth;
int weekDay,month,day,year,firstDay;
String monthNames[12]={"JANUARY","FEBRUARY","MARCH","APRIL","MAY","JUNE","JULY","AUGUST","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER"};
// String lblT[]={"HOUR","MIN","SEC","DAY","MONTH","YEAR"};
#define gray 0xB5B6
#define blue 0x0AAD
#define orange 0xC260
#define purple 0x604D
#define green 0x1AE9
#define left 15
#define up 8
#define down 7
#define right 9
#define a 2
#define b 14
int fromTop=65;
int fromLeft=10;
int boxW=22;
int boxH=20;
int space=4;
int n=4;
int m=4;
int posX[16];
int posY[16];
int cx,cy=0;
float n1=0;
float n2=0;
String num="";
int operation=0;
char buttons[4][4]={{'7','4','1','0'},{'8','5','2','.'},{'9','6','3','='},{'/','*','-','+'}};
String Day[7]={"SU","MO","TU","WE","TH","FR","SA"};
String SDay[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
String Months[12]={"January","February","March","April","May","June","July","August","September","October","November","December"};
int mm[12]={31,28,31,30,31,30,31,31,30,31,30,31};
int dayCounter=0;
// int dayInMonth=0;
// int daysInMonth=0;
// int firstDay=0;
int db1,db2,db3,db4,db5,db6=0;
int brightness=50;
struct tm timeinfo;
int rtcMonthDays(int month, int year) {
if (month == 2) {
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
return 29; // Prijestupna godina
} else {
return 28; // Nije prijestupna godina
}
} else if (month == 4 || month == 6 || month == 9 || month == 11) {
return 30;
} else {
return 31;
}
}
int getDayOfWeek(int wd, int day) {
int n=wd;
for(int i=day-1;i>0;i--)
{n--; if(n<0) n=6;
}
return n;
}
String splitString(String data, char separator, int index)
{
int stringData = 0; //variable to count data part nr
String dataPart = ""; //variable to hole the return text
for(int i = 0; i<data.length(); i++) {
if(data[i]==separator) {
//Count the number of times separator character appears in the text
stringData++;
}else if(stringData==index) {
//get the text when separator is the rignt one
dataPart.concat(data[i]);
}else if(stringData>index) {
//return text and stop if the next separator appears - to save CPU-time
return dataPart;
break;
}
}
return dataPart;
}
void setup() {
// pinMode(15,OUTPUT);
// digitalWrite(15,1);
pinMode(up,INPUT_PULLUP);
pinMode(down,INPUT_PULLUP);
pinMode(left,INPUT_PULLUP);
pinMode(right,INPUT_PULLUP);
pinMode(a,INPUT_PULLUP);
pinMode(b,INPUT_PULLUP);
pinMode(0,INPUT_PULLUP);
pinMode(1,INPUT_PULLUP);
// ledcSetup(0, 10000, 8);
// ledcAttachPin(38, 0);
// ledcWrite(0, brightness);
tft.init();
tft.setRotation(1);
tft.setSwapBytes(true);
tft.invertDisplay(false);
tft.fillScreen(TFT_BLACK);
img.createSprite(320, 170);
img.setTextDatum(4);
img.setTextColor(TFT_WHITE,TFT_BLACK);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
if (WiFi.status() == WL_CONNECTED )
{
// 使用 NTP 抓取網路時間
timeClient.begin();
timeClient.setTimeOffset(8 * 3600); //UTC+8 8 * 3600
while (!timeClient.update()) {
timeClient.forceUpdate();
}
}
}
#define color1 0x33AE //body
#define color2 0x22CE //number region
#define color3 0x2C8E //buttons region
int caw=22;
int cay=20;
int cax=150;
int cah=22;
int seg=0;
long t=0;
void initDraw()
{
img.fillSprite(TFT_BLACK);
img.setTextColor(TFT_WHITE,TFT_BLACK);
img.setTextDatum(4);
img.drawRoundRect(2,2,118,166,5,TFT_WHITE); ///border
img.fillRoundRect(fromLeft,26,100,24,5,color2);
img.setTextColor(TFT_WHITE,color3);
for(int i=0;i<n;i++){
posY[i]=fromTop+(boxH*i)+(space*i);
for(int j=0;j<m;j++)
{
posX[j]=fromLeft+(boxW*j)+(space*j);
img.fillRoundRect(posX[j],posY[i],boxW,boxH,3,color3);
img.drawString(String(buttons[j][i]),posX[j]+boxW/2,posY[i]+boxH/2,2);
}}
img.drawRoundRect(posX[cx],posY[cy],boxW,boxH,3,TFT_WHITE);
img.setTextDatum(5);
img.setTextColor(TFT_WHITE,color2);
img.drawString(num,fromLeft+94,38,2);
img.setTextColor(TFT_WHITE,TFT_BLACK);
caw=24;
cay=70;
cax=142;
cah=15;
img.setTextDatum(4);
for(int j=0;j<7;j++)
img.drawString(Day[j],cax+(j*caw),cay,2);
int broj=1;
int w=0;
bool started=0;
for(int i=0;i<5;i++)
for(int j=0;j<7;j++){
if(w==firstDay)
started=1;
if(started==1 && broj<=daysInMonth){
if(broj==monthDay)
img.setTextColor(TFT_BLACK,TFT_WHITE);
else
img.setTextColor(TFT_ORANGE,TFT_BLACK);
img.drawString(String(broj),cax+(j*caw),cay+cah+(cah*i),2);
broj++;
}
w++;
}
img.setTextDatum(0);
img.setTextColor(TFT_WHITE,TFT_BLACK);
img.setFreeFont(&Orbitron_Light_32);
img.drawString(String(hour)+":"+String(minute),130,-6);
img.setFreeFont(&Orbitron_Light_24);
img.setTextColor(0xD399,TFT_BLACK);
img.drawString(String(second),250,-4);
img.setTextColor(0x35F9,TFT_BLACK);
img.setFreeFont(&FreeSans9pt7b);
img.drawString(String(monthNames[tm_Month-1])+" "+String(monthDay),130,32);
img.setTextColor(gray,TFT_BLACK);
img.drawString("Pico Game",15,8);
img.drawRoundRect(304,30,12,136,2,TFT_SILVER);
seg=brightness/24;
for(int i=0;i<seg;i++)
img.fillRect(308,150-(i*13),4,11,0x35F9);
img.drawLine(cax-10,cay-10,cax+152,cay-10,gray);
img.pushImage(298,0,26,26,bright);
img.pushSprite(0,0);
}
void loop() {
if(t+1000<millis()){
getLocalTime();
t=millis();
}
if(digitalRead(b)==0)
num="";
if(digitalRead(up)==0){
if(db1==0){
db1=1;
cy--;}
}else db1=0;
if(digitalRead(down)==0){
if(db2==0){
db2=1;
cy++;}
}else db2=0;
if(digitalRead(left)==0){
if(db4==0){
db4=1;
cx--;}
}else db4=0;
if(digitalRead(right)==0){
if(db5==0){
db5=1;
cx++;}
}else db5=0;
if(cx==4)
cx=0;
if(cx==-1)
cx=3;
if(cy==4)
cy=0;
if(cy==-1)
cy=3;
if(digitalRead(a)==0){
if(db3==0){
db3=1;
if(buttons[cx][cy]=='0' || buttons[cx][cy]=='1' || buttons[cx][cy]=='2' || buttons[cx][cy]=='3' || buttons[cx][cy]=='4' || buttons[cx][cy]=='5' || buttons[cx][cy]=='6' || buttons[cx][cy]=='7' || buttons[cx][cy]=='8' || buttons[cx][cy]=='9' || buttons[cx][cy]=='.' )
num=num+String(buttons[cx][cy]);
if(buttons[cx][cy]=='+') {operation=1; n1=num.toFloat(); num="";}
if(buttons[cx][cy]=='-') {operation=2; n1=num.toFloat(); num="";}
if(buttons[cx][cy]=='*') {operation=3; n1=num.toFloat(); num="";}
if(buttons[cx][cy]=='/') {operation=4; n1=num.toFloat(); num="";}
if(buttons[cx][cy]=='=') {
if(operation==1)
{float r=n1+num.toFloat(); num=String(r); n1=num.toFloat();
int p=r*10.00;
if(p%10==0)
num=String(p/10);
}
if(operation==2)
{float r=n1-num.toFloat(); num=String(r); n1=num.toFloat();
int p=r*10.00;
if(p%10==0)
num=String(p/10);}
if(operation==3)
{float r=n1*num.toFloat(); num=String(r); n1=num.toFloat();
int p=r*10.00;
if(p%10==0)
num=String(p/10);}
if(operation==4)
{float r=n1/num.toFloat(); num=String(r); n1=num.toFloat();
int p=r*10.00;
if(p%10==0)
num=String(p/10);}
}
}
}else db3=0;
initDraw();
}
void getLocalTime() {
timeClient.update();
unsigned long epochTime = timeClient.getEpochTime();
// Serial.println(epochTime);
if(flag == 1)
{
currentSec = epochTime;
flag = 0;
}
String formattedTime = timeClient.getFormattedTime();
// Serial.println(formattedTime);
// 取得日期
// formattedDate函式取得的日期格式為: 2022-06-24T16:00:13Z
formattedDate = timeClient.getFormattedDate();
int splitT = formattedDate.indexOf("T");
dayStamp = formattedDate.substring(0, splitT);
tm_Year = splitString(dayStamp, '-', 0).toInt();
tm_Month = splitString(dayStamp, '-', 1).toInt();
monthDay = splitString(dayStamp, '-', 2).toInt();
Serial.print("DATE: ");
Serial.println(tm_Month);
tm_Hour = timeClient.getHours();
tm_Minute = timeClient.getMinutes();
tm_Second = timeClient.getSeconds();
week_day = timeClient.getDay();
String currentDate = String(tm_Month) + "/" + String(monthDay);
if (tm_Hour < 10)
hour = "0" + String(tm_Hour);
else
hour = String(tm_Hour);
if (tm_Minute < 10)
minute = "0" + String(tm_Minute);
else
minute = String(tm_Minute);
if (tm_Second < 10)
second = "0" + String(tm_Second);
else
second = String(tm_Second);
currentTime = hour + ":" + minute;
daysInMonth=rtcMonthDays(tm_Month, tm_Year);
firstDay=getDayOfWeek(week_day,monthDay); //算出每個月第一天是星期幾
}