天天看點

使用Arduino做一個時鐘?鬧鐘?定時啟動裝置?真的超簡單!!

作者:藍戰科技

問題

您想在代碼中使用當天的時間(小時,分鐘和秒),而且您不想連接配接外部硬體。

使用Arduino做一個時鐘?鬧鐘?定時啟動裝置?真的超簡單!!

解決方案

此代碼使用Time庫來顯示當天的時間。可以使用Arduino庫管理器安裝Time庫(如果您無法找到它,請嘗試在Arduino庫管理器中搜尋“timekeeping”):

/*
 * 時間示例
 */
#include <TimeLib.h>

void setup()
{
 Serial.begin(9600);
 setTime(12,0,0,1,1,2020); // 将時間設定為2020年1月1日中午12點
}

void loop()
{
 digitalClockDisplay();
 delay(1000);
}

// 使用前導0填充數字
String padDigits(int digit)
{
 String str = String("0") + digit; // 在數字前加0
 return str.substring(str.length() - 2); // 删除除最後兩個字元外的所有字元
}

void digitalClockDisplay(){
 String timestr = String(hour()) + ":" + padDigits(minute()) + ":" + padDigits(second());
 Serial.println(timestr);
 
 String datestr = String(year()) + "-" + padDigits(month()) + "-" + padDigits(day());
 Serial.println(datestr);
}           

Time庫使您能夠跟蹤日期和時間。許多Arduino闆使用石英晶體進行計時,每天精度為幾秒,但它沒有電池來在斷電時記憶時間。是以,每次啟動程式時時間都會從0開始,是以您需要使用setTime函數設定時間。

該程式在每次啟動時将時間設定為2020年1月1日中午12點。 Time庫使用Unix時間标準(也稱為POSIX時間或紀元時間)。這些值表示自1970年1月1日以來經過的秒數。有經驗的C程式員可能會認識到,這與用于存儲時間值的ISO标準C庫中使用的time_t相同。

當然,将時間設定為您目前的本地時間而不是固定值更加有用。以下草圖從序列槽擷取數字時間值(自1970年1月1日以來經過的秒數),以設定時間。您可以使用串行螢幕輸入值(目前的Unix時間可以在許多網站上找到,包括Epoch Converter):

#include <TimeLib.h>

#define TIME_HEADER 'T' // 串行時間同步消息的頭标簽

void setup()
{
    Serial.begin(9600);
    Serial.println("Waiting for time sync message");
}

void loop()
{
    if (Serial.available())
    {
        processSyncMessage();
    }

    if (timeStatus() != timeNotSet)
    {
        // 顯示時間和日期
        digitalClockDisplay();
    }
    delay(1000);
}

// 帶前導零的數字填充

String padDigits(int digit)
{
    String str = String("0") + digit; // 在數字前面加上零
    return str.substring(str.length() - 2); // 隻保留最後兩個字元
}

void digitalClockDisplay()
{
    String timestr = String(hour()) + ":" + padDigits(minute()) +
    ":" + padDigits(second());
    Serial.println(timestr);
    String datestr = String(year()) + "-" + padDigits(month()) +
    "-" + padDigits(day());
    Serial.println(datestr);
}

// 解析時間消息
void processSyncMessage()
{
    time_t pctime = 0;
    if (Serial.find(TIME_HEADER))
    {
        pctime = Serial.parseInt();
        setTime(pctime); // 将時鐘設定為從序列槽接收到的時間
    }
}           

顯示時間和日期的代碼與以前相同,但現在草圖等待從序列槽接收時間。

Time庫示例中包含一個名為SyncArduinoClock的Processing Sketch(在Time/Examples/Processing/SyncArduinoClock檔案夾中)。這個Processing Sketch可以在單擊滑鼠時将目前時間從計算機發送到Arduino。在Processing中運作SyncArduinoClock,確定序列槽是連接配接到Arduino的序列槽(第4章描述了如何運作與Arduino通信的Processing Sketch)。你應該會看到Arduino發送的消息“Waiting for time sync message”顯示在Processing文本區域中(Processing IDE底部的黑色文本消息區域)。單擊Processing應用程式視窗(它是一個200像素的灰色正方形),你應該可以看到Arduino Sketch列印的時間在文本區域中顯示出來。

如果你可以擷取目前的Unix時間,也可以通過串行螢幕設定時鐘;Epoch Converter是提供此格式時間的許多網站之一。確定你使用的轉換器配置為微秒(至少為10位數字,直到2286年);如果配置為毫秒,則該數字将大1000倍。複制訓示為目前Unix時間的10位數字,将其粘貼到串行螢幕發送視窗中。在數字前加上字母T,然後單擊“Send”。例如,如果你發送以下内容:

T1282041639

Arduino應該會每秒顯示時間:

10:40:49 17 8 2019

10:40:50 17 8 2019

10:40:51 17 8 2019

10:40:52 17 8 2019

10:40:53 17 8 2019

10:40:54 17 8 2019

. . .

你也可以使用按鈕或其他輸入裝置(如傾斜傳感器、操縱杆或旋轉編碼器)來設定時間。

以下草圖使用兩個按鈕向前或向後移動時鐘的“指針”。下圖顯示了連接配接方式:

/*
AdjustClockTime sketch
buttons on pins 2 and 3 adjust the time
*/
#include <TimeLib.h>
const int btnForward = 2; // 按鈕向前移動時間
const int btnBack = 3; // 按鈕向後移動時間
unsigned long prevtime; // 上次顯示時鐘的時間
void setup()
{
    pinMode(btnForward, INPUT_PULLUP); // 啟用内部上拉電阻
    pinMode(btnBack, INPUT_PULLUP);
    setTime(12, 0, 0, 1, 1, 2020); // 開始時間設定為2020年1月1日中午12點
    Serial.begin(9600);
}
void loop()
{
    prevtime = now(); // 記錄時間
    while (prevtime == now()) // 一直在這個循環中直到秒數改變
    {
        // 檢查是否在等待秒數翻轉時按下設定按鈕
        if (checkSetTime())
            prevtime = now(); // 時間已改變,重置開始時間
    }
    digitalClockDisplay();
}

// 函數檢查是否應調整時間
// 如果時間已更改,則傳回true
bool checkSetTime()
{
    int step; // 要移動的秒數(如果為負數,則向後移動)
    bool isTimeAdjusted = false; // 如果已調整時間,則設定為true
    step = 1; // 準備向前移動
    while (digitalRead(btnForward) == LOW)
    {
        adjustTime(step);
        isTimeAdjusted = true; // 告訴使用者時間已更改
        step = step + 1; // 下一步将更大
        digitalClockDisplay(); // 更新時鐘
        delay(100);
    }
    step = -1; // 負數向後移動
    while (digitalRead(btnBack) == LOW)
    {
        adjustTime(step);
        isTimeAdjusted = true; // 告訴使用者時間已更改
        step = step - 1; // 下一步将更大的負數
        digitalClockDisplay(); // 更新時鐘
        delay(100);
    }
    return isTimeAdjusted; // 告訴使用者是否已調整時間
}
// 使用前導0填充數字
String padDigits(int digit)
{
    String str = String("0") + digit; // 在數字前面加上0
    return str.substring(str.length() - 2); // 删除所有但最後兩個字元
}
void digitalClockDisplay()
{
    String timestr = String(hour()) + ":" + padDigits(minute()) +
    12.4 Using Arduino as a Clock | 459
":" + padDigits(second());
    Serial.println(timestr);

    String datestr = String(year()) + "-" + padDigits(month()) +
    "-" + padDigits(day());
    Serial.println(datestr);
}
           
使用Arduino做一個時鐘?鬧鐘?定時啟動裝置?真的超簡單!!

上圖使用兩個按鈕調整時間。

這個示例使用到上面定義的digitalClockDisplay和printDigits函數,是以在運作此示例之前請先複制這些函數。 這是一個變種,它使用可變電阻的位置來确定在按下開關時調整時間的方向和速率:

#include <TimeLib.h>
const int potPin = A0; // 用于确定方向和速度的電位器
const int buttonPin = 2; // 按鈕啟用時間調整
unsigned long prevtime; // 上次顯示時鐘的時間
void setup()
{
    digitalWrite(buttonPin, HIGH); // 啟用内部上拉電阻
    setTime(12, 0, 0, 1, 1, 2020); // 從2020年1月1日中午12點開始
    Serial.begin(9600);
}
void loop()
{
    prevtime = now(); // 記錄時間
    while (prevtime == now()) // 一直循環,直到秒數變化
    {
        // 檢查是否在等待秒數翻轉期間按下設定按鈕
        if (checkSetTime())
            prevtime = now(); // 時間已經改變,重置起始時間
    }
    digitalClockDisplay();
}
// 函數用于檢查是否應該調整時間
// 如果時間已經改變則傳回true
bool checkSetTime()
{
    int value; // 從電位器讀取的值
    int step; // 要移動的秒數(如果是負數則向後移動)
    bool isTimeAdjusted = false; // 如果時間已經調整則設定為true
    while (digitalRead(buttonPin) == LOW)
    {
        // 按鈕按下時執行此處代碼
        value = analogRead(potPin); // 讀取電位器的值
        step = map(value, 0, 1023, 10, -10); // 将值映射到所需範圍
        if (step != 0)
        {
            adjustTime(step);
            isTimeAdjusted = true; // 告訴使用者時間已經改變
            digitalClockDisplay(); // 更新時鐘
            delay(100);
        }
    }
    return isTimeAdjusted;
}           

下圖顯示了可變電阻和開關的連接配接方式。如果您使用的是不支援5伏特的3.3伏特闆,請将可變電阻的正極連接配接到3.3V而不是5V。 所有這些示例都列印到串行端口,但您也可以将輸出列印到LED或LCD上。在12.9節中涵蓋的圖形LCD的下載下傳包含了使用在LCD上繪制的模拟時鐘顯示來顯示和設定時間的示例。Time庫包含友善的函數,用于将各種時間格式進行轉換。例如,您可以找出從一天開始已經過去了多少時間,以及到當天結束還有多少時間。

使用Arduino做一個時鐘?鬧鐘?定時啟動裝置?真的超簡單!!

個可變電阻用于調節時間

你可以檢視位于libraries檔案夾中的TimeLib.h擷取完整的函數清單。

dayOfWeek(now()); //傳回星期幾(星期日為第1天)

elapsedSecsToday(now()); //傳回從今天開始到現在經過的秒數

nextMidnight(now()); //距離今天結束還有多少時間

elapsedSecsThisWeek(now()); //從本周開始到現在經過的時間

你也可以列印出星期和月份的文本字元串。以下是一種基于數字時鐘顯示代碼的變體,它列印出星期和月份的名稱:

void digitalClockDisplay()
{
    String timestr = String(hour()) + ":" + padDigits(minute()) +
    ":" + padDigits(second());
    Serial.println(timestr);
    String datestr = String(dayStr(weekday())) + ", " +
    String(monthShortStr(month())) + " " + String(year());
    Serial.println(datestr);
}           

繼續閱讀