去年因參加創客比賽,學會雷切木盒子設計,因此計時器從外觀設計到內部電路及程式設計,一手包辦,下次擺攤時,這個計時器就可以讓遊客們打賞使用。
電路的挑選就是 Arduino Uno 和 LCD KeyPad 模組,一個按鈕 (停止鍵) 和微動開關 (偵測投幣)。
這個 LCD KeyPad 模組,使用 Arduino pin 4 ~ 9,pin 10 為背光控制,A0 是按鍵讀取的腳位,利用類比方式處理,因此不會占用過多數位腳,不過模組的按鍵這裡沒有使用。 另外這個投幣計時器使用 pin 3 偵測計時啟動,pin A1 偵測計時停止,這兩隻腳都設定數位輸入,並且 PULLUP,所以未按鍵時會讀到 1。
程式當然是使用 ROSA 2020,它使用了ROSA_BASE.cpp 、ROSA_DISPLAY.cpp、ROSA_TIMER.cpp 三個函式庫,ROSA_DISPLAY 內含 LCD KeyPad 驅動程式,並引用外部的程式庫 LiquidCrystal.h (Arduino 內含的程式庫)、LCDKeypad.h,ROSA_TIMER 函式可以處理碼錶正數和倒數計時,ROSA_BASE 除了基本時間和 IO 腳控制外,還加入 STRING,可將整數依據格式轉換成字串,這個 STRING 讓我花了五天時間把它最佳化,下一篇文章再仔細介紹設計的關鍵在哪裡。
現在繼續看 ROSA_Coin.ino 程式碼,系統使用 2ms 和10ms,2ms 用於碼錶計時,也是 ROSA 系統最小時間單位,10ms 為按鍵讀取時間間隔,原本設定 50ms 即可,不需要這麼密集,但是怕有人反應計時器按鍵反應遲鈍誤差高達 50ms,所以選擇 10ms,另外 Stop 按鍵持續一秒鐘,會把時間歸零。
// (C) 2019-2020, Bridan Wang, CC BY-NC-SA 3.0 TW // This is a demo program applied Robot Operating System for Arduino (ROSA) // http://4rdp.blogspot.tw/search/label/ROSA%20(Arduino) //軟件許可協議 // //研發養成所 Bridan Wang 提供此軟體供學校教育或個人單獨使用 //對外分享展示本軟體時,請說明來源來自研發養成所 //你可以架構在本軟體基礎上,設計新功能或修改 //本軟體屬於 Bridan 和或其它原始碼供應商,並受適用的法律版權保護 //此軟體按“原樣”提供,可能含有錯誤,不作任何明示,暗示或法律的保證 //本軟體僅限 Arduino 部分微控制器產品,適用於特定用途 // Bridan 在任何情況、環境以及特殊使用不負任何原因損害賠償責任 // //這是 ROSA 韌體版本的一部分。 // //建議使用 Arduino-1.8.8 以後版本編譯,因為有發現舊版本有錯誤情形 /*********************************************************** // System Condition DEFINE ************************************************************/ #define PRODUCT "ROSA- 4rdp Timer" #define VERSION "v2020.5.12" #define TIME_2ms // ROSA_TIME_2ms() #define TIME_10ms // ROSA_TIME_10ms() //#define TIME_50ms // ROSA_TIME_50ms() //#define TIME_100ms // ROSA_TIME_100ms() //#define TIME_250ms // ROSA_TIME_250ms() //#define TIME_500ms // ROSA_TIME_500ms() //#define TIME_1sec // ROSA_TIME_1sec() //#define TIME_SYSTEM // ROSA_TIME_SETUP() #define PROJECT_ROOT C:\Users\bridwang\Desktop\Bridan\ROSA_2020 #define TO_STRING(s) #s #define ABSOLUTE_PATH(root, relative_path) TO_STRING(root\relative_path) #define RELATIVE_PATH(library) ABSOLUTE_PATH(PROJECT_ROOT, library) /*********************************************************** // Include ************************************************************/ #include RELATIVE_PATH(ROSA\ROSA_BASE.cpp) #include RELATIVE_PATH(ROSA\ROSA_DISPLAY.cpp) #include RELATIVE_PATH(ROSA\ROSA_TIMER.cpp) ROSA_PIN key_start; ROSA_PIN key_stop; ROSA_LCD_KEYPAD lcd; ROSA_TIMER timer; /*********************************************************** // Main Program ************************************************************/ void setup() { timer.START(0, 0, 0, 0, 0); // start, hr, min, sec, msec key_start.SETUP(3, INPUT_PULLUP); // pin 3 key_stop.SETUP(A1, INPUT_PULLUP); // pin A1 lcd.SETUP(); // pin 4 ~ 9, 10, A0 DISPLAY_INITIAL(); } void loop() { ROSA_TIME_RUNNING(); // 系統時間處理 DISPLAY_UPDATE(); } /*********************************************************** // DISPLAY ************************************************************/ void DISPLAY_INITIAL() { lcd.CLEAR(); lcd.PRINT(PRODUCT); lcd.CURSOR(0,1); // 換行 lcd.PRINT(" 00:00:00.000"); } void DISPLAY_UPDATE() { lcd.CURSOR(2,1); // 換行 lcd.PRINT(STRING("%02d:", timer.hr)); lcd.PRINT(STRING("%02d:", timer.min)); lcd.PRINT(STRING("%02d.", timer.sec)); lcd.PRINT(STRING("%03d", timer.msec)); } /*********************************************************** // SYSTEM TIME ************************************************************/ void ROSA_TIME_2ms() { timer.RUNUP(); } void ROSA_TIME_10ms() { if (key_stop.IN()==0) { if (key_stop.count == 100) // 持續按 STOP 一秒 timer.START(0, 0, 0, 0, 0); // start, hr, min, sec, msec else { timer.start = 0; // 按一下 STOP key_stop.count++; } } else { key_stop.count = 0; if (key_start.IN()==0) // 投幣 START timer.START(1, 0, 0, 0, 0); // start, hr, min, sec, msec } }
關於 ROSA_DISPLAY.cpp 中的 ROSA_LCD_KEYPAD,它是繼承了 LiquidCrystal.h 和 LCDKeypad.h
#include <LiquidCrystal.h> #include <LCDKeypad.h> class ROSA_LCD_KEYPAD : public LCDKeypad { public: void SETUP(void); #define PRINT print #define CLEAR clear #define CURSOR setCursor }; void ROSA_LCD_KEYPAD::SETUP(void) { byte c_up[8] = { B00100, B01110, B10101, B00100, B00100, B00100, B00100, B00100, }; byte c_down[8] = { B00100, B00100, B00100, B00100, B00100, B10101, B01110, B00100, }; byte c_select[8] = { B00000, B01110, B11111, B11111, B11111, B11111, B01110, B00000, }; this->createChar(1,c_select); this->createChar(2,c_up); this->createChar(3,c_down); this->begin(16, 2); // init done }
而 ROSA_TIMER.cpp 中的 ROSA_TIMER,是自行設計的 Timer 物件,ROSA 系統允許同時多個 Timer 運作計時,可正數亦可倒數,各自獨立,時間範圍 00:00:00.000 ~ 99:59:59.998,它是運作在 ROSA 系統中 2ms 。
class ROSA_TIMER{public:byte start;byte hr;byte min;byte sec;int msec;void START(byte st, byte hr, byte min, byte sec, byte ms);void RUNUP(void);void RUNDOWN(void);};void ROSA_TIMER::START(byte st, byte h, byte m, byte s, byte ms) {start =st;hr = h;min = m;sec = s;msec = ms;}void ROSA_TIMER::RUNUP(void) { // 00:00:00.000 ~ 99:59:59.998if (start) {msec += INTERVAL;if (msec == 1000) {msec = 0;if (++sec == 60) {sec = 0;if (++min == 60) {min = 0;if (++hr == 100) {hr = 0;}}}}}}void ROSA_TIMER::RUNDOWN(void) { // 00:00:00.000 ~ 99:59:59.998if (start) {if (msec != 0) {msec -= INTERVAL;if (msec == 0 && (sec + min + hr == 0))start = 0; // stop} else {msec = 998;if (sec-- == 0) {sec = 59;if (min-- == 0) {min = 59;hr--;}}}}}
延伸閱讀
很有創意的打賞。
回覆刪除謝謝,有機會去新竹時,老師可以試試。
刪除好的。
刪除