上位机编程:CP56Time2a格式精讲

一 Cp56Time2a 介绍

        CP56Time2a 是电力系统和工业自动化中广泛使用的时间同步格式,通常用于 IEC 60870-5-101 和 IEC 60870-5-104 协议中。这个格式用于在远程终端单元 (RTU) 和主站 (Master) 之间传输时间信息,保证设备间的时钟同步。

二 CP56Time2a 格式

        CP56Time2a 是一个 7 字节(56 比特)的时间戳格式,包含从世纪、年、月、日到毫秒的时间信息,适用于精确时间同步。以下是具体的字段结构:

  1. 毫秒 (Millisecond) (16 bits): 表示秒的小数部分,以 1 毫秒为单位(0 - 59999),代表一个分钟中的具体时间点。
  2. 分钟 (Minute) (6 bits): 表示时间中的分钟部分(0 - 59)。最高位 (MSB) 是无效标志位(validity bit),当该位为1时,表示分钟字段无效。
  3. 小时 (Hour) (5 bits): 表示小时(0 - 23)。
  4. 天 (Day) (5 bits): 表示当前日期中的天数(1 - 31)。注意:该字段最高位为工作日标志位,表示当前的日期是否为工作日。
  5. 月 (Month) (4 bits): 表示月份(1 - 12)。
  6. 年 (Year) (7 bits): 表示年份的后两位(00 - 99),表示的范围为 2000 年到 2099 年。

     对应字节码相应位置如下:

  1.  字节位置0:包含秒值的低位部分。
  2.  字节位置1:包含秒值的高位部分。
  3.  字节位置3:分钟
  4.  字节位置4:小时(24小时制,0-23)
  5.  字节位置5:天(月份中的号数,1-31)
  6.  字节位置6:月份(1-12)
  7.  字节位置7:年份后两位(1-99)

        总的来说,Cp56Time2a格式使用了12个字节来表示完整的日期和时间信息,包括秒、毫秒、日、月、以及年份。

三 Cp56Time2a 编码

1 Cp56Time2a 编码与 解码

  • 编码:将当前时间转换为 CP56Time2a 格式(7 字节)。
  • 解码:从 7 字节的 CP56Time2a 格式还原为标准时间。 

  用 Java 实现 CP56Time2a 格式的编码解码的示例代码如下:

import java.nio.ByteBuffer;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Arrays;

public class CP56Time2a {
    
    // 编码当前时间为 CP56Time2a 格式
    public static byte[] encodeCP56Time2a(LocalDateTime dateTime) {
        ByteBuffer buffer = ByteBuffer.allocate(7);
        
        // 毫秒部分,1分钟 = 60,000毫秒
        int millis = (dateTime.getSecond() * 1000) + (dateTime.getNano() / 1000000);
        buffer.putShort((short) millis);

        // 分钟 (6 bits) + 有效性位 (1 bit)
        byte minute = (byte) dateTime.getMinute();
        buffer.put(minute);

        // 小时 (5 bits)
        byte hour = (byte) dateTime.getHour();
        buffer.put(hour);

        // 天 (5 bits) + 工作日标志 (1 bit)
        byte day = (byte) dateTime.getDayOfMonth();
        buffer.put(day);

        // 月份 (4 bits)
        byte month = (byte) dateTime.getMonthValue();
        buffer.put(month);

        // 年 (7 bits, 两位数年份)
        byte year = (byte) (dateTime.getYear() % 100);
        buffer.put(year);
        
        return buffer.array();
    }

    // 解码 CP56Time2a 格式为 LocalDateTime
    public static LocalDateTime decodeCP56Time2a(byte[] data) {
        ByteBuffer buffer = ByteBuffer.wrap(data);
        
        // 毫秒部分
        int millis = buffer.getShort() & 0xFFFF;
        int seconds = millis / 1000;
        int nanos = (millis % 1000) * 1000000;

        // 分钟
        int minute = buffer.get() & 0x3F;

        // 小时
        int hour = buffer.get() & 0x1F;

        // 天
        int day = buffer.get() & 0x1F;

        // 月
        int month = buffer.get() & 0x0F;

        // 年
        int year = 2000 + (buffer.get() & 0x7F);
        
        return LocalDateTime.of(year, month, day, hour, minute, seconds, nanos);
    }

    public static void main(String[] args) {
        // 获取当前时间
        LocalDateTime currentTime = LocalDateTime.now(ZoneOffset.UTC);
        System.out.println("当前时间: " + currentTime);

        // 编码当前时间为CP56Time2a格式
        byte[] encodedTime = encodeCP56Time2a(currentTime);
        System.out.println("编码后的CP56Time2a格式: " + Arrays.toString(encodedTime));

        // 解码回LocalDateTime
        LocalDateTime decodedTime = decodeCP56Time2a(encodedTime);
        System.out.println("解码后的时间: " + decodedTime);
    }
}

代码说明:

  1. 编码方法 (encodeCP56Time2a):将 LocalDateTime 转换为 7 字节的 CP56Time2a 格式,包括毫秒、分钟、小时、天、月、年。
  2. 解码方法 (decodeCP56Time2a):将 7 字节的数据转换回 LocalDateTime 对象,重新得到时间。

2  Cp56Time2a开发案例

  Cp56Time2a编码在开发过程会用到,如以下云快充协议要求就是用Cp56Time2a格式实现传输时间,协议需求开发文档如下图:

  用java实现时间格式转换Cp56Time2a编码,如下图:

/**
 * @author hua
 * @date 2023-09-18 15:33
 */
public class Cp56Time2aUtil {

   /**
     * 本地时间转Cp56Time2a
     * @param date
     * @return
     */
    public static byte[] toByteCp56Time2a(LocalDateTime date) {
        DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        System.out.println("下发时间:"+dtf.format(date));
        byte[] result = new byte[7];

        int seconds = date.getSecond();
        int milliseconds=seconds*1000;

        result[0] = (byte) (milliseconds % 256);
        result[1] = (byte) (milliseconds / 256);

        result[2] = (byte) date.getMinute();
        result[3] = (byte) date.getHour();
        result[4] = (byte) date.getDayOfMonth();
        result[5] = (byte) date.getMonthValue();
        result[6] = (byte) (date.getYear() % 100);
        return result;
    }


    /**
     * Cp56Time2a转时间字符串
     * @param b Cp56Time2a 数组
     * @return
     */
    public static String getTimeByCp56Time2a(byte[] b) {

        if (b.length == 7) {

            String str = "";
            int year = b[6] & 0x7F;
            int month = b[5] & 0x0F;
            int day = b[4] & 0x1F;
            int hour = b[3] & 0x1F;
            int minute = b[2] & 0x3F;
            int s0=b[0]&0xff;
            int s1 = ((b[1]&0xff)*256);
            int second = s0 + s1;

            str += "20" + year + "-"
                    + String.format("%02d", month) + "-"
                    + String.format("%02d", day) + " "
                    + String.format("%02d",hour) + ":"
                    + String.format("%02d",minute) + ":"
                    + String.format("%02d",second / 1000);
            return str + "\n";

        } else {
            System.out.println("无效格式");
            return "";
        }


    }

    

public static void main(String[] args) {

        //测试1  样例报文时间
        // 68(起始标志)12(数据长度)00DF(序列号域)00(加密标志)56(类型)55031412782305(桩编码)98B70E11100314(当前时间:2020-03-16 17:14:47)8A13(帧校验域)
        String time="98B70E11100314";
        byte[] b=HexTool.hexStringToBytes(time);
        System.out.println(time+" 还原示例报文时间 -> "+Cp56Time2aUtil.getTimeByCp56Time2a(b) );

        //测试2  当前报文时间
        byte[] curTime=Cp56Time2aUtil.toByteCp56Time2a(LocalDateTime.now());
        System.out.println(time+" gen cur time hex -> "+HexTool.bytesToHexString(curTime) );
        System.out.println("getTimeByCp56Time2a time str -> "+Cp56Time2aUtil.getTimeByCp56Time2a(curTime));


    }

}

main方法测试结果如下图:

测试结果正确,在实际开发过程中只需调用以上toByteCp56Time2a方法,把需要的时间按Cp56Time2a格式编码转换byte后直接下发到设备即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qyhua

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值