天天看點

UTC時間轉本地時間用于PLC的校時(帶程式)

UTC時間轉本地時間用于PLC的校時(帶程式)

UTC時間,也稱協調世界時,是以原子時為基礎,在時刻上盡量接近世界時的一種時間計量系統。在某些對時間要求較為嚴格的應用場合(如事故記錄),由于PLC本身的RTC(Real Time Clock)會有一定的走時誤差,我們可能需要從GPS\北鬥等星座導航系統擷取時間資訊對PLC進行比較高頻的時間同步。​此時,我們會發現,GPS\北鬥接收機以1秒為周期向外發送資料的時間部分,其時間格式往往是UTC時間而不是PLC所在地的時間,比如我們在國内使用的中原標準時間。在下面這段北鬥接收機發送的GNRMC封包中,070618表示目前的UTC日期為2018年6月7日,083904.000表示目前的UTC時間為8點39分04秒。

$GNRMC,083904.000,A,3904.59971,N,11705.13873,E,0.068,5.63,070618,,*2C

這就需要我們在對PLC校時之前,将UTC時間轉換為本地時間。下面将以中原標準時間為例,對轉換方法進行展示。

Part A

算法思路

由于這裡我們隻考慮中原標準時間,而北京是處在時區的東八區,故簡單來說就是把UTC時間加8小時即得到了中原標準時間。但是,在對小時數加8的時候,我們會遇到如下問題:

(1) 如果小時數+8大于了24小時,我們需要對天數+1;

(2) 如果對天數+1後,所在月份的天數有大于了本月的最大天數,我們需要對月份+1;

(3) 如果對月份+1後,月份值大于了12,則需要對年份+1;

(4) 每月的天數是不一樣的,有30天,31天,2月份根據是平年和閏年的不同有28天和29天的差別。

Part B

程式實作

1. %T10015是之前程式産生的校時脈沖,這裡假設UTC時間以秒,分,時,日,月,年的格式存放在PLC的寄存器中,位址為從%R20001-R20006,資料格式INT。我們首先對UTC小時%R20003加8,得到待比較的新的%R20003。然後我們根據月份的不同,對每月的最大天數進行指派,資料存放在%R20008中。如果是2月份,則暫緩指派,待後面程式處理。

UTC時間轉本地時間用于PLC的校時(帶程式)
UTC時間轉本地時間用于PLC的校時(帶程式)

2. 然後,我們對2月份是否是閏年的月份進行讨論。某年是否是閏年的判斷方法如下:

(1) 如果年份是世紀年,則能被400整除的是閏年。(如2000年是閏年,1900年不是閏年)

(2) 如果年份是普通年,則能被4整除且不能被100整除的為閏年。(如2008年就是閏年,1900年不是閏年)

按照以上方法,我們使用MOD(取餘)運算之後進行比較,最後如果目前年份是閏年,則2月最大天數為29天;如果是平年,則為28天。

UTC時間轉本地時間用于PLC的校時(帶程式)

3. 然後,我們再對+8小時後的時間進行分情況讨論:

(1) 當算出的時間大于或等于24:00時,應減去24:00,日期加一天;

(2) 當算出的日期大于該月最後一天的日期時,應減去該月最後一天的日期,月份加1;

(3) 當算出的月份大于12時,應減去12,年份加上一年。

UTC時間轉本地時間用于PLC的校時(帶程式)

4. 最後,調用PLC内的校時函數,我們可以使用計算得到的結果對PLC進行校時。

UTC時間轉本地時間用于PLC的校時(帶程式)

5. 程式實際運作效果如下:在HORNER的XL4控制器上,我們假定UTC時間為2016-2-28 19:56:04,因為2016年為閏年,故轉換後的時間為2016-2-29 03:56:04。

UTC時間轉本地時間用于PLC的校時(帶程式)

Part C

結語

1. 以上算法僅列出了中原標準時間(東8區)的轉換方式,如果是東區時間,僅需要修改增加的小時數n的數值即可。但如果是西區時間,則增加的小時數會變為負數。并且程式需要按相反的方向思考,即減n小時之後如果時間小于了0時,或小于了1日,或小于了1月後如何對日期進行處理。

2. 如果UTC時間是來源于GPS/北鬥等星座系統,在實際運作中,應考慮如果接收機無法收到信号後,應停止校時動作,由PLC本身的RTC進行走時,待信号恢複後再進行校準。

3. 如果裝置在不同時區間變化,比如在船舶上,則可能需要根據解析到的經度資料,判斷出所在時區後,再進行校正。

4. ST語言的版本如下:​

If Calibrate Then //Calibrate是觸發脈沖,對每月最大有多少天進行分情況讨論
    Case UTC_Month of
        1,3,5,7,8,10,12:
          Day_Max := 31;
        4,6,9,11:
          Day_Max := 30;
        2: //如果是世紀年,能被400整除的是閏年;如果是普通年,可以被4整除,但不被100整除的是閏年
          IF ((UTC_Year MOD 400) = 0) OR (((UTC_Year MOD 4) = 0) And ((UTC_Year MOD 100) <> 0)) Then
            Day_Max := 29;
          Else
            Day_Max := 28;
          End_IF;
    End_Case;
//CALTIME是定義的INT型數組,6個WORD,分别存放最後校準的秒,分,時,日,月,年
    CALTIME[0] := UTC_Second;
    CALTIME[1] := UTC_Minute;    
這裡按東8區進行運算
    CALTIME[3] := UTC_Day;
    CALTIME[4] := UTC_Month;
    CALTIME[5] := UTC_Year;

    If CALTIME[2] >= 24 Then //當算出的時間大于或等于24:00時,應減去24:00,日期加一天
        CALTIME[2] := CALTIME[2] - 24;
        CALTIME[3] := CALTIME[3] + 1;
    End_if;

    If CALTIME[3] > Day_Max Then //算出的日期大于該月最後一天的日期時,應減去該月最後一天的日期,月份加1
        CALTIME[3] := CALTIME[3] - Day_Max;
        CALTIME[4] := CALTIME[4] + 1;
    End_if;

    If CALTIME[4] > 12 Then //算出的月份大于12時,應減去12,年份加上一年
        CALTIME[4] := CALTIME[4] - 12;
        CALTIME[5] := CALTIME[5] + 1;
    End_if;

    SETCLK(CALTIME); //調用校時指令校時
END_IF;      
UTC時間轉本地時間用于PLC的校時(帶程式)

作者簡介