Arduino GPS時速表
一直以來,都是以數位化家庭生活的想法來做為Arduino設計基礎.並分享給大家.
所以這次有點算番外篇吧,哈.
這次的GSP時速表,聽起來感覺有些難度,但拜GPS模組所賜,用起來其實還蠻簡單的.
準備材料
1. Arduino Mega2560x1
2. U-BLOX NEO-7N GPS模組
3. 2.8吋 FTF模組 HX8347G
就3樣,超級簡單吧!
但......其實不太好買,哈!
^_^|||
GPS時速表-線路圖
只有5條線,夠簡單吧.
再把螢幕裝上去.
好了.就是這樣而已.
多裝了一個黑色的厚紙板,是防止螢幕反光至前擋風玻璃用的.
不想理解程式碼,可直接將程式碼燒錄製Mega2560就可以直接使用了.
燒錄流程不懂的,可以參考我的另一篇文章,Arduino 聲控開關.
https://betapanel.pixnet.cc/#/edit-article/222494175
分析語法
以下語言部份來自函式庫的範例,因為不再這次GPS時速表的應用範圍內,所以我沒做測試.
但覺得應該有些人會覺得有用,例如經緯度座標.所以我還是節錄出來,至於解釋部分就省略囉.
#include <Adafruit_TFTLCD.h> // 2.8吋TFT的函示庫
#include <TinyGPS++.h> // GPS模組的函示庫 #if defined(__SAM3X8E__) #undef __FlashStringHelper::F(string_literal) #define F(string_literal) string_literal #endif #define YP A1 // 2.8吋TFT的接腳定義
#define XM A2 // 2.8吋TFT的接腳定義 #define YM 7 //2.8吋TFT的接腳定義 #define XP 6 // 2.8吋TFT的接腳定義 //#define TS_MINX 150
//#define TS_MINY 120 //#define TS_MAXX 920 //#define TS_MAXY 940 // For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it // For the one we're using, its 300 ohms across the X plate //TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); #define LCD_CS A3 // 2.8吋TFT的接腳定義
#define LCD_CD A2 // 2.8吋TFT的接腳定義 #define LCD_WR A1 // 2.8吋TFT的接腳定義 #define LCD_RD A0 // 2.8吋TFT的接腳定義 // optional #define LCD_RESET A4 // Assign human-readable names to some common 16-bit color values:
#define BLACK 0x0000 // RGB #define BLUE 0x001F // RGB #define RED 0xF800 // RGB #define GREEN 0x07E0 // RGB #define CYAN 0x07FF // RGB #define MAGENTA 0xF81F // RGB #define YELLOW 0xFFE0 // RGB #define WHITE 0xFFFF // RGB #define GRAY 0x14A5 // RGB #define DARKRED 0xA000 // RGB
#define DARKGREEN 0x0280 // RGB #define DARKYELLOW 0xA280 // RGB #define DARKMAGENTA 0xA014 // RGB #define MINPRESSURE 10 // touch功能用
#define MAXPRESSURE 1000 // touch功能用 #define Serial28 Serial1 // GPS通訊用
#define PASS 1 #define FAIL 0 #define SPEEDGREEN 100 // 時速低於100,數字是綠色
#define SPEEDYELLOW 110 // 時速高於100,低於110,數字是黃色 #define SPEEDMAGENTA 120 // 時速高於110,低於120,數字是紫色 #define SPEEDRED 130 // 時速高於120,數字是色 // The TinyGPS++ object
TinyGPSPlus gps; // 宣告gps變數 Adafruit_TFTLCD Touchtft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET); // 宣告螢幕變數
char cBuf80[80]; // Dispatch incoming characters
int iSpeed123_1, iSpeed123_2, iSpeed123_3; // 時速表3位數字用 unsigned long last = 0UL; int iOldDay, iOldMinute, iOldSecond, iOldValue, iOldSpeed; // 更新比對用 double dOldDeg, dOldMeters; // 更新比對用 int iParaColor, iHour, iFlash, iSpeedUpdate; unsigned int iLoseSpeedCount; //-----------------------------------------------------------------------------------------------
void setup(void) { Serial.begin(115200); // 偵錯用 Serial28.begin(9600); // GPS模組用 // TFT init
Touchtft.reset(); // 螢幕初始化 Touchtft.begin(0x7575); // for HX8347G Touchtft.setRotation(1); // for HX8347G Touchtft.fillScreen(BLACK); // 螢幕全黑 // if sharing pins, you'll need to fix the directions of the touchscreen pins
pinMode(XM, OUTPUT); // 觸控用,這次沒用到 pinMode(YP, OUTPUT); // 觸控用,這次沒用到 Touchtft.fillRect(0, 0, 320, 240, BLACK); // 螢幕xy(0,0)到xy(320,240)設定為黑色 // Touchtft.fillRect這指令常用到,以下就省略BJ4了.
Touchtft.setTextColor(GREEN); // 設定字是綠色
// Touchtft.setTextColor這指令常用到,以下就省略BJ4了.
Touchtft.setTextSize(1); // 字體大小設為1 // Touchtft.setTextSize這指令常用到,以下就省略BJ4了.
Touchtft.setCursor(0, 190); // 設定游標到xy(0,190) // Touchtft.setCursor這指令常用到,以下就省略BJ4了.
Touchtft.println(" Smart Car GPS System"); // 印出Smart Car GPS System,並換行 Touchtft.println(" Ver: 1.0.0.1"); // 印出Ver: 1.0.0.1,並換行 // Touchtft.println,這指令常用到,以下就省略BJ4了.
delay(3000); // 延遲3秒 Touchtft.fillRect(0, 180, 150, 240, BLACK); Touchtft.setTextColor(RED); Touchtft.setCursor(0, 210); //Speedometer
Touchtft.setCursor(0, 210); Touchtft.println(" GPS Speedometer V:0.1"); // 0.1初版 Touchtft.fillRect(230, 205, 90, 15, RED); Touchtft.setTextColor(WHITE); Touchtft.setCursor(240, 210); Touchtft.println("30sec studio"); Touchtft.setTextSize(2);
Touchtft.fillRect(269, 180, 50, 20, BLACK); Touchtft.setTextColor(WHITE); Touchtft.setCursor(269, 180); Touchtft.println("km/h"); iSpeed123_1 = -1; // 初始值設定
iSpeed123_2 = -1; // 初始值設定 iSpeed123_3 = -1; // 初始值設定 iOldSpeed = -1; // 速度,初始值設定
iOldDay = -1; // 日期,初始值設定 iOldMinute = -1; // 時間,初始值設定 iOldSecond = -1; // 秒數,初始值設定 iOldValue = -1; // 衛星,初始值設定 dOldDeg = -1; // 原航道,初始值設定 dOldMeters = -1; // 高度,初始值設定 iParaColor = WHITE; // 初始設定 iLoseSpeedCount = 0; // 初始設定 iFlash = 0; // 0 -> ":"滅, 1 -> ":"亮 iSpeedUpdate = 0; // 0 -> 完成, 1 -> 須更新 } void loop()
{ uint32_t iValue; double dDeg; while (Serial28.available() > 0) // 輪詢GPS模組
gps.encode(Serial28.read()); ShowSpeed((int)gps.speed.kmph()); // 印出時速數值
if (gps.location.isUpdated()) // GPS位置用,這次沒用
{ Serial.print(F("LOCATION Fix Age=")); Serial.print(gps.location.age()); Serial.print(F("ms Raw Lat=")); Serial.print(gps.location.rawLat().negative ? "-" : "+"); Serial.print(gps.location.rawLat().deg); Serial.print("[+"); Serial.print(gps.location.rawLat().billionths); Serial.print(F(" billionths], Raw Long=")); Serial.print(gps.location.rawLng().negative ? "-" : "+"); Serial.print(gps.location.rawLng().deg); Serial.print("[+"); Serial.print(gps.location.rawLng().billionths); Serial.print(F(" billionths], Lat=")); Serial.print(gps.location.lat(), 6); Serial.print(F(" Long=")); Serial.println(gps.location.lng(), 6); } else if (gps.date.isUpdated()) // GPS日期 { Serial.print(F("DATE Fix Age=")); Serial.print(gps.date.age()); Serial.print(F("ms Raw=")); Serial.print(gps.date.value()); Serial.print(F(" Year=")); Serial.print(gps.date.year()); Serial.print(F(" Month=")); Serial.print(gps.date.month()); // Date
if (gps.date.day() != iOldDay) { Touchtft.fillRect(0, 0, 120, 16, BLACK); Touchtft.setTextSize(2); Touchtft.setTextColor(iParaColor); Touchtft.setCursor(0, 0); if(gps.time.hour()>=16) // 補時差16hr { // 印出年月日,格式為: 20xx-xx-xx
sprintf(cBuf80, "%04d-%02d-%02d", gps.date.year(), gps.date.month(), gps.date.day()+1); }
else { sprintf(cBuf80, "%04d-%02d-%02d", gps.date.year(), gps.date.month(), gps.date.day()); } Touchtft.println(cBuf80); } iOldDay = gps.date.day(); // 日期有變時,更新螢幕字體 } else if (gps.time.isUpdated())
{ Serial.print(F("TIME Fix Age=")); Serial.print(gps.time.age()); Serial.print(F("ms Raw=")); Serial.print(gps.time.value()); Serial.print(F(" Second=")); Serial.print(gps.time.second()); Serial.print(F(" Hundredths=")); Serial.println(gps.time.centisecond()); if (iOldSpeed != gps.time.second())
{ // 根據秒速,閃爍時間中間的":"
if (iFlash == 0) // 0 -> ":"滅, 1 -> ":"亮 { iFlash = 1; Touchtft.setTextSize(3); Touchtft.setTextColor(BLACK); Touchtft.setCursor(220+36, 0); sprintf(cBuf80, ":"); Touchtft.println(cBuf80); } else { iFlash = 0; Touchtft.setTextSize(3); Touchtft.setTextColor(WHITE); Touchtft.setCursor(220 + 36, 0); sprintf(cBuf80, ":"); Touchtft.println(cBuf80); } iOldSpeed = gps.time.second(); } // 時間
if (gps.time.minute() != iOldMinute) { if (gps.time.hour() < 16) // 補時差 { iHour = gps.time.hour() + 8; } else { iHour = gps.time.hour() - 16; // update DATE
Touchtft.fillRect(0, 0, 120, 16, BLACK); Touchtft.setTextSize(2); Touchtft.setTextColor(iParaColor); Touchtft.setCursor(0, 0); sprintf(cBuf80, "%04d-%02d-%02d", gps.date.year(), gps.date.month(), gps.date.day()+1);
Touchtft.println(cBuf80); } if (gps.date.year() == 2000)
{ iHour = 0; } Touchtft.fillRect(220, 0, 90, 22, BLACK); Touchtft.setTextSize(3); Touchtft.setTextColor(iParaColor); Touchtft.setCursor(220, 0); // 印出GPS時間,格式為: xx:xx
sprintf(cBuf80, "%02d:%02d", iHour, gps.time.minute()); Touchtft.println(cBuf80); } iOldMinute = gps.time.minute(); } else if (gps.speed.isUpdated()) // 速度
{ Serial.print(F("SPEED Fix Age=")); Serial.print(gps.speed.age()); Serial.print(F("ms Raw=")); Serial.print(gps.speed.value()); Serial.print(F(" Knots=")); Serial.print(gps.speed.knots()); Serial.print(F(" MPH=")); Serial.print(gps.speed.mph()); Serial.print(F(" m/s=")); Serial.print(gps.speed.mps()); Serial.print(" Speed: "); Serial.println((int)gps.speed.kmph()); } else if (gps.course.isUpdated()) // 原航道,沒用到
{ Serial.print(F("COURSE Fix Age=")); Serial.print(gps.course.age()); Serial.print(F("ms Raw=")); Serial.print(gps.course.value()); } else if (gps.altitude.isUpdated()) // 高度,沒用到
{ Serial.print(F("ALTITUDE Fix Age=")); Serial.print(gps.altitude.age()); Serial.print(F("ms Raw=")); Serial.print(gps.altitude.value()); Serial.print(F(" Miles=")); Serial.print(gps.altitude.miles()); Serial.print(F(" KM=")); Serial.print(gps.altitude.kilometers()); Serial.print(F(" Feet=")); Serial.println(gps.altitude.feet()); } else if (gps.satellites.isUpdated()) // 衛星
{ Serial.print(F("SATELLITES Fix Age=")); Serial.print(gps.satellites.age()); Serial.print(F("ms Value=")); Serial.println(gps.satellites.value()); if (gps.satellites.value() > 2) // 利用衛星數,判斷是否,時速歸0, 字變灰
{ iLoseSpeedCount = 0; iParaColor = WHITE; if (iSpeedUpdate == 1) // 0 -> 完成, 1 -> 須更新 { iSpeed123_1 = -1; // 時速更新 iSpeed123_2 = -1; // 時速更新 iSpeed123_3 = -1; // 時速更新 iSpeedUpdate = 0; // 0 -> 完成, 1 -> 須更新 } } else { iParaColor = 0x2084; iOldDay = -1; // 日期更新 iOldMinute = -1; // 時間更新 iOldValue = -1; // 衛星更新 dOldDeg = -1; // 原航道更新 dOldMeters = -1; // 高度更新 iSpeed123_1 = -1; // 時速更新 iSpeed123_2 = -1; // 時速更新 iSpeed123_3 = -1; // 時速更新 iSpeedUpdate = 1; // 0 -> 完成, 1 -> 須更新 Touchtft.fillRect(0, 220, 320, 20, 0x2084);
delay(300); Touchtft.fillRect(0, 220, 320, 20, BLACK); } // 衛星
if (gps.satellites.value() != iOldValue) { iOldDay = -1; // 日期 Touchtft.fillRect(132, 20, 48, 16, BLUE); Touchtft.setTextSize(2); Touchtft.setTextColor(iParaColor); Touchtft.setCursor(0, 20); sprintf(cBuf80, "satellites: %d", gps.satellites.value()); Touchtft.println(cBuf80); } iOldValue = gps.satellites.value(); } else if (gps.hdop.isUpdated()) // 精度因子,沒用到
{ Serial.print(F("HDOP Fix Age=")); Serial.print(gps.hdop.age()); Serial.print(F("ms Value=")); Serial.println(gps.hdop.value()); } else if (millis() - last > 5000)
{ Serial.println(); if (gps.location.isValid()) { // 沒進來過 static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002; double distanceToLondon = TinyGPSPlus::distanceBetween( gps.location.lat(), gps.location.lng(), LONDON_LAT, LONDON_LON); double courseToLondon = TinyGPSPlus::courseTo( gps.location.lat(), gps.location.lng(), LONDON_LAT, LONDON_LON); Serial.print(F("LONDON Distance="));
Serial.print(distanceToLondon / 1000, 6); Serial.print(F(" km Course-to=")); Serial.print(courseToLondon, 6); Serial.print(F(" degrees [")); Serial.print(TinyGPSPlus::cardinal(courseToLondon)); Serial.println(F("]")); } Serial.print(F("DIAGS Chars="));
Serial.print(gps.charsProcessed()); Serial.print(F(" Sentences-with-Fix=")); Serial.print(gps.sentencesWithFix()); Serial.print(F(" Failed-checksum=")); Serial.print(gps.failedChecksum()); Serial.print(F(" Passed-checksum=")); Serial.println(gps.passedChecksum()); if (gps.charsProcessed() < 10)
Serial.println(F("WARNING: No GPS data. Check wiring.")); last = millis();
Serial.println(); iLoseSpeedCount++; Serial.print("......................................... "); Serial.println(iLoseSpeedCount); } } void ShowSpeed(int iSpeed) // 顯示GPS時速
{ int iShowSpeed; int i1, i2, i3; int iColor1, iColor2, iColor3, iColor4; pinMode(XM, OUTPUT); pinMode(YP, OUTPUT); switch (iHour) // 根據時間顯示不同顏色,用以調整日夜的螢幕亮度0~23點
{ case 0: iColor1 = DARKGREEN; iColor2 = DARKYELLOW; iColor3 = DARKMAGENTA; iColor4 = DARKRED; break; case 1: iColor1 = DARKGREEN; iColor2 = DARKYELLOW; iColor3 = DARKMAGENTA; iColor4 = DARKRED; break; case 2: iColor1 = DARKGREEN; iColor2 = DARKYELLOW; iColor3 = DARKMAGENTA; iColor4 = DARKRED; break; case 3: iColor1 = DARKGREEN; iColor2 = DARKYELLOW; iColor3 = DARKMAGENTA; iColor4 = DARKRED; break; case 4: iColor1 = DARKGREEN; iColor2 = DARKYELLOW; iColor3 = DARKMAGENTA; iColor4 = DARKRED; break; case 5: iColor1 = DARKGREEN; iColor2 = DARKYELLOW; iColor3 = DARKMAGENTA; iColor4 = DARKRED; break; case 6: iColor1 = DARKGREEN; iColor2 = DARKYELLOW; iColor3 = DARKMAGENTA; iColor4 = DARKRED; break; case 7: iColor1 = GREEN; iColor2 = YELLOW; iColor3 = MAGENTA; iColor4 = RED; break; case 8: iColor1 = GREEN; iColor2 = YELLOW; iColor3 = MAGENTA; iColor4 = RED; break; case 9: iColor1 = GREEN; iColor2 = YELLOW; iColor3 = MAGENTA; iColor4 = RED; break; case 10: iColor1 = GREEN; iColor2 = YELLOW; iColor3 = MAGENTA; iColor4 = RED; break; case 11: iColor1 = GREEN; iColor2 = YELLOW; iColor3 = MAGENTA; iColor4 = RED; break; case 12: iColor1 = GREEN; iColor2 = YELLOW; iColor3 = MAGENTA; iColor4 = RED; break; case 13: iColor1 = GREEN; iColor2 = YELLOW; iColor3 = MAGENTA; iColor4 = RED; break; case 14: iColor1 = GREEN; iColor2 = YELLOW; iColor3 = MAGENTA; iColor4 = RED; break; case 15: iColor1 = GREEN; iColor2 = YELLOW; iColor3 = MAGENTA; iColor4 = RED; break; case 16: iColor1 = GREEN; iColor2 = YELLOW; iColor3 = MAGENTA; iColor4 = RED; break; case 17: iColor1 = GREEN; iColor2 = YELLOW; iColor3 = MAGENTA; iColor4 = RED; break; case 18: iColor1 = GREEN; iColor2 = YELLOW; iColor3 = MAGENTA; iColor4 = RED; break; case 19: iColor1 = DARKGREEN; iColor2 = DARKYELLOW; iColor3 = DARKMAGENTA; iColor4 = DARKRED; break; case 20: iColor1 = DARKGREEN; iColor2 = DARKYELLOW; iColor3 = DARKMAGENTA; iColor4 = DARKRED; break; case 21: iColor1 = DARKGREEN; iColor2 = DARKYELLOW; iColor3 = DARKMAGENTA; iColor4 = DARKRED; break; case 22: iColor1 = DARKGREEN; iColor2 = DARKYELLOW; iColor3 = DARKMAGENTA; iColor4 = DARKRED; break; case 23: iColor1 = DARKGREEN; iColor2 = DARKYELLOW; iColor3 = DARKMAGENTA; iColor4 = DARKRED; break; default: break; } i1 = iShowSpeed = (iSpeed / 100) % 10; //取出個位數 i2 = iShowSpeed = (iSpeed / 10) % 10; //取出十位數 i3 = iShowSpeed = iSpeed % 10; //取出百位數 iShowSpeed = iSpeed % 10;
if (iShowSpeed != iSpeed123_3) // iShowSpeed跟舊的數值iSpeed123_3比 { Serial.print("123_3: "); Serial.println(iShowSpeed); Touchtft.fillRect(213, 60, 90, 120, BLACK); if (iParaColor != 0x2084) { if (iSpeed < SPEEDGREEN) // 根據時速變更字體的顏色 { Touchtft.setTextColor(iColor1); // GREEN 100km/h以下 } else if ((iSpeed >= SPEEDGREEN) && (iSpeed < SPEEDYELLOW)) { Touchtft.setTextColor(iColor2); // YELLOW 100km/h以上, 110km/h以下 } else if ((iSpeed >= SPEEDYELLOW) && (iSpeed < SPEEDMAGENTA)) { Touchtft.setTextColor(iColor3); // MAGENTA 110km/h以上, 120km/h以下 } else { Touchtft.setTextColor(iColor4); // RED 120km/h以上 } } else { iSpeed = 0; Touchtft.setTextColor(0x2084); // iSpeed歸0, 字變灰 } Touchtft.setTextSize(17); Touchtft.setCursor(213, 60); sprintf(cBuf80, "%d", iShowSpeed); Touchtft.println(cBuf80); // 更新個位數 } iSpeed123_3 = iShowSpeed; // 儲存起來,用以比對,若數字變更,才刷新螢幕字體 iShowSpeed = iSpeed / 10; iShowSpeed = iShowSpeed % 10; if (iShowSpeed != iSpeed123_2) { Serial.print("123_2: "); Serial.println(iShowSpeed); Touchtft.fillRect(112, 60, 90, 120, BLACK); if ((iShowSpeed == 0) && (i1 == 0)) {} // do nothing else { if (iParaColor != 0x2084) { if (iSpeed < SPEEDGREEN) { Touchtft.setTextColor(iColor1); } else if ((iSpeed >= SPEEDGREEN) && (iSpeed < SPEEDYELLOW)) { Touchtft.setTextColor(iColor2); } else if ((iSpeed >= SPEEDYELLOW) && (iSpeed < SPEEDMAGENTA)) { Touchtft.setTextColor(iColor3); } else { Touchtft.setTextColor(iColor4); } Touchtft.setTextSize(17); Touchtft.setCursor(112, 60); sprintf(cBuf80, "%d", iShowSpeed); Touchtft.println(cBuf80); // 更新十位數 } } } iSpeed123_2 = iShowSpeed; // 儲存起來,用以比對,若數字變更,才刷新螢幕字體 iShowSpeed = iSpeed / 100;
iShowSpeed = iShowSpeed % 10; if (iShowSpeed != iSpeed123_1) { Serial.print("123_1: "); Serial.println(iShowSpeed); Touchtft.fillRect(10, 60, 90, 120, BLACK); if (iShowSpeed != 0) { if (iParaColor != 0x2084) { if (iSpeed < SPEEDGREEN) { Touchtft.setTextColor(iColor1); } else if ((iSpeed >= SPEEDGREEN) && (iSpeed < SPEEDYELLOW)) { Touchtft.setTextColor(iColor2); } else if ((iSpeed >= SPEEDYELLOW) && (iSpeed < SPEEDMAGENTA)) { Touchtft.setTextColor(iColor3); } else { Touchtft.setTextColor(iColor4); } } else { iSpeed = 0; Touchtft.setTextColor(0x2084); // iSpeed歸0, 字變灰 } Touchtft.setTextSize(17); Touchtft.setCursor(10, 60); sprintf(cBuf80, "%d", iShowSpeed); Touchtft.println(cBuf80); } } else // iSpeed超過100km/hr, 才處理字不變,顏色變 { if ((iParaColor != 0x2084) && ((iSpeed / 100) != 0)) { if (iSpeed < SPEEDGREEN) { Touchtft.setTextColor(iColor1); } else if ((iSpeed >= SPEEDGREEN) && (iSpeed < SPEEDYELLOW)) { Touchtft.setTextColor(iColor2); } else if ((iSpeed >= SPEEDYELLOW) && (iSpeed < SPEEDMAGENTA)) { Touchtft.setTextColor(iColor3); } else { Touchtft.setTextColor(iColor4); } if ((iSpeed == SPEEDGREEN) || (iSpeed == SPEEDYELLOW) || (iSpeed = SPEEDMAGENTA) || (iSpeed == SPEEDRED)) { Touchtft.setTextSize(17); Touchtft.setCursor(10, 60); sprintf(cBuf80, "%d", iShowSpeed); Touchtft.println(cBuf80); // 更新個位數 } } } iSpeed123_1 = iShowSpeed; // 儲存起來,用以比對,若數字變更,才刷新螢幕字體 } |
Designed by 30sec studio in Taiwan
Arduino GPS時速表由Peng Yi Hsing製作,以創用CC 姓名標示-非商業性-禁止改作 3.0 台灣 授權條款釋出。
全站熱搜