2017/03/19

Arduino練習:RTC即時時鐘PCF8523

之前曾用過RTC即時時鐘DS1307,自買零件組裝,這篇則購買Adafruit的RTC即時時鐘PCF8523電路板模組

我的環境:Windows 10,Arduino IDE 1.8.1,Arduino Uno板子。

這款PCF8523模組的基本資料:

  • 工作電壓:3.3V或5V
  • 電池:CR1220
  • 精確度:不高,一天可能誤差2秒
  • 介面:I2C,位址0x68
正面照,左邊有5個腳位,右邊要裝電池CR1220。
背面照。
準備一顆CR1220電池。
線路很簡單:
Arduino Uno的5V,接到這款產品的VCC。
Arduino Uno的GND,接到這款產品的GND。
Arduino Uno的A4,接到這款產品的SDA。
Arduino Uno的A5,接到這款產品的SCL。

這款產品的SQW,不接。
近照。
以上是硬體部分,軟體部分要安裝Adafruit的程式庫RTClib。到Arduino IDE選單-草稿碼-匯入程式庫-管理程式庫...,開啟程式庫管理員,找到「RTClib by Adafruit」,安裝。
便可在Arduino IDE選單-檔案-範例-RTClib-pcf8523找到範例程式。
編譯並燒錄,開啟序列埠監控視窗,出現如下畫面。
這支範例程式,會把草稿碼編譯的日期時間,設定到RTC裡,所以第一行會出現正確的日期時間,後兩行則是測試用,計算7天又12小時又30分又6秒之後的日期時間。

參考資料:
DS1307 Real Time Clock Breakout Board Kit | Adafruit Learning System

15 comments:

  1. 葉大 請問一下 我想用呼吸燈的形式,可是我不要讓它自動閃滅,我要用監控來給數值給它多少就亮多少的亮度 麻煩您

    ReplyDelete
    Replies
    1. 不麻煩。
      你提的是需求,不是問題。
      請問你碰上什麼問題嗎?

      Delete
  2. 懇請指教!
    不才想擷取四個訊號如下
    電磁閥趨動上行訊號
    電磁閥趨動下行訊號
    氣壓缸上行死點訊號
    氣壓缸下行死點訊號
    想用此訊號計算出趨動訊號改變時氣壓缸移動所花費之時間
    四個布林是想讓程式上報時只報一次

    # define solenoid_down 3
    # define solenoid_up 2
    # define sensor_down 5
    # define sensor_up 4
    # define led_pin 13
    # define SERIAL_BAUDRATE 19200

    void setup()
    {
    pinMode (solenoid_down, INPUT);
    pinMode (solenoid_up, INPUT);
    pinMode (sensor_up, INPUT);
    pinMode (sensor_down, INPUT);
    pinMode (led_pin,OUTPUT);
    Serial.begin(SERIAL_BAUDRATE);
    }

    void loop()
    {
    unsigned long time_previous;
    unsigned long time_current;
    int ut1;
    int ut2;
    int dt1;
    int dt2;
    boolean r;
    boolean q;
    boolean p;
    boolean t;
    int uso = digitalRead (solenoid_up);
    int use = digitalRead (sensor_up);
    int dso = digitalRead (solenoid_down);
    int dse = digitalRead (sensor_down);


    // step 1
    if (dso == HIGH && uso == LOW && dse == HIGH && use == LOW )
    {
    if (t == true)
    {
    dt2 = time_current - time_previous;
    Serial.print ("dt2=");
    Serial.println (dt2);
    }
    t = false ;
    time_previous = millis();

    }

    // step 2
    if (dso == LOW && uso == HIGH && dse == HIGH && use == LOW)
    {
    time_current = millis();
    p = true ;
    }
    // step 3
    if (dso == LOW && uso == HIGH && dse == LOW && use == LOW)
    {
    if (p == true )
    {
    ut1 = time_current - time_previous;
    time_previous = time_current;
    Serial.print ("ut1=");
    Serial.println(ut1);
    }
    p = false ;
    time_current = millis();
    q = true ;
    }
    // step 4
    if (dso == LOW && uso == HIGH && dse == LOW && use == HIGH)
    {
    if (q == true )
    {
    ut2 = time_current - time_previous;
    Serial.print("ut2=");
    Serial.println(ut2);
    }
    q = false ;
    time_previous = millis();
    }
    // step 5
    if (dso == HIGH && uso == LOW && dse == LOW && use == HIGH)
    {
    r = true ;
    time_current = millis();
    }
    // step 6
    if (dso == HIGH && uso == LOW && dse == LOW && use == LOW)
    {
    if (r == true )
    {
    dt1 = time_current - time_previous;
    time_previous = time_current;
    Serial.print("dt1=");
    Serial.println(dt1);
    }
    r = false ;
    time_current = millis();
    t = true ;
    }


    }

    ReplyDelete
    Replies
    1. 當 氣壓缸上行死點訊號 為 HIGH時,
      電磁閥趨動 是不是就會停止?

      Delete
    2. 不會
      電磁閥上行趨動訊號會保持存在

      Delete
    3. > 想用此訊號計算出趨動訊號改變時氣壓缸移動所花費之時間
      請再說清楚一點。
      要量哪裡到哪裡的時間?要量哪個狀況到哪個狀況之間的花費時間?

      Delete
    4. 電磁閥趨動上行訊號觸發後氣缸會由下死點移動至上死點
      電磁閥趨動上行訊號會保持到下行訊號趨動前解除
      電磁閥趨動下行訊號觸發後氣缸會由上死點移動至下死點
      電磁閥趨動下行訊號會保持到上行訊號趨動前解除
      電磁閥趨動及氣缸動作會呈現一有限狀態機的結果一直循環(您的書上有教過但我沒試過,我想以自己的想法寫)
      在step1時電磁閥下行訊號及氣缸下死點訊號為真(若承接step6則計算及上報一次dt2,以布林t做為旗標)
      在step2時電磁閥下行訊號解除,電磁閥上行訊號觸發,此時高壓氣體尚未進入缸體,故下死訊號為真,以布林p做為旗標
      在step3時因高壓氣體進入缸體,故下死訊號會消失,在此計算出電磁閥上行訊號起,到下死訊號消失之時間差ut1並上報一次
      在step4時高壓氣體持續推動氣缸直到上死感測器訊號觸發,在此計算出下死訊號消失至上死訊號觸發之時間差ut2並上報一次
      step5~step6~step1則為下行的循環
      我不知是否為以下宣告問題,是否提至全域較佳?
      int ut1;
      int ut2;
      int dt1;
      int dt2;
      boolean r;
      boolean q;
      boolean p;
      boolean t;

      Delete
    5. 有限狀態機我會再試試

      Delete
    6. 大概是這樣,試試吧,只通過編譯,我沒真實的東西可以測試。
      https://pastebin.com/Qrqxqtq1


      # define solenoid_down 3
      # define solenoid_up 2
      # define sensor_down 5
      # define sensor_up 4
      # define SERIAL_BAUDRATE 19200
      void setup()
      {
      pinMode (solenoid_down, INPUT);
      pinMode (solenoid_up, INPUT);
      pinMode (sensor_up, INPUT);
      pinMode (sensor_down, INPUT);
      Serial.begin(SERIAL_BAUDRATE);
      }

      unsigned long time_so = 0;
      unsigned long time_se = 0;

      void loop()
      {
      int uso = digitalRead (solenoid_up);
      int use = digitalRead (sensor_up);
      int dso = digitalRead (solenoid_down);
      int dse = digitalRead (sensor_down);

      /* 在step1時電磁閥下行訊號及氣缸下死點訊號為真(若承接step6則計算及上報一次dt2,以布林t做為旗標) */
      if (dso == HIGH && uso == LOW && dse == HIGH && use == LOW )
      {
      if (time_se != 0)
      {
      Serial.print ("dt2=");
      Serial.println (millis() - time_se);
      time_se = 0;
      }
      }
      /* 在step2時電磁閥下行訊號解除,電磁閥上行訊號觸發, 此時高壓氣體尚未進入缸體,故下死訊號為真,以布林p做為旗標 */
      else if (dso == LOW && uso == HIGH && dse == HIGH && use == LOW)
      {
      if (time_so == 0)
      {
      time_so = millis();
      }
      }
      /* 在step3時因高壓氣體進入缸體,故下死訊號會消失, 在此計算出電磁閥上行訊號起,到下死訊號消失之時間差ut1並上報一次 */
      else if (dso == LOW && uso == HIGH && dse == LOW && use == LOW)
      {
      if (time_so != 0)
      {
      time_se = millis();
      Serial.print ("ut1=");
      Serial.println(time_se - time_so);
      time_so = 0;
      }
      }
      /* 在step4時高壓氣體持續推動氣缸直到上死感測器訊號觸發, 在此計算出下死訊號消失至上死訊號觸發之時間差ut2並上報一次 */
      else if (dso == LOW && uso == HIGH && dse == LOW && use == HIGH)
      {
      if (time_se != 0)
      {
      Serial.print ("ut2=");
      Serial.println (millis() - time_se);
      time_se = 0;
      }
      }
      // step5; step5~step6~step1則為下行的循環
      else if (dso == HIGH && uso == LOW && dse == LOW && use == HIGH)
      {
      if (time_so == 0)
      {
      time_so = millis();
      }
      }
      // step 6
      else if (dso == HIGH && uso == LOW && dse == LOW && use == LOW)
      {
      if (time_so != 0)
      {
      time_se = millis();
      Serial.print ("dt1=");
      Serial.println(time_se - time_so);
      time_so = 0;
      }
      }
      else
      {
      Serial.println ("Error: wrong state.");
      }
      }

      Delete
  3. 感謝指教
    我試試看再向您回報

    ReplyDelete
  4. 感謝先生指導,不才以switch 測試結果
    會有error 的訊息 , 是彈跳的問題
    但整體的結果相當的成功,
    經此一案後不才得到的心得為:
    看先生的語法貌似 "SOP"
    不才的語法有如 "走馬看花"
    先生的參數用量精簡 , 不才的參數繁雜
    尚有一大段學習的路要努力
    再次感謝先生指導

    ReplyDelete
    Replies
    1. > 但整體的結果相當的成功,
      恭喜。

      > 參數用量精簡
      有多少功能、用多少程式碼。多了會造成困擾。

      > 參數繁雜
      邏輯不夠清楚的關係。多寫幾次、多練習,:D。

      Delete
    2. 我用的是有限狀態機的寫法,有6個狀態,
      也就是上面程式裡、最外圍的那些
      if (狀態1)
      else if(狀態2)
      else if(狀態3)
      else if(狀態4)
      else if(狀態5)
      else if(狀態6)

      Delete
    3. 我想用的是您書上寫的 typedef enum{}state; + switch (state)的寫法
      我會試著去改改看 感謝

      Delete
    4. 嗯,要釐清狀態變化。

      Delete