【文献阅读】阅读IEC61162-1-2016

核心任务

我们想在PC机上串口调试助手相关的功能,进行复现,因为现在的串口调试助手exe是一个可执行文件,实际上,我们需要编写一个程序,处理雷达回来的数据,那首先就是先把这些目标先把它发给我的数据解析出来。从串口的这个界面上去抓取数据也可以。

个人理解:需要编写一个c或者MATLAB程序,把接收到的Character等信息,通过该程序解析其所包含的信息。因为其发送的数据一般是ASCII格式,不易阅读,我们需要在接收其信息的基础上,把其中含有的信息解析出来。

介绍

IEC161162是国际电工协会制定的海上通信标准协议。
在这里插入图片描述
数字接口由5部分组成:

  • 单讲器和多听器
  • 单讲器和多听器,高速传输
  • 多对讲机和多听机,串行数据仪表网络
  • 多对讲机和多听机,以太网互连
  • 多对讲机和多听机,以太网互连,安全保障

问题1:single talker and multiple listeners是什么?
我个人理解就是单发送,多接收。

数据传输格式

在这里插入图片描述
D0-D7是数据位,数据位之前还有一个起始位,最后一位是停止位。
问题1:数据的发送命令是什么?

7.1 Character

General

在这里插入图片描述
所有传输的数据应被解释为ASCII字符。8位字符的最高有效位应始终作为0 (D7 = 0)传输。

Reserved characters

在这里插入图片描述

8.1 Table 1

在这里插入图片描述
翻译如下,虽然知道了名字,但是还是不理解其具体作用

Vaild characters(有效字符)

在这里插入图片描述

有效的字符集由所有可打印的ASCII字符(HEX 20到HEX 7E)组成,除了那些定义为保留字符的字符。有效字符集的列表见8.1(表2)

8.1 Table 2

在这里插入图片描述
在这里插入图片描述

对应的就是通常所说的ASCII码表

Undefined characters(未定义字符)

在这里插入图片描述
未指定为“保留字符”或“有效字符”的ASCII值被排除在外,并且在任何时候都不得传输.
但是有必要传输在Table1中但是不在Table2中的数据时,需要用三位character传输。

举个例子:

  • 若要发送ASCII “127.5°”,则要发送"“127.5 ^F8"。(F8为什么代表°,没搞懂)
  • 若要发送ReservedCharacters< CR >< LF >,则发送"^0D ^0A"。(根据8.1Table1得)
  • 若要发送ReservedCharacters"^“,则发送” ^5E"。(根据8.1Table1得)

Character symbols

在这里插入图片描述
当本标准中使用单个字符来定义计量单位、表示数据字段类型、句子类型等时,应按8.1(表3)中的字符符号进行解释。我的理解是,用一个字母,大小写,来代表不同的含义。

8.1 Table 3

在这里插入图片描述
在这里插入图片描述

7.2 Fields

String

字段由位于两个适当分隔符之间的有效字符字符串或无字符(空字段)组成。

Address field

General

在这里插入图片描述

地址字段是句子中的第一个字段,在“$”或“!”之后。“分隔符。它用来定义句子。他说到,分隔符的详细描述在7.3.3中。
在这里插入图片描述
这些句子被称作Parametric sentences(参数句),这些句子以" $ "为开头,句子结构具有分隔和定义的数据字段,是传递信息的首选方法。
下面是Parametric sentences的具体规则:

  • 句子以“$”分隔符开始
  • 只允许使用经过批准的句子格式化程序。特殊用途封装语句使用的格式化程序不能重用
  • 只允许使用有效字符
  • 只允许批准的字段类型
  • 数据字段(参数)是单独分隔的,其内容由该标准标识并经常详细描述
  • 不允许封装的非分隔数据字段

Approved address field(批准的地址字段)

批准的地址字段由本标准定义的五位数字大写字母字符组成。前两个字符是话务员标识符,列在8.2(表4)中。话务员标识符用于定义正在传输的数据的性质。
具有从多个源传输数据能力的设备应传输适当的对讲机标识符。这里有一个例子,关于GPS和LORAN-C的例子,目前还不是很懂,需要去查阅相关资料。

for example a device with both a GPS receiver and a LORAN-C
receiver shall transmit GP when the position is GPS-based, LC when the position is LORANC-based, and IN for integrated navigation shall be used if lines of position from LORAN-C
and GPS are combined into a position fix

能够从其他来源重新传输数据的设备应使用适当的标识符。
例子

for example GPS receivers transmitting heading data shall not transmit $GPHCD unless the
compass heading is actually derived from the GPS signals

Approved Sentence批准的语句

关于传输指令的解读
句子结构
{开始和发送者的ID}-{字段描述}

TTM

TTM:Tracked target message跟踪目标消息
在这里插入图片描述

关于RATTM的RA暂时不清楚,先按LORAN处理。

$TTM,(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15)h< CR >< LF >

位置代表信息
(1)目标编号(0-999)
(2)目标距离自己的船的距离(NM海里,1海里=1.852公里(千米) )
(3)(4)本船方位(单位,度。T代表绝对位置,R代表相对位置)
(5)目标速度
(6)(7)目标航向(单位,度。T代表绝对位置,R代表相对位置)
(8)到最近会遇点的距离
(9)到最近会遇点的时间(单位min)
(10)速度/距离单位(K/N/S,K =公里/小时;N=节;S =法定英里/小时)
(11)目标名称
(12)目标状态 (见注1)
(13)参考目标=R(见注2)
(14)数据获取时间(UTC格式hhmmss.ss)
(15)获取的类型(A=自动的,M=手动的,R=报告的)

相对位置指的是,正北到船舶航向线的角度。
目标状态:
注1:
L=丢失,跟踪目标已经失去
Q =查询,在获取进程中的目标
T=正在跟踪中
注2:参考目标:如果目标是用于确定本船舶位置或速度的参考设置为“R”,否则为空。
关于绝对位置和相对位置:

  1. 绝对方位,也被称为真方向或绝对方位,是描述一个物体相对于地球表面的位置的方位角。在航海中,真方位是从真北顺时针量到物标的方位角(0-360度)。
  2. 相对方位,是描述一个物体相对于其他物体的方位。在航海中,相对方位是从船首量至物标的方位角(左右0-180度)。

例子:
$RATTM,37,0.3,345.6,T,0.1,121.1,T,0.2,100.0,N,TGT37,Q,T,111521.70,M*1B

描述数值
编号37
目标距离我们多少海里0.3海里
本船的方位345.6度
是相对位置还是绝对位置绝对位置
目标速度0.1节
目标航向121.1度
是相对位置还是绝对位置绝对位置
到最近会遇点的距离0.2海里
到最近会遇点的时间100min
船的速度单位
目标名称TGT37
目标状态Q查询
参考目标为T(见注2)
数据获取时间11时15分21.70
获取类型M手动型

使用c语言进行解码操作
*也叫做取址符
在这里插入图片描述

#include <stdio.h>
#include <string.h>

#define MAX_LENGTH 1000  // 用于存储输入字符串的最大长度
#define MAX_TOKENS 16    // 假设最多有 20 个子字符串

int splitString(const char* str, char* tokens[], const char* delimiter) 
{
    int count = 0;
    char* ptr;

    ptr = strtok(str, delimiter);
    while (ptr != NULL && count < MAX_TOKENS) 
    {
        tokens[count++] = ptr;
        ptr = strtok(NULL, delimiter);
    }

    return count;
}



int main() {

    //对指令中几个判断量进行定义
    char located[20];//本船方位(相对or绝对)
    char towards[20];//目标航向 (相对or绝对)
    char states[20];//目标状态
    char TFA[20];//获取的数据类型
    char* TFA_temp;
    char speedUnit[20];

    char data[MAX_LENGTH];  // 用于存储输入的字符串
    printf("请输入要解析的指令: ");
    fgets(data, MAX_LENGTH, stdin);  // C 库函数 char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止

    // 如果使用fgets读取了换行符,则需要将其替换为字符串结束符
    char* newline = strchr(data, '\n');//在的data中查找换行符

    if (newline != NULL) {
        *newline = '\0';//  '\0'是判定字符数组结束的标识
    }

    char* tokens[MAX_TOKENS];  // 存储子字符串的数组
    int count;  // 子字符串数量

    // 调用分隔字符串的函数
    count = splitString(data, tokens, ",");

    // 打印数组中存储的子字符串
    for (int i = 0; i < count; i++) {
        printf("Token %d: %s\n", i + 1, tokens[i]);
    }

    // 根据 tokens 数组的内容设置 located 和 speed 的值
    //strcmp把 str1 所指向的字符串和 str2 所指向的字符串进行比较
    if (strcmp(tokens[4], "T") == 0)
    {
        strcpy(located, "本船方位:绝对位置");
    }
    else if (strcmp(tokens[4], "R") == 0) {
        strcpy(located, "本船方位:相对位置");
    }

    if (strcmp(tokens[7], "T") == 0)
    {
        strcpy(towards, "目标航向:绝对位置");
    }
    else if (strcmp(tokens[7], "R") == 0) {
        strcpy(towards, "目标航向:相对位置");
    }


    if (strcmp(tokens[12], "T") == 0)
    {
        strcpy(states, "目标状态:正在跟踪中");
    }
    else if (strcmp(tokens[12], "Q") == 0) {
        strcpy(states, "目标状态:查询中");
    }
    else if (strcmp(tokens[12], "L") == 0) {
        strcpy(states, "目标状态:丢失");
    }

    if (strcmp(tokens[10], "K") == 0)
    {
        strcpy(speedUnit, "速度单位:公里/小时");
    }
    else if (strcmp(tokens[10], "N") == 0) {
        strcpy(speedUnit, "速度单位:节");
    }
    else if (strcmp(tokens[10], "S") == 0) {
        strcpy(speedUnit, "速度单位:法定英里/小时");
    }

    TFA_temp = strtok(tokens[15], "*");

    if (strcmp(strtok(TFA_temp,"*"), "A") == 0)
    {
        strcpy(TFA, "获取类型:自动");
    }
    else if (strcmp(strtok(TFA_temp, "*"), "M") == 0) {
        strcpy(TFA, "获取类型:手动");
    }
    else if (strcmp(strtok(TFA_temp, "*"), "R") == 0) {
        strcpy(TFA, "获取类型:报告");
    }

 

   printf("发送格式:%s\n船舶的编号:%s\n目标距离本船的距离:%s海里\n本船方位:%s度\n%s\n目标速度:%s节\n目标航向:%s度\n%s\n距离最近会遇点:%s海里\n到最近会遇点的时间:%smin\n%s\n目标名称:%s\n%s\n数据获取时间:%s\n%s\n",
       tokens[0],tokens[1],tokens[2],tokens[3],located,tokens[5],tokens[6],towards,tokens[8],tokens[9],speedUnit,tokens[11],states,tokens[14],TFA);
    return 0;
}

运行此代码输入$RATTM,37,0.3,345.6,T,0.1,121.1,T,0.2,100.0,N,TGT37,Q,T,111521.70,M*1B可以得到
在这里插入图片描述

程序接收并解析串口数据

在这里插入图片描述
首先启动demo.c程序,在打开串口软件,对COM2进行数据的发送,随后可以接收到结果,并进行解析。
在这里插入图片描述

#include <stdio.h>
#include <string.h>
#include <Windows.h>
#include <stdbool.h>

#define MAX_LENGTH 1000  // 用于存储输入字符串的最大长度
#define MAX_TOKENS 16    // 假设最多有 20 个子字符串

HANDLE hCom;

int splitString(const char* str, char* tokens[], const char* delimiter) 
{
    int count = 0;
    char* ptr;

    ptr = strtok(str, delimiter);
    while (ptr != NULL && count < MAX_TOKENS) 
    {
        tokens[count++] = ptr;
        ptr = strtok(NULL, delimiter);
    }

    return count;
}



int main() {

    //打开串口读部分
    hCom = CreateFile(TEXT("com2"),//在这里选择COM口
        GENERIC_READ, //允许读
        0, //指定共享属性,由于串口不能共享,所以该参数必须为0
        NULL,
        OPEN_EXISTING, //打开而不是创建

        FILE_ATTRIBUTE_NORMAL, //属性描述,该值为FILE_FLAG_OVERLAPPED,表示使用异步I/O,该参数为0,表示同步I/O操作
        NULL);

    if (hCom == INVALID_HANDLE_VALUE)
    {
        printf("打开COM失败!\n");
        return FALSE;
    }
    else
    {
        printf("COM打开成功!\n");
    }

    SetupComm(hCom, 1024, 1024); //输入缓冲区和输出缓冲区的大小都是1024

    /*********************************超时设置**************************************/
    COMMTIMEOUTS TimeOuts;
    //设定读超时
    TimeOuts.ReadIntervalTimeout = MAXDWORD;//读间隔超时
    TimeOuts.ReadTotalTimeoutMultiplier = 0;//读时间系数
    TimeOuts.ReadTotalTimeoutConstant = 0;//读时间常量
    //设定写超时
    TimeOuts.WriteTotalTimeoutMultiplier = 1;//写时间系数
    TimeOuts.WriteTotalTimeoutConstant = 1;//写时间常量
    SetCommTimeouts(hCom, &TimeOuts); //设置超时

    /*****************************************配置串口***************************/
    DCB dcb;
    GetCommState(hCom, &dcb);
    dcb.BaudRate = 115200; //波特率为115200
    dcb.ByteSize = 8; //每个字节有8位
    dcb.Parity = NOPARITY; //无奇偶校验位
    dcb.StopBits = ONESTOPBIT; //一个停止位
    SetCommState(hCom, &dcb);

    DWORD wCount;//实际读取的字节数
    bool bReadStat;

    char str[100] = { 0 };

    //解析串口数据部分
    //对指令中几个判断量进行定义
    char located[20];//本船方位(相对or绝对)
    char towards[20];//目标航向 (相对or绝对)
    char states[20];//目标状态
    char TFA[20];//获取的数据类型
    char* TFA_temp;
    char speedUnit[20];
    char data[MAX_LENGTH];  // 用于存储输入的字符串

    char* tokens[MAX_TOKENS];  // 存储子字符串的数组
    int count;  // 子字符串数量

    while (1)
    {
        //PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR); //清空缓冲区
        bReadStat = ReadFile(hCom, str, sizeof(str), &wCount, NULL);

        if (!bReadStat)
        {
            printf("读串口失败!");
            return FALSE;
        }
        else
        {
            if (wCount <= 34) {
               //printf("没读取到8个字节数据\n!");
                printf("请输入要解析的指令: \n");
            }
            else {


              
               char* newline = strchr(str, '\n');//在的data中查找换行符
                // 如果使用fgets读取了换行符,则需要将其替换为字符串结束符


                if (newline != NULL) {
                    *newline = '\0';//  '\0'是判定字符数组结束的标识
                }
                // 调用分隔字符串的函数
                count = splitString(str, tokens, ",");

                // 打印数组中存储的子字符串
                //for (int i = 0; i < count; i++) {
                //    printf("Token %d: %s\n", i + 1, tokens[i]);
                //}

                // 根据 tokens 数组的内容设置 located 和 speed 的值
                //strcmp把 str1 所指向的字符串和 str2 所指向的字符串进行比较
                if (strcmp(tokens[4], "T") == 0)
                {
                    strcpy(located, "本船方位:绝对位置");
                }
                else if (strcmp(tokens[4], "R") == 0) {
                    strcpy(located, "本船方位:相对位置");
                }

                if (strcmp(tokens[7], "T") == 0)
                {
                    strcpy(towards, "目标航向:绝对位置");
                }
                else if (strcmp(tokens[7], "R") == 0) {
                    strcpy(towards, "目标航向:相对位置");
                }


                if (strcmp(tokens[12], "T") == 0)
                {
                    strcpy(states, "目标状态:正在跟踪中");
                }
                else if (strcmp(tokens[12], "Q") == 0) {
                    strcpy(states, "目标状态:查询中");
                }
                else if (strcmp(tokens[12], "L") == 0) {
                    strcpy(states, "目标状态:丢失");
                }

                if (strcmp(tokens[10], "K") == 0)
                {
                    strcpy(speedUnit, "速度单位:公里/小时");
                }
                else if (strcmp(tokens[10], "N") == 0) {
                    strcpy(speedUnit, "速度单位:节");
                }
                else if (strcmp(tokens[10], "S") == 0) {
                    strcpy(speedUnit, "速度单位:法定英里/小时");
                }

                TFA_temp = strtok(tokens[15], "*");

                if (strcmp(strtok(TFA_temp, "*"), "A") == 0)
                {
                    strcpy(TFA, "获取类型:自动");
                }
                else if (strcmp(strtok(TFA_temp, "*"), "M") == 0) {
                    strcpy(TFA, "获取类型:手动");
                }
                else if (strcmp(strtok(TFA_temp, "*"), "R") == 0) {
                    strcpy(TFA, "获取类型:报告");
                }

                printf("发送格式:%s\n船舶的编号:%s\n目标距离本船的距离:%s海里\n本船方位:%s度\n%s\n目标速度:%s节\n目标航向:%s度\n%s\n距离最近会遇点:%s海里\n到最近会遇点的时间:%smin\n%s\n目标名称:%s\n%s\n数据获取时间:%s\n%s\n",
                    tokens[0], tokens[1], tokens[2], tokens[3], located, tokens[5], tokens[6], towards, tokens[8], tokens[9], speedUnit, tokens[11], states, tokens[14], TFA);
                return 0;
               
            }
        }
        Sleep(100);
    }

    CloseHandle(hCom);

  
}

  • 11
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Sol-itude

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

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

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

打赏作者

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

抵扣说明:

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

余额充值