HART协议详解:HART与MCU通信代码解析举例

HART(Highway Addressable Remote Transducer),可寻址远程传感器高速通道的开放通信协议,Hart协议比较大的特点在于支持模拟信号和数字信号同时传递。

参考:
https://blog.csdn.net/weixin_33775572/article/details/91708920
https://blog.csdn.net/lixiaojie123123/article/details/73302900

先介绍下HART协议的通信原理:
主要分为两个部分:

  1. 数模转换测量数据
  2. 基于频率数据传输

HART协议类似于早期坐机电话协议 早期的电话传输的是声音模拟量,包括了电压、频率,以此来反应不同的声音。而后加入了“来电显示”等数字量,就要采用HART协议类似的方式来传输,即在模拟量的基础上加上数字量。

对于HART协议 其模拟量输出的为4-20mA电流,对其进行数模转换即可得到对应的数据,比如100psi的压力传感器,20mA对应的就是100psi,4mA对应的就是0psi。

对于基于频率的数据传输 HART协议将不同的频率作为数据0和1 通常是使用1200Hz表示1,2200Hz表示0

依次排列下来即可得到数据

将电流量与频率量叠加,即模拟量与数字量同时传输,构成完整的HART协议

HART协议的数字量空闲时为1,即频率恒定1200Hz,而当表示8位数据时,则需要一个起始位0和一个停止位0 中间8位才是数据位

如AD5700芯片:


比如发一个0xAA 则HART总线上 表示的数据如下:
1111 0 1010 1010 0 1111
其中0 1010 1010 0部分为传输部分 1010 1010为数据部分0xAA
1111为空闲时的状态

HART协议的模拟量部分就很好理解了 就是数模转换而已 不用再过多介绍

在使用HART器件时 通常都是用MCU连接一个HART协议的调制解析器 然后再连接到HART器件

HART协议的调制解析器有很多种 比如可以采用AD5700+AD5421构成的HART组合 但都大同小异 都是采用UART的方式进行与MCU的通信(如果用AD5421组合则是SPI)

在HART模块中,通常是通过UART发送一个字节,且需要11位二进制数据,第一位起始位,第二到九位共八位是要发送的数据,第十位是校验位<奇校验>,第十一位是停止位。

整体的HART命令字段由以下组成:
PREAMBLE START ADDR COM BCNT STATUS DATA CHK
对应序文 定界符 地址 命令号 数据长度 响应码 数据字节 奇偶校验(异或校验)
以上便是一个完整的Hart通信数据帧格式,其中Status(通信状态)只有在从机对主机通信时才会加入的。

  1. PREAMBLE 前导字符,作为通信同步的需要,是5到20个字节的0XFF,通常采用5个字节; 也就是5个0xFF

  2. START 起始字节符,将告之使用的结构为“长”还是“短”,消息源是否是“突发”模式消息。主机到从机为短结构时,起始位为 0X02,长帧时为 0X82。从机到主机的短结构值为 0X06,长结构值为0X86。而为“突发”模式的短结构值为 0X01,长结构为 0X81。一般设备进行通讯接收到 2 个0XFF 字节后,就将侦听起始位。

  3. ADDR 地址字符,包含了主机地址和从机地址,短结构中占 1 字节,长结构中占 5 字节。
    主机到从机为短结构时,起始位为02,长帧时为82。
    从机到主机的短结构值为06,长结构值为86
    “突发”模式的短结构值为01,长结构为81
    短指令时:地址码由一个字节表示(如80),其结构为

    一般我们不用到突发模式,这里的80表示的就是(主机1—-设备地址(0))
    长指令时:地址码由5个字节表示,其结构为

    另外,长结构的低 38 位如果都是 0 的话表示的是广播地址,即消息发送给所有的设备。

  4. COM 命令字节,范围为 253 个,用 HEX 的 0~FD 表示。31,127,254,255 为预留值。PS:一开始对此处提到的命令很困惑,就在心里发问,每个命令都什么含义?所有的厂家都支持么?终于,在一篇名为HCF_SPEC 99官方文档中找到

  5. BCNT 数据总长度,它的值表示的是 BCNT 下一个字节到最后(不包括校验字节)的字节数,其实说了这么多,无非是因为从机回传的数据中多了一个状态码,明确也是要算在数据长度的。接收设备用他可以鉴别出校验字节,也可以知道消息的结束。因为规定数据最多为 25 字节,所以它的值是从 0~27。

  6. STATUS 状态字节,也叫做“响应码”,顾名思义,只存在于从机响应主机消息的时候,用 2 字节表示。他将报告通讯中的错误、接收命令的状态(如:设备忙、无法识别命令等)和从机的操作状态。 如果我们在通讯过程中发现了错误,首字节的最高位(第 7 位)将置 1,其余的 7 位将汇报出错误的细节,而第 2 个字节全为 0。否则,当首字节的最高位为 0 时,表示通讯正常,其余的 7 位表示命令响应情况,第 2 个字节表示场设备状态的信息。UART 发现的通讯错误一般有:奇偶校验、溢出和结构错误等。命令响应码可以有 128 个,表示错误和警告,他们可以是单一的意义,也可以有多种意义,我们通过特殊命令进行定义、规定。现场设备状态信息用来表示故障和非正常操作模式。此处依然是一个专门的文档来叙述 HCF_SPEC_307 。

  7. DATA 数据字节,首先需说明的是并非所有的命令和响应都包含数据字节,它最多不超过 25 字节(随着通讯速度的提高,正在要求放宽这一标准)。数据的形式可以是无符号的整数(可以是8,16,24,32 b),浮点数(用 IEEE754 单精浮点格式)或 ASCII 字符串,还有预先制定的单位数据列表。具体的数据个数根据不同的命令而定!此处查阅官方文档 HCF_SPEC_183<数据格式表> 此中数据量相当大 HCF_SPEC 99 HCF_SPEC 127 HCF_SPEC-151;

  8. CHK 奇偶校验,方式是纵向奇偶校验,从起始字节开始到奇偶校验前一个字节为止。

在这些数据中,除了数据长度对应的数据位不同,起始字节符对应的地址字符也不同,在做命令解析的时候 要根据起始字节和数据大小来判断数据位的位置

例子:
FF FF FF FF FF 82 A6 06 BC 61 4E 01 00 B0
上面是主机到从机发送的一条消息。前 5 个字节值都为 FF,显然他是前导字节。接着的 82 起始字节,表示主机到从机发出的长结构的消息。
后 5 个字节 “A6,06,BC,61,4E”是地址字节化为二进制表示如下:
A6 06 BC 61 4E
1010 0110 0000 0110 1011 1100 0110 0001 0100 1110
可见首字节 A6 的最高位为 1 表示主机,次高位为 0 表示非突发模式,后面的 38 位二进制数表示设备的惟一标号:“100110”是生产厂家代码,值为 38,是 Rosemount 公司的代码;后一字节 06 是设备型号代码,06 代表的型号是3051C;后面的 3 个字节是设备识别号,本例中的值为 12345678;再接下来的 01 是命令字节,表示 1 号命令,该命令的返回内容可在文档资料中找到 HCF_SPEC 127,即读取 PV 值,后面的 00 是表示数据的长度;本例中无数据,值为 0;最后是校验字节 B0;

FF FF FF FF FF 86 A6 06 BC 61 4E 01 07 00 00 06 40 B0 00 00 45
上面表示的是从机到主机的一条消息。本例大部分与上例相似,不同的是数据字节不再为 0,其中的 06 表示单位 PSI;后面的 4 个字节是用浮点数表示的值 为 5.5。并且由于本例是由从机到主机的应答消息,所以存在着状态位,即本例中的“00 00”,表示“OK”。

将数据依次排列:

第一列为前导字符
00 60为状态码
41 3F A0 00到41 95 00 00为数据位 数据长度1A

上面是突发模式发出的一条消息。第 1 个字节 81 表示突发的长结构模式,与前例中相似的地方不再介绍。注意到状态字节“00 60”后的字节“41 3F A0 00”,他表示的是当前的电流值,是IEEE754格式的浮点数,计算后是 11.9766;后面的 27 表示单位 mA,像后面的 39 表示“%”一样。数据字节中的"42 47 60 00",“BF 06 60 00”,“41 95 00 00”分别表示"SV”,“TV”,"FV"表示方法与 PV 相同。经过解释后的消息可以表示为:“LBTXS/RdAllPv/026/0060/11.9766/mA/11.9766/%/49.8438/psi/-0.524902/%/18.625”。 所有的数据格式在文档资料Common Tables HCF_SPEC 183中。附命令3——属于通用命令,可在HCF_SPEC_127中查找


以下代码为串口信号解析:

#include<stdio.h>
#include<stdint.h>
#include <string.h>typedef struct
{uint8_t PREAMBLE[5];uint8_t START;uint8_t ADDR[5];uint8_t COM;uint8_t BCNT;uint8_t STATUS[2];uint8_t DATA[25];uint8_t CHK;
}HART_Struct;HART_Struct trans_HART_to_Struct(uint8_t * buf)
{HART_Struct HART_Stu;uint8_t i=0;uint8_t START_Num=0;uint8_t COM_Num=0;uint8_t CHK_Num=0;uint8_t Check_Sum=0;  if(buf[0]==0xFF){                for(i=0;i<6;i++){            if(buf[i]!=0xFF){HART_Stu.START=buf[i];START_Num=i;                break;}START_Num=i;}if(START_Num<2){return HART_Stu;}for(i=0;i<START_Num;i++){HART_Stu.PREAMBLE[i]=buf[i];}if(HART_Stu.START<0x10){COM_Num=START_Num+2;            }else{COM_Num=START_Num+6;            }for(i=0;i<COM_Num-START_Num-1;i++){HART_Stu.ADDR[i]=buf[START_Num+1+i];}HART_Stu.COM=buf[COM_Num];HART_Stu.BCNT=buf[COM_Num+1];CHK_Num=COM_Num+HART_Stu.BCNT+2;HART_Stu.CHK=buf[CHK_Num];for(i=START_Num;i<CHK_Num;i++){Check_Sum=Check_Sum^buf[i];}if(HART_Stu.CHK==Check_Sum){if(HART_Stu.BCNT>0){if(HART_Stu.BCNT>1 && (HART_Stu.START&0x0F)==0x06){                  for(i=0;i<2;i++){HART_Stu.STATUS[i]=buf[COM_Num+2+i];}for(i=0;i<HART_Stu.BCNT-2;i++){HART_Stu.DATA[i]=buf[COM_Num+4+i];}}else{for(i=0;i<HART_Stu.BCNT;i++){HART_Stu.DATA[i]=buf[COM_Num+2+i];}}}else{return HART_Stu;}}else{return HART_Stu;}}else{return HART_Stu;}return HART_Stu;
}int8_t trans_HART_to_Buf(HART_Struct HART_Stu,uint8_t * buf)
{uint8_t i=0;uint8_t START_Num=0;uint8_t COM_Num=0;uint8_t CHK_Num=0;uint8_t Check_Sum=0;if(HART_Stu.PREAMBLE[0]==0xFF){for(i=0;i<6;i++){            if(HART_Stu.PREAMBLE[i]!=0xFF){buf[i]=HART_Stu.START;START_Num=i;                break;}            START_Num=i;}if(START_Num<2){return -1;}for(i=0;i<START_Num;i++){buf[i]=HART_Stu.PREAMBLE[i];}        if(HART_Stu.START<0x10){COM_Num=START_Num+2;}else{COM_Num=START_Num+6;}CHK_Num=COM_Num+HART_Stu.BCNT+2;buf[START_Num]=HART_Stu.START;for(i=0;i<COM_Num-START_Num-1;i++){buf[START_Num+1+i]=HART_Stu.ADDR[i];}buf[COM_Num]=HART_Stu.COM;buf[COM_Num+1]=HART_Stu.BCNT;buf[CHK_Num]=HART_Stu.CHK;if(HART_Stu.BCNT>1 && (HART_Stu.START&0x0F)==0x06){for(i=0;i<2;i++){buf[COM_Num+2+i]=HART_Stu.STATUS[i];}for(i=0;i<HART_Stu.BCNT-2;i++){buf[COM_Num+4+i]=HART_Stu.DATA[i];}}else{for(i=0;i<HART_Stu.BCNT;i++){            buf[COM_Num+2+i]=HART_Stu.DATA[i];}}for(i=START_Num;i<CHK_Num;i++){Check_Sum=Check_Sum^buf[i];}if(HART_Stu.CHK==Check_Sum){return 1;}else{return -2;}}else{return -1;}return 0;
}int main(void)
{unsigned char list[41]={0xFF,0xFF,0xFF,0xFF,0xFF,0x86,0xA6,0x06,0xBC,0x61,0x4E,0x01,0x07,0x00,0x00,0x06,0x40,0xB0,0x00,0x00,0x45};HART_Struct a;uint8_t buf[41];    memset(buf,0,sizeof(buf)/sizeof(buf[0]));a=trans_HART_to_Struct(list);printf("%02X\n",a.CHK);printf("%d\n",trans_HART_to_Buf(a,buf));printf("%02X\n",buf[8]);for(uint8_t i=0;i<41;i++){if(buf[i]==list[i]){}else{printf("ERROR\n");break;}}
}

代码经检验后顺利通过不报错

HART协议详解:HART与MCU通信代码解析举例相关推荐

  1. SOME/IP协议详解「2.0·服务化通信概述」

    SOME/IP协议详解「2.0·服务化通信概述」 点击返回雪云飞星的SOME/IP协议详解「总目录」 SOME/IP协议详解「2.0·服务化通信概述」 1 SOME/IP服务的组成 2 Method| ...

  2. Modbus 协议详解

    Modbus 协议详解 通信协议是指双方实体完成通信或服务所必须遵循的规则和约定,例如我们为实现人与人之间的交流需要约定统一的语言,统一的文字,规定语速等等. 而对于设备之间,协议定义了数据单元使用的 ...

  3. STM32常用协议之SPI协议详解

    SPI协议详解 SPI协议简介 一.SPI物理层 二.SPI协议层 2.1 SPI基本通信过程 2.2 通信的起始和终止信号 2.3 数据有效性 2.4 CPOL/CPHA及通信模式 三.编程实现 四 ...

  4. STM32常用协议之IIC协议详解

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 IIC协议详解 前言 一.IIC协议简介 1.1 简介 1.2 IIC物理层 1.3 协议层 1.3.1 IIC基本读写过程 1.3. ...

  5. HTTP协议详解(真的很经典)

    转自:http://blog.csdn.net/gueter/archive/2007/03/08/1524447.aspx Author :Jeffrey 引言 HTTP是一个属于应用层的面向对象的 ...

  6. Http 协议详解笔记

    HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1.0的第 ...

  7. Http协议 详解(转载)

    http://blog.csdn.net/gueter/archive/2007/03/08/1524447.aspx 引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分 ...

  8. ARP协议详解之ARP动态与静态条目的生命周期

    ARP协议详解之ARP动态与静态条目的生命周期 ARP动态条目的生命周期 动态条目随时间推移自动添加和删除. q  每个动态ARP缓存条目默认的生命周期是两分钟.当超过两分钟,该条目会被删掉.所以,生 ...

  9. HTTP协议详解 转自小坦克

    HTTP协议详解 转自小坦克 -- 有些文章是引用别人的,为了方便我以后或不再备注;引用目的是因为直接网摘里面的地址经常被重置,找不到原来的文章 当今web程序的开发技术真是百家争鸣,ASP.NET, ...

  10. nbns协议_网络协议详解1 - NBNS

    NetBIOS 简介 NetBIOS,Network Basic Input/Output System的缩写,一般指用于局域网通信的一套API,相关RFC文档包括 RFC 1001, RFC 100 ...

最新文章

  1. 关于Javascript的内存泄漏问题的整理稿
  2. react遇到的各种坑
  3. DZ各个数据表详解(DZ论坛各表详细说明,二次开发用)
  4. linux wine运行效率,Wine 3.0让Windows应用在Linux上流畅运行!
  5. 版本名称GA的含义:SNAPSHOT-alpha-beta-release-GA
  6. ASP.NET Core MVC 源码学习:Routing 路由
  7. python与golang_Golang与python线程详解及简单实例
  8. java并发编程(3)--线程 有序性 volatile
  9. 电工结业试卷_维修电工技师二级难吗考试内容怎么样
  10. hibernate、ibatis、freyja的价值
  11. riscv ELF bss段解析
  12. S7-1200/1500获取本地IP地址(不使用库)
  13. 验证手机号或座机号的合法性
  14. 爬点今日头条街拍美女。。。
  15. win计算机名长度限制,Win7,Server 2012文件名过长无法删除解决方案
  16. python在abaqus中的应用光盘文件下载_Python语言在Abaqus中的应用DVD光盘
  17. 【Linux】Linux关闭防火墙、关机重启和查看系统运行级别
  18. ReviewBoard 的安装和使用(二)—— 邮箱的配置
  19. 离散数学:数学语言与证明方法(练习题)
  20. 互联网公司级别的简单划分(小白总结)

热门文章

  1. 记使用springboot过程中遇到的一个问题
  2. 像仓管一样管理redux-仓管也需要才艺(中间件)
  3. 网红王思聪数字屏保下载
  4. 大一linux考试试题及答案,大一计算机期末考试试题及答案
  5. backgroundworker与Thread区别
  6. 盛大 传奇 的网游启示录
  7. 视频教程-WPS Office轻松办公(文字篇)-Office/WPS
  8. Padavan 老毛子路由器登录SSH教程
  9. [安全攻防进阶篇] 十.熊猫烧香病毒机理IDA和OD逆向分析--病毒释放过程(中)
  10. CWMP协议(TR069协议)学习