2020年5月30日 星期六

ROSA 2020 系統開發 2 ─ 投幣計時器 (4rdp Timer)

https://4rdp.blogspot.com/2020/05/rosa-2020-2-4rdp-timer.html

每次創客活動擺攤,4rdp 益智拼圖攤位前總是一堆遊客玩拼圖,因此讓我興起十元投幣贈獎的念頭,設計一個投幣計時器,投入十塊錢開始計時,只要五分鐘內排好拼圖,現場獎品隨便挑,反正家中很多雜物藉機出脫,即使拼圖沒賣出一個,總是有人會殺時間嘗試拼圖能力吧!

去年因參加創客比賽,學會雷切木盒子設計,因此計時器從外觀設計到內部電路及程式設計,一手包辦,下次擺攤時,這個計時器就可以讓遊客們打賞使用。

電路的挑選就是 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.998
  if (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.998
  if (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--;
      }
      }
    }
  }
}

延伸閱讀

3 則留言: