作者: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這樣便利的時間工具。
歡迎閱讀“騎著企鵝採樹莓”系列文章