目录

  • 前言
  • 一、关键词
  • 二、什么是HART
  • 三、HART协议
    • 一、什么是HART协议
    • 二、物理层
    • 三、数据链路层
      • 1.概述
      • 2. 数据帧格式
        • ①.Preamble 前导码
        • ②.Delimiter 定界符
        • ③.Address 地址
          • 1. 短帧地址结构
          • 2. 长帧地址结构
        • ④.Command 命令
        • ⑤.Bytes Count 数据字节数
        • ⑥.Data 数据
        • ⑦.Check Byte 校验字节
  • 四、HART硬件方案
  • 五、OPEN_HART
    • 一.帧结构体定义
    • 二.状态机
      • 1.接收状态机
      • 2.发送状态机
      • 3.从机/突发模式状态机
      • 4.主机状态机
    • 三.命令
  • 六、HART资料及工具

前言

提示:老板让调HART然后就调了


提示:读红字

一、关键词

示例:HART 调制 解调 4-20mA hart协议 仪表通讯

二、什么是HART

HART(Highway Addressable Remote Transducer),可寻址远程传感器高速通道的开放通信协议,是美国ROSEMOUNT公司于1985年推出的一种用于现场智能仪表和控制室设备之间的通信协议。经过30多年的发展,HART技术在国外已经十分成熟,并已成为全球智能仪表的工业标准。 –百度

HART协议使用基于Bell 202标准的1200波特率频移键控(FSK)将数字信息叠加到传统的4到20mA模拟信号上。HART协议由一个独立的组织HART通信基金会维护,它是一个工业标准,用于定义智能现场设备与控制系统之间的通信协议。

HART协议采用基于Bell202标准的FSK频移键控信号,在低频的4-20mA模拟信号上叠加幅度为0.5mA的音频数字信号进行双向数字通讯(半双工),数据传输率为1.2kbps。由于FSK信号的平均值为0,不影响传送给控制系统模拟信号的大小,保证了与现有模拟系统的兼容性。在HART协议通信中主要的变量和控制信息由4~20mA传送,在需要的情况下,另外的测量、过程参数、设备组态、校准、诊断信息通过HART协议访问。

HART通信采用的是半双工的通信方式,其特点是在现有模拟信号传输线上实现数字信号通信,属于模拟系统向数字系统转变过程中过渡性产品,因而在当前的过渡时期具有较强的市场竞争能力,得到了较快发展。HART规定了一系列命令,按命令方式工作。它有三类命令,第一类称为通用命令,这是所有设备都能理解和执行的命令;第二类称为一般行为命令,所提供的功能可以在许多现场设备(尽管不是全部)中实现,这类命令包括最常用的的现场设备的功能库;第三类称为特殊设备命令,以便于工作在某些设备中实现特殊功能,这类命令既可以在基金会中开放使用,又可以为开发此命令的公司所独有。在一个现场设备中通常可发现同时存在这三类命令。

三、HART协议

一、什么是HART协议

HART协议参照了国际标准化组织的开放性互连模型,使用 OSI 标准的物理层、数据链路层、应用层。HART协议规定了传输的物理形式、消息结构、数据格式和一系列操作命令,是一种主从协议。当通讯模式为“问答式”的时候,一个现场设备只做出被要求的应答。HART 协议允许系统中存在 2 个主机(比如说,一个用于系统控制,另一个用于 HART 通信的手操仪),如果不需要模拟信号,多点系统中的一对电缆线上最多可以连接 15 个从设备。

二、物理层


1200波特率频移键控(FSK)将数字信息叠加到传统的4-20mA模拟信号上,以1200 Hz 代表逻辑“1”,2200 Hz 代表逻辑“0”,在4~20 mA 电流上叠加幅度为0. 5mA的正弦调制波。

三、数据链路层

1.概述

  1. 数据链路层规定 HART 协议帧的格式,可寻址范围 0~15,“0”时,处于 4~20mA 及数字信号点对点模式,现场仪表与两个数字通信主设备(也称作通信设备或主设备)之间采用特定的串行通信,主设备包括 PC 机或控制室系统和手持通信器。单站操作中,主变量(过程变量)可以以模拟形式输出,也可以以数字通信方式读出,以数字方式读出时,轮询地址始终为 0。也就是说,单站模式时数字信号和 4~20mA 模拟信号同时有效。
  2. “1~15”处于全数字通信状态,工作在点对多点模式,通信模式有“问答”式、“突发”式(点对点、自动连续地发送信息)。按问答方式工作时的数据更新速率为 2~3 次/s,按突发方式工作时的数据更新速率为 3~4 次/s。在本质安全要求下,只使用一个电源,至多能连接 15 台现场仪表,每个现场设备可有 256 个变量,每个信息最大可包含 4 个变量。这就是所谓的多点(多站)操作模式。这种工作方式尤其适用于远程监控,如管道系统和油罐储存场地。
  3. 采用多点模式,4~20mA 的模拟输出信号不再有效(输出设在 4mA 使功耗最小,主要是为变送器供电,各个现场装置并联连接 ),系统以数字通信方式依次读取并联到一对传输线上的多台现场仪表的测量值(或其它数据)。如果以这种方式构成控制系统,可以显著地降低现场布线的费用和减少主设备输入接口电路,这对于控制系统有重要价值。HART 协议根据冗余检错码信息,采用自动重复请求发送机制,消除由于线路噪声或其他干扰引起的数据误码,实现数据无差错传送。能利用总线供电,可满足本质安全防爆要求。

2. 数据帧格式

HART 协议的帧格式以 8 位为一个字节进行编码,对每个字节加上一个起始位、一个奇偶校验位和一个停止位以串行方式进行传输。通常采用 UART(通用异步接收/发送器)来完成字节的传输。由于数据的有无和长短不恒定,所以 HART 数据的长度不能超过 25 个字节。串口配置波特率为1200bps;每个字符由11位组成:1位起始位,8位数据位,1位校验位(奇校验),1位停止位

Preamble Delimiter Address Expansion bytes Command Bytes Count Data Check Byte
前导码 定界符 地址 扩展字节 命令 数据个数 数据 校验
5-20个字节
(固定FF)
1个字节 短帧1字节
长帧5字节
0-3个字节 1个字节 1个字节 n个字节 1个字节

①.Preamble 前导码

导言字节,一般是 5~20 个 FF 十六进制字节。他实际上是同步信号,各通讯设备可以据此略做调整,保证信息的同步。在开始通讯的时候,使用的是 20 个 FF 导言,从机应答 0信号时将告之主机他“希望”接收几个字节的导言,另外主机也可以用 59 号命令告诉从机应答时应用几位导言。

②.Delimiter 定界符

起始字节,他将告之使用的结构为“长”还是“短”、消息源、是否是“突发”模式消息。主机到从机为短结构时,起始位为 02,长帧时为 82。从机到主机的短结构值为 06,长结构值为86。而为“突发”模式的短结构值为 01,长结构为 81。一般设备进行通讯接收到 2 个 FF 字节后,就将侦听起始位。

Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
地址类型 扩展字节数 物理层类型 帧类型(传输方向)
0:短帧1个字节
1:长帧5个字节
00 00:异步(FSK)
01:同步(ACK)
001:突发模式
010:主机向从机请求数据(STX)
110:从机向主机回复数据(ACK)
0x02 主机到从机的短帧
0x82 主机到从机的长帧
0x06 从机到主机的短帧
0x86 从机到主机的长帧
0x01 突发模式短帧
0x81 突发模式长帧

③.Address 地址

短帧结构包含了主机地址和从机地址,短结构中占 1 字节,长结构中占 5 字节。无论长结构还是短结构,因为 HART 协议中允许 2 个主机存在,所以我们用首字节的最高位来进行区分,值为 1 表示第一主机地址,第二主机用 0 表示。“突发”模式是特例,0,1 值将交替出现,也就是说,在该模式下,赋予 2 个主机的机会均等。次高位为 1 表示为“突发”模式,短结构用首字节的 0~4 位表示值为 0~15 的从机地址,第 5,6 位赋 0;而长结构用后 6 位表示从机的生产厂商的代码,第 2 个字节表示从机设备型号代码,后 3~5 个字节表示从机的设备序列号,构成“唯一”标志码。另外,长结构的低 38 位如果都是 0 的话表示的是广播地址,即消息发送给所有的设备。

1. 短帧地址结构
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
地址类型 模式 00 00 短帧地址
0:第一主机
1:第二主机
0:正常模式
1:从机在突发模式
保留 轮询从机地址

• Bit4和Bit5保留必须为00
• 最低有效4位指定轮询地址0-15

2. 长帧地址结构
Byte0 Byte1 Byte2 Byte3 Byte4
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 从机设备型号 从机设备序列号
0:第一主机
1:第二主机
0:正常模式
1:从机在突发模式
从机生产厂商代码

• 制造商ID的最低有效6位。有效的制造商ID可以是公司(制造商)识别码。
• 1字节设备类型代码。该代码由制造商因为只有制造商ID的较低6位用于地址,设备类型代码应按表1所示分配。进一步的有关分配设备类型代码的规范可以在命令中找到摘要规范:第6.1节兼容性规则
• 一个3字节的设备标识符。这与序列号相似,因为每个设备使用相同设备类型代码制造的设备必须具有不同的设备标识符。

④.Command 命令

功能码,指明一个数据帧的具体实现功能,命令有通用命令、普通应用命令、设备专用命令三大类。

⑤.Bytes Count 数据字节数

指实际的数据 Data 的数据。他的值表示的是 BCNT 下一个字节到最后(不包括校验字节)的字节数。接收设备用他可以鉴别出校验字节,也可以知道消息的结束。因为规定数据最多为 25 字节,所以他的值是从 0~27。

⑥.Data 数据

设置或读取指定从机的参数数据(通信的最终结果)。

⑦.Check Byte 校验字节

从定界符到数据的所有字节的“异或”值,即纵向校验。

协议解析的例子百度很多,后面上传的资料中也有很多。

四、HART硬件方案


硬件方案使用了SDIC(晶华微)SD2057方案.
SD2057datasheet
手册上很详细强烈建议精读
HART_OUT:hart芯片根据RXD的数据调制出的模拟信号,叠加在4-20mA环路中。
HART_IN:接收带有调制信号的环路模拟信号后在hart芯片中解调通过TXD输出。

H_OUT内部有0.75v直流偏置,调制信号幅值±250mv,最终出来的信号就是0.75±0.25=0.5-1v正弦波

HART_OUT芯片脚的波形如上图所示,但是要叠加在控制环路电流的芯片控制脚或者运放脚时,需要将直流分量滤掉,所以需要低通加高通滤波,最终H_OUT波形如下图:

H_IN发送与回复幅值(前面发送后面应答):硬件电路如果没错的话,一般调制出来的波形应该正常,反正我是硬件一次OK,但是软件卡了两个星期(后面发现是个小问题,但容易忽略)。

电流环方案一大堆,可以用集成芯片也可以用运放三极管去做,hart硬件没有任何难度,别人都做好了方案。重点介绍下软件协议。

五、OPEN_HART

hart protocol implement

一.帧结构体定义

按照数据链路层协议格式构造数据结构:

typedef struct
{unsigned char preamble_num;unsigned char delimiter;unsigned char address_size;unsigned char cmd;unsigned char byte_count;unsigned char data_buf[50];unsigned char check_byte;
}frame_type;typedef struct
{unsigned char manufacturer_id;unsigned char device_type;unsigned char unique_device_id[3];
}long_addr_type;long_addr_type long_addr = {MANUFACTURER_ID,DEVICE_TYPE,UNIQUE_DEVICE_ID0,UNIQUE_DEVICE_ID1,UNIQUE_DEVICE_ID2,
};

二.状态机

两个原始状态机,一个接收机和一个传输机。它们在数据传输和接收时进行状态转换,由“xmt_msg”表示和“rcv_msg”两个中断函数去动作。通常这些状态的切换是通过中断去实现的。

void USART3_IRQHandler(void)
{if(USART_GetITStatus(USART3,USART_IT_RXNE)){hart_rcv_msg();}else if(USART_GetITStatus(USART3,USART_IT_TXE)){hart_xmt_msg();}
}

1.接收状态机


定义接收状态:

/* receive state machine */
typedef enum
{RCV_WAIT_IDLE,RCV_WAIT_START,RCV_READ,RCV_DONE,
}rsm_state;

没有通信时状态机处于空闲状态,当收到前导码FF后进入开始接收状态,此时判断前导字节个数,每个字节间隔时间GAP,用定时器去标记(Set GAP)
定义定时器,去定时器中断里累加判断,置标志位

#define TMR_CNT     3  typedef struct soft_timer
{unsigned int cnt;unsigned char flg;
}soft_timer;

因为源码比较多且复杂,挑点重要的讲讲思路,大家有时间自己琢磨下

#define GAP_TIMER   0    //帧空隙
#define SLAVE_TIMER 1    //从机响应最大时间  28个 CHaracter times 256.7ms
#define BT_TIMER    2    // 突发模式响应时间

此处顺带提一下从机响应最大时间 ,刚开始移植的时候忽略这个时间导致通讯失败
若超时接收状态为错误

/* STX : a master to slave message */
/* ACK : a slave to master message */
/* BACK : a slave message transmited to a master without an STX*/
/* the type of message received */
typedef enum
{RCV_ERR  = 0xff,RCV_COMM_ERR = 0xee,RCV_STX  = 0x02, //根据数据帧结构定界符RCV_ACK  = 0x06, RCV_BACK = 0x01,
}rcv_msg_type;

接收中断服务函数:顺着协议,顺着状态转换图

void hart_rcv_msg(void)
{static unsigned char PreambleNum = 0;static unsigned int ByteCount;unsigned char Byte;serical_get_byte(&Byte);switch(g_RcvState){case RCV_WAIT_IDLE:if(Byte == PREAMBLE){PreambleNum = 1;g_RcvState = RCV_WAIT_START;set_delay_time(GAP_TIMER,HRT_GAPT);}break;case RCV_WAIT_START:if(is_timeout_id(GAP_TIMER)){g_RcvMsgType = RCV_ERR;}else{if(Byte == PREAMBLE){PreambleNum++;}else{switch(Byte){case (SHORT_FRAME|RCV_STX):if(PreambleNum > 1){g_Rx.address_size = SHORT_ADDR_SIZE;g_RcvMsgType = RCV_STX;s_RcvBufferPos = 0;g_Rx.data_buf[s_RcvBufferPos++] = Byte;g_RcvState = RCV_READ;}     else{g_RcvMsgType = RCV_ERR;}break;case (SHORT_FRAME|RCV_ACK):if(PreambleNum > 1){g_Rx.address_size = SHORT_ADDR_SIZE;g_RcvMsgType = RCV_ACK;s_RcvBufferPos = 0;g_Rx.data_buf[s_RcvBufferPos++] = Byte;g_RcvState = RCV_READ;}else{g_RcvMsgType = RCV_ERR;}break;case (SHORT_FRAME|RCV_BACK):if(PreambleNum > 1){g_Rx.address_size = SHORT_ADDR_SIZE;g_RcvMsgType = RCV_BACK;s_RcvBufferPos = 0;g_Rx.data_buf[s_RcvBufferPos++] = Byte;g_RcvState = RCV_READ;}else{g_RcvMsgType = RCV_ERR;}break;case (LONG_FRAME|RCV_STX):if(PreambleNum > 1){g_Rx.address_size = LONG_ADDR_SIZE;g_RcvMsgType = RCV_STX;s_RcvBufferPos = 0;g_Rx.data_buf[s_RcvBufferPos++] = Byte;g_RcvState = RCV_READ;}else{g_RcvMsgType = RCV_ERR;}break;case (LONG_FRAME|RCV_ACK):if(PreambleNum > 1){g_Rx.address_size = LONG_ADDR_SIZE;g_RcvMsgType = RCV_ACK;s_RcvBufferPos = 0;g_Rx.data_buf[s_RcvBufferPos++] = Byte;g_RcvState = RCV_READ;}else{g_RcvMsgType = RCV_ERR;}break;case (LONG_FRAME|RCV_BACK):if(PreambleNum > 1){g_Rx.address_size = LONG_ADDR_SIZE;g_RcvMsgType = RCV_BACK;s_RcvBufferPos = 0;g_Rx.data_buf[s_RcvBufferPos++] = Byte;g_RcvState = RCV_READ;}else{g_RcvMsgType = RCV_ERR;}break;default:g_RcvMsgType = RCV_ERR;g_RcvState = RCV_DONE;break;}}} set_delay_time(GAP_TIMER,HRT_GAPT);break;case RCV_READ:if(is_timeout_id(GAP_TIMER)){g_RcvMsgType = RCV_ERR;}else{g_Rx.data_buf[s_RcvBufferPos++] = Byte;if(g_Rx.address_size == SHORT_ADDR_SIZE){ if(s_RcvBufferPos == HRT_SHORTF_LEN_OFF+1){ByteCount = Byte;}if(s_RcvBufferPos > HRT_SHORTF_LEN_OFF+ByteCount+1){g_RcvState = RCV_DONE;}}else{if(s_RcvBufferPos == HRT_LONGF_LEN_OFF+1){ByteCount = Byte;}if(s_RcvBufferPos > HRT_LONGF_LEN_OFF+ByteCount+1){g_RcvState = RCV_DONE;}}   }set_delay_time(GAP_TIMER,HRT_GAPT);if(g_RcvState == RCV_DONE){is_timeout_id(GAP_TIMER);g_HartState = HRT_WAIT;g_RcvState = RCV_WAIT_IDLE;PreambleNum = 0;ByteCount = 0;set_rcv_frame_count();serical_enable(FALSE,FALSE);}break;default:break;}
}

想了一下,这样大篇幅的粘贴代码没什么用,还是自己去打读源码打断点调试,思路要自己去体会。

2.发送状态机

3.从机/突发模式状态机

4.主机状态机

重点就是几张状态转换图。给大家个源码链接GITHUB上搜HART。
OpenHart开源是真的好。作者是断断续续调了两周左右,其实是卡在一个小问题,顺利的话应该三四天就可以通上。

三.命令

定义函数指针

void (*command)(unsigned char *data);

成帧的时候选择调用相应函数

g_Tx.byte_count = cmd_function(cmd,data);
g_Tx.data_buf[HRT_LONGF_LEN_OFF] = g_Tx.byte_count;

写不同命令入口函数,以comm0为例子

case 0: command = C0_RdUniqueId;        break;

0命令是响应设备信息

在这里插入代码片

/* the same as C11 */
void C0_RdUniqueId(unsigned char *data)
{set_respose_code(data);if(!HrtResposeCode){set_ID(data);}
}
HART命令0:读标识码
返回扩展的设备类型代码,版本和设备标识码。
请求:无
响应:
字节0:        254
字节1:        制造商ID(Enum)
字节2:        设备类型(Enum)
字节3:        请求的最小前导符数(主->从)
字节4:        通用命令文档版本号
字节5:        设备规范版本号
字节6:        设备软件版本号
字节7:        (前五个bit)设备硬件版本号(后三个bit)物理信号类型(Enum)
字节8:        设备标志
字节9-11:    设备ID号void set_ID(unsigned char *data)
{data[HrtByteCnt++] = 254;data[HrtByteCnt++] = MANUFACTURER_ID;data[HrtByteCnt++] = DEVICE_TYPE;data[HrtByteCnt++] = get_response_preamble_num();data[HrtByteCnt++] = 5; //hart revisiondata[HrtByteCnt++] = 5; //device revision leveldata[HrtByteCnt++] = 2;  //software revisiondata[HrtByteCnt++] = 0x20;data[HrtByteCnt++] = 0; //flag assignmentdata[HrtByteCnt++] = UNIQUE_DEVICE_ID0;data[HrtByteCnt++] = UNIQUE_DEVICE_ID1;data[HrtByteCnt++] = UNIQUE_DEVICE_ID2;//the 12th data byte?
}

类似这样的命令函数有很多。
就先这样吧,太晚了,希望帮助到新人朋友,大家一起少走弯路。最后我把用到的文档,开发工具全部打包上传!大家点点关注涨个粉哈哈哈哈

六、HART资料及工具

参考文章

HART通信协议
讲一讲hart协议
OpenHart源代码下载
工具明天整理好了传,GitHub上的源码有一部分缺失,但是我相信大家可以找出来自己补完整,不仅可以熟悉程序,而且可以提升写代码质量。加油!

HART协议学习记录相关推荐

  1. OAuth2 and OpenId 协议学习记录一

    用identityserver4搭建了一个环境,通过浏览器分析了下整个协议流程 locahost:5003(资源), identityserver4使用的localhost:5001 (授权服务) 以 ...

  2. Zigbee协议学习记录

    ZigBee是基于IEEE 802.15.4标准的低功耗局域网协议,是一种短距离.低功耗的天线通信技术. 特点是:近距离.低复杂度.低数据传输速率. 本文内容共分为六个模块: 1,ZigBee无线通信 ...

  3. TCP/IP协议学习记录之九:Traceroute程序

    Traceroute程序可以让我们看到IP数据报从一台主机传到另一台主机所经过的路由,还可以使用IP源路由选项: Traceroute程序的操作 为什么不使用IP记录路由选项而另外开发这个程序: 1) ...

  4. TCP协议学习记录 (三) Ping程序 RR选项 记录路由hop

    一开始想直接在上个程序改,自己构造IP包头,但后来发现不行,微软不让干了,所以后来选用libcap库来收发包 代码写的很乱.. 1 #pragma pack(4) 2 3 #define ECHO_R ...

  5. DTLS协议学习记录

    DTLS基于UDP协议 1.DTLS握手协议 2.DTLS时序图: 2.1.实际上在握手之前还需要做很多事情,其中之一就是交换SDP信息,也就是媒体协商(需要通过信令进行连接),其中也包含交换了ICE ...

  6. TCP/IP协议学习记录之一:ppp适配器和以太网适配器

    首先看几个图片 1.当我的电脑有宽带连接的时候,在cmd窗口ipcofig会出现: 会显示两个IP地址,一个是PPP适配器的宽带连接,一个是以太网适配器的本地连接,然后我们分别来ping这两个IP地址 ...

  7. AMBA总线协议之AHB学习记录(1)—ahb_bus(附verilog代码)

    目录 0.前言 1.AHB简介 2.ahb_bus实现(verilog) 3.总结反思 & 后面学习计划 0.前言 前段时间粗略过了一下riscv指令集相关内容,并对开源项目tinyriscv ...

  8. 视频播放压缩的相关知识点:I帧、P帧、B帧、RTMP协议、RTSP协议、GB28181协议等学习记录

    I帧.P帧.B帧.RTMP协议.RTSP协议.GB28181协议等学习记录 引言 1. I帧.P帧.B帧 1.1 P帧 1.2 B帧 1.3 I帧 2.ONVIF协议与GB28181协议,RTMP与R ...

  9. 生成树协议 STP RSTP PVST PVST+ 学习记录

    生成树协议 STP& RSTP& PVST& PVST+ 学习记录 记录大学时的生成树协议学习经过,当时参考了一些网络资料,出处已难寻,如有误,请不吝赐教 背景 STP的工作过 ...

  10. Android开发技术周报176学习记录

    Android开发技术周报176学习记录 教程 当 OkHttp 遇上 Http 2.0 http://fucknmb.com/2018/04/16/%E5%BD%93OkHttp%E9%81%87% ...

最新文章

  1. oracle专用服务器模式与共享服务器模式
  2. ConneR and the A.R.C. Markland-N CodeForces - 1293A(暴力)
  3. 做论坛签名外链 我们需要注意什么?
  4. 把Arraylist转换成GameObject[]
  5. 产品经理处理问题“五步法”模板
  6. java 多态 重载的区别_重写、覆盖、重载、多态几个概念的区别分析
  7. 6.大数据架构详解:从数据获取到深度学习 --- 交互式分析
  8. Android截图命令screencap
  9. 电气EPLAN电气图纸设计
  10. 制造业执行系统MES 在汽车零配件行业展露锋芒
  11. switch相关系列
  12. C# 网络编程之网页简单下载实现
  13. sublime 正则跨行匹配
  14. 淘宝的互动项目,为什么总会刷爆你的好友圈?
  15. html5 promise,从HTML5与PromiseA+规范来看事件循环
  16. 念白白 php,戏曲课堂︱【第五二讲】戏曲的念白(散白与诗白)
  17. 全国计算机公共基础知识点
  18. Lake Shore亥姆霍兹线圈
  19. qq电脑管家文件粉碎工具
  20. 热电偶校验仪_热电偶校验方法_热电偶冷端补偿方法

热门文章

  1. 关闭Dynamipsgui的自动更新
  2. aspectjweaver.jar 下载地址
  3. wps2000老版本 v3.02.99
  4. mdf2iso linux,MDF to ISO下载
  5. Pixel手机电信4G破解(含解锁BL和root)
  6. 电脑桌面计算机软件不见了,电脑桌面图标不见了怎么恢复?
  7. 23_Open_Loop
  8. qt drawline 线类型
  9. ALSA声卡驱动二之声卡的创建
  10. 草料二维码 批量生成二维码