樹莓派:光陰的故事

Vamei發表於2017-01-05

作者:Vamei 出處:http://www.cnblogs.com/vamei 嚴禁任何形式轉載。

 

對於電子裝置來說,時間都是基礎性的功能,也很容易被人忽視。上世紀的“千年蟲”問題,就是時間方面設計缺陷造成的。對於網路連線的多裝置來說,保持時間同步又是一個新的問題。對於樹莓派的眾多應用情景來說,時間的準確性都至關重要。

 

NTP服務

樹莓派中內建了NTP服務,所以連上網之後就可以自動調整時間。NTP是網路時間協議(Network Time Protocol)的簡稱,主要用於網路時間的同步。NTP協議早在80年代就已經誕生,至今還是網際網路的基礎性協議之一。NTP通訊分為伺服器和客戶端兩方。客戶端發出的資料包中,包含有發出時客戶端的時間。伺服器收到資料包並回復。回覆的資料包中,附加了伺服器收到和發出資料包的時間。客戶端收到回覆後,就可以獲得網路延遲時間,以及自己和伺服器的時間差。客戶端據此調整自己的時鐘,就可以與伺服器時間保持同步。

NTU客戶與伺服器

 

你可以通過下面命令來查詢當前使用的NTP伺服器:

sudo ntpq -pn

 命令返回:

     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
 203.135.184.123 .GPS.            1 u  322   64   20  365.136   -7.571  15.792
 223.112.179.133 .INIT.          16 u    - 1024    0    0.000    0.000   0.000
*202.112.29.82   202.118.1.46     2 u  122   64  276   53.148    0.766   0.868

行首加*號的是當前伺服器。此外,還列出了網路延遲時間(delay)、與伺服器時間差(offset)等關鍵的NTP時間資料。單位是milliseconds。

 

如果NTP服務出現問題,造成樹莓派時間錯誤,可以強制要求NTP對錶: 

sudo service ntp stop
sudo ntpd -gq
sudo service ntp start

上面的第一句和第三句分別用於停止和啟動NTP服務。 

 

不使用NTP,你也可以手動調整系統時間: 

sudo date -s "1 Jan 2017 00:00:00"

即把系統時間調整為2017年1月1日00:00:00。

  

然後用date命令來顯示系統當前時間:

date

 

時區設定

地球自西向東轉到。所以,全球不同經度地點的日出日落以及正午的時間不同。人們又習慣於用同樣的12點來代表正午,這意味著不同經度的人要用不一樣的表。可是,如果人每時每刻都要根據經度調錶,就會非常麻煩。因此,地球以15度的經度來劃分時區,一個時區內的表用統一的時間,向東跨過一個時區,就需要把表調快1小時。當然,時區的劃分不是嚴格的按照15度。比如說,一些地跨多個時區的國家有可能用統一一個時區,例如中國。下面是地球上時區分佈的地圖。

 

對於不同地區的使用者來說,往往需要把樹莓派調整成當地的時區。你可以用raspi-config進入到樹莓派的設定頁面,在"4 Localisation Options"->"I2 Change Timezone"中修改時區。

當然,你也可以用下面的命令手動修改:

sudo cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

注意到,/user/share/zoneinfo中有多個以各大洲名字命令的資料夾,裡面的檔案以該州的主要城市命名。把對應城市的檔案複製到/etc/localtime,就可以把系統的時區設成該城市所用的時區。這裡我把時區修改為"Shanghai",也就是上海。修改之後,用date命令檢視時間,可以看到時區簡寫變成CST,也就是“上海時間”的縮寫:

Tue  3 Jan 20:42:24 CST 2017

 

用date命令檢視UTC時間:

date -u

顯示的時間正好相差8個小時:

Tue  3 Jan 12:42:24 UTC 2017

 

實時時鐘

大多數電腦在主機板上包含了一個實時時鐘(RTC,Real Time Clock)。實時時鐘是一個有電源的表,能在電腦斷電時繼續計時。因此,電腦斷電後一天再開機,你會發現電腦的時鐘也往前走了一天。但樹莓派並不包含一個實時時鐘。因此,如果樹莓派斷電一天再開機,在NTP服務校正時間之前,你會發現樹莓派的時間還停留在一天前。為了克服這一問題,你可以給樹莓派附加一個實時時鐘,比如PiFace專門為樹莓派設計的實時時鐘。

這個實時時鐘設計成一個使用鈕釦電池的電路板。把PiFace電路板的孔對準樹莓派的GPIO針腳插入,就可以使用了。插入位置如下圖所示。插入正確的情況下,電池正好在樹莓派CPU的上方。網上也有人詬病這一設計,認為電池的發熱會影響樹莓派CPU的散熱。不過我在使用中並沒有太大問題。

為了使用這款實時時鐘,我還需要進行一些設定。首先,這塊電路板是通過I2C介面與樹莓派通訊的,所以要在raspi-config的頁面中開啟I2C介面。然後,安裝所需的工具包: 

sudo apt-get install i2c-tools
sudo apt-get install python-smbus

 

接下來,賦予使用者pi使用I2C介面的許可權:

sudo usermod -aG i2c pi

 

開啟檔案/etc/modules,這裡面列出了系統可以載入的模組。檢查是否有如下兩行。如果沒有的話請新增:

i2c-dev
i2c-bcm2708

 

下面一段程式修改自官網程式,用來讓樹莓派在開機時自動載入實時時鐘。把下面程式儲存為rtc.bash,並執行:

#!/bin/bash

#=======================================================================
# NAME: set_revision_var
# DESCRIPTION: Stores the revision number of this Raspberry Pi into
#              $RPI_REVISION
#=======================================================================
set_revision_var() {
    revision=$(grep "Revision" /proc/cpuinfo | sed -e "s/Revision\t: //")
    RPI2_REVISION=$((16#a01041))
    RPI3_REVISION=$((16#a02082))
    if [ "$((16#$revision))" -ge "$RPI3_REVISION" ]; then
        RPI_REVISION="3"
    elif [ "$((16#$revision))" -ge "$RPI2_REVISION" ]; then
        RPI_REVISION="2"
    else
        RPI_REVISION="1"
    fi
}

#=======================================================================
# NAME: start_on_boot
# DESCRIPTION: Load the I2C modules and send magic number to RTC, on boot.
#=======================================================================
start_on_boot() {
    echo "[info]Create a new pifacertc init script to load time from PiFace RTC."
    echo "[info]Adding /etc/init.d/pifacertc ."

    if [[ $RPI_REVISION == "3" ]]; then
        i=1  # i2c-1
    elif [[ $RPI_REVISION == "2" ]]; then
        i=1  # i2c-1
    else
        i=0  # i2c-0
    fi

    cat > /etc/init.d/pifacertc  << EOF
#!/bin/sh
### BEGIN INIT INFO
# Provides:          pifacertc
# Required-Start:    udev mountkernfs \$remote_fs raspi-config
# Required-Stop:
# Default-Start:     S
# Default-Stop:
# Short-Description: Add the PiFace RTC
# Description:       Add the PiFace RTC
### END INIT INFO

. /lib/lsb/init-functions

case "\$1" in
  start)
    log_success_msg "Probe the i2c-dev"
    modprobe i2c-dev
    # Calibrate the clock (default: 0x47). See datasheet for MCP7940N
    log_success_msg "Calibrate the clock"
    i2cset -y $i 0x6f 0x08 0x47
    log_success_msg "Probe the mcp7941x driver"
    modprobe i2c:mcp7941x
    log_success_msg "Add the mcp7941x device in the sys filesystem"
    # https://www.kernel.org/doc/Documentation/i2c/instantiating-devices
    echo mcp7941x 0x6f > /sys/class/i2c-dev/i2c-$i/device/new_device
    log_success_msg "Synchronise the system clock and hardware RTC"
    hwclock --hctosys
    ;;
  stop)
    ;;
  restart)
    ;;
  force-reload)
    ;;
  *)
    echo "Usage: \$0 start" >&2
    exit 3
    ;;
esac
EOF
    chmod +x /etc/init.d/pifacertc

    echo "[info]Install the pifacertc init script"
    update-rc.d pifacertc  defaults
}

set_revision_var &&
start_on_boot

 

完成後重啟電腦。此時樹莓派應該已經自動通過I2C介面載入了實時時鐘。你可以通過下面命令來檢查實時時鐘是否就位:

sudo i2cdetect -y 1

如果就位,那麼60開頭的行會有一個"UU"的標準位。你可以通過下面的命令,讀出實時時鐘的時間:

sudo hwclock -r 

你可以通過下面的命令,把當前系統時間寫入實時時鐘:

sudo hwclock --systohc

 

有了實時時鐘,你就可以在無網環境下保持時間的連續性。PiFace的產品賣得有一些貴。淘寶上還有一些便宜的實時時鐘可以選購。另外,PiFace官網速度很慢。需要說明書的,可以在這裡下載 

 

date用例

文章中多處使用了date命令。date是UNIX系統下常用的時間命令工具,能提供非常豐富的時間功能,比如以特定格式顯示時間:

date +"%Y year %m month %d day"

+號後面的字串代表了時間顯示格式。%開頭的識別符號會用時間資訊填充。%Y代表了年,%m代表了month,%d代表了日期。所以上面命令返回:

2017 year 01 month 01 day

更多的識別符號可以通過man date來查詢文件。

 

date不一定只顯示當前時間,它還可以用來顯示一個使用者輸入的時間:

date --date="2017/01/03 12:00:00"

這個功能看起來有些雞肋,但實際上可以用於時間推算。比如說下面的命令就可以用於推算2016年11月12日之前1個月的時間:

date --date="2016/11/12 -1 month"

除了"-1 month",還可以是"+1 second"、"-2 day"等多種時間差,能滿足各種各樣的時間推算需求。

 

date的功能極為豐富,這裡只列出了一些常見用例。其他使用可以參考man date的文件。

 

總結

樹莓派提供了NTP服務,通過網路來校正時間。即使在斷網情況下,也可以物理計時實施來校正時間。而樹莓派使用的Linux系統,也提供了date這樣便利的時間工具。

 

歡迎閱讀“騎著企鵝採樹莓”系列文章 

相關文章