查看: 412|回复: 1

UT325D 接触式温度计分析

[复制链接]

该用户从未签到

发表于 2018-7-12 12:51 | 显示全部楼层 |阅读模式
最近公司有要求进行温度的记录,经过研究入手“UT325数字测温仪,这是是优利德(UNI-T 生产的双路测温仪。
image001.png
                              
但是对于需要用上位机采集数据的用户来说,它只是单路的。它可以通过USB口上报 T1 温度,T2温度或者 T1-T2温度,但是没有办法同时报告 T1 T2温度,并且只能通过正面按键才能切换报告的通道,因此,对于我们来说,这只是单通道的测温仪。
image002.png
官方没有提供支持,为了获得通讯协议,需要使用 USBlyzer 抓取数据逐步分析。第一步就是抓取 Descriptor
USB Input Device
  
Connection Status
  
  
Device connected
  
  
Current Configuration
  
  
1
  
  
Speed
  
  
Full (12 Mbit/s)
  
  
Device Address
  
  
8
  
  
Number Of Open Pipes
  
  
2
  
Device Descriptor USBto Serial
  
Offset
  
  
Field
  
  
Size
  
  
Value
  
  
Description
  
  
0
  
  
bLength
  
  
1
  
  
12h
  
  
1
  
  
bDescriptorType
  
  
1
  
  
01h
  
  
Device
  
  
2
  
  
bcdUSB
  
  
2
  
  
0100h
  
  
USB Spec 1.0
  
  
4
  
  
bDeviceClass
  
  
1
  
  
00h
  
  
Class info in Ifc Descriptors
  
  
5
  
  
bDeviceSubClass
  
  
1
  
  
00h
  
  
6
  
  
bDeviceProtocol
  
  
1
  
  
00h
  
  
7
  
  
bMaxPacketSize0
  
  
1
  
  
08h
  
  
8 bytes
  
  
8
  
  
idVendor
  
  
2
  
  
1A86h
  
  
10
  
  
idProduct
  
  
2
  
  
E008h
  
  
12
  
  
bcdDevice
  
  
2
  
  
1400h
  
  
14.00
  
  
14
  
  
iManufacturer
  
  
1
  
  
01h
  
  
"WCH.CN ."
  
  
15
  
  
iProduct
  
  
1
  
  
02h
  
  
"USB to Serial"
  
  
16
  
  
iSerialNumber
  
  
1
  
  
00h
  
  
17
  
  
bNumConfigurations
  
  
1
  
  
01h
  
Configuration Descriptor1 Bus Powered, 100 mA
  
Offset
  
  
Field
  
  
Size
  
  
Value
  
  
Description
  
  
0
  
  
bLength
  
  
1
  
  
09h
  
  
1
  
  
bDescriptorType
  
  
1
  
  
02h
  
  
Configuration
  
  
2
  
  
wTotalLength
  
  
2
  
  
0029h
  
  
4
  
  
bNumInterfaces
  
  
1
  
  
01h
  
  
5
  
  
bConfigurationValue
  
  
1
  
  
01h
  
  
6
  
  
iConfiguration
  
  
1
  
  
04h
  
  
7
  
  
bmAttributes
  
  
1
  
  
80h
  
  
Bus Powered
  
  
4..0: Reserved
  
  
...00000
  
  
5: Remote Wakeup
  
  
..0.....
  
  
No
  
  
6: Self Powered
  
  
.0......
  
  
No, Bus Powered
  
  
7: Reserved (set to one)
  (bus-powered for 1.0)
  
  
1.......
  
  
8
  
  
bMaxPower
  
  
1
  
  
32h
  
  
100 mA
  
Interface Descriptor 0/0 HID,2 Endpoints
  
Offset
  
  
Field
  
  
Size
  
  
Value
  
  
Description
  
  
0
  
  
bLength
  
  
1
  
  
09h
  
  
1
  
  
bDescriptorType
  
  
1
  
  
04h
  
  
Interface
  
  
2
  
  
bInterfaceNumber
  
  
1
  
  
00h
  
  
3
  
  
bAlternateSetting
  
  
1
  
  
00h
  
  
4
  
  
bNumEndpoints
  
  
1
  
  
02h
  
  
5
  
  
bInterfaceClass
  
  
1
  
  
03h
  
  
HID
  
  
6
  
  
bInterfaceSubClass
  
  
1
  
  
00h
  
  
7
  
  
bInterfaceProtocol
  
  
1
  
  
00h
  
  
8
  
  
iInterface
  
  
1
  
  
00h
  
HID Descriptor
  
Offset
  
  
Field
  
  
Size
  
  
Value
  
  
Description
  
  
0
  
  
bLength
  
  
1
  
  
09h
  
  
1
  
  
bDescriptorType
  
  
1
  
  
21h
  
  
HID
  
  
2
  
  
bcdHID
  
  
2
  
  
0100h
  
  
1.00
  
  
4
  
  
bCountryCode
  
  
1
  
  
00h
  
  
5
  
  
bNumDescriptors
  
  
1
  
  
01h
  
  
6
  
  
bDescriptorType
  
  
1
  
  
22h
  
  
Report
  
  
7
  
  
wDescriptorLength
  
  
2
  
  
0025h
  
  
37 bytes
  
Endpoint Descriptor 82 2In, Interrupt, 5 ms
  
Offset
  
  
Field
  
  
Size
  
  
Value
  
  
Description
  
  
0
  
  
bLength
  
  
1
  
  
07h
  
  
1
  
  
bDescriptorType
  
  
1
  
  
05h
  
  
Endpoint
  
  
2
  
  
bEndpointAddress
  
  
1
  
  
82h
  
  
2 In
  
  
3
  
  
bmAttributes
  
  
1
  
  
03h
  
  
Interrupt
  
  
1..0: Transfer Type
  
  
......11
  
  
Interrupt
  
  
7..2: Reserved
  
  
000000..
  
  
4
  
  
wMaxPacketSize
  
  
2
  
  
0008h
  
  
8 bytes
  
  
6
  
  
bInterval
  
  
1
  
  
05h
  
  
5 ms
  
Endpoint Descriptor 02 2Out, Interrupt, 5 ms
  
Offset
  
  
Field
  
  
Size
  
  
Value
  
  
Description
  
  
0
  
  
bLength
  
  
1
  
  
07h
  
  
1
  
  
bDescriptorType
  
  
1
  
  
05h
  
  
Endpoint
  
  
2
  
  
bEndpointAddress
  
  
1
  
  
02h
  
  
2 Out
  
  
3
  
  
bmAttributes
  
  
1
  
  
03h
  
  
Interrupt
  
  
1..0: Transfer Type
  
  
......11
  
  
Interrupt
  
  
7..2: Reserved
  
  
000000..
  
  
4
  
  
wMaxPacketSize
  
  
2
  
  
0008h
  
  
8 bytes
  
  
6
  
  
bInterval
  
  
1
  
  
05h
  
  
5 ms
  
Interface 0 HID ReportDescriptor Vendor-Defined 1
  
Item Tag (Value)
  
  
Raw Data
  
  
Usage Page (Vendor-Defined 161)
  
  
06 A0 FF
  
  
Usage (Vendor-Defined 1)
  
  
09 01
  
  
Collection (Application)
  
  
A1 01
  
  
    Usage  (Vendor-Defined 1)
  
  
09 01
  
  
    Logical  Minimum (0)
  
  
15 00
  
  
    Logical  Maximum (255)
  
  
26 FF 00
  
  
    Report  Size (8)
  
  
75 08
  
  
    Report  Count (8)
  
  
95 08
  
  
    Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit)
  
  
81 02
  
  
    Usage  (Vendor-Defined 2)
  
  
09 02
  
  
    Report  Size (8)
  
  
75 08
  
  
    Report  Count (8)
  
  
95 08
  
  
    Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit)
  
  
91 02
  
  
    Usage  (Vendor-Defined 3)
  
  
09 03
  
  
    Report  Size (8)
  
  
75 08
  
  
    Report  Count (5)
  
  
95 05
  
  
    Feature (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit)
  
  
B1 02
  
  
End Collection
  
  
C0
  
This report was generated by USBlyzer
Descriptor上可以看到,它是通过 HID来进行通讯的(根据【参考1】,使用WCH CH9325 Uart HID 芯片),这种通讯的好处是无需使用驱动,缺点是速度不快,这里对于温度这种物理量来说已经足够使用。
第二步,分析具体通讯协议了,好在网上找到了一些资料【参考2】,虽然对不上(国产设备经常发生型号相同,但是细节完全不同的情况),但是根据提示重新捋一下还是能够得到大概的结果。
image003.png image004.png
image005.png
  
最终的结论是:每次读取HID数据中第二个字节是有意义的,我们需要的温度信息就在上面数值的第二个字节中。

编写一个 Application,输出读取到的数据,可以看到存在一个以  0x0D0x0A作为结尾的循环节。下面的数据中,第一个是HIDReport ID, 所以会比前面USB Analyzer 抓到的多一个。
image006.png
针对有意义的数值(就是前面红框中的第三个数值:00 00 00 00 00 00 32 3A…….0D 0A)进行分析。

  
偏移(Byte)
  
0
保留,0x00
1
保留,0x00
2
保留,0x00
3
保留,0x00
4
保留,0x00
5
保留,0x00
6
保留,0x32
7
ASCII,  
  
符号位,正=0x3A,负=0x3B
8
ASCII
9
ASCII
10
ASCII
11
当前温度单位,摄氏度=1,华氏度=2,开尔文温度=3
12
保留,0x30
13
保留,0x30
14
保留,0x30
15
ASCII格式的时间
16
ASCII格式的时间
17
ASCII格式的时间
18
ASCII格式的时间
19
数据来源:
  
T1=0
  
T2=1
  
T1-T2=2
20
保留,0x00
21
保留,0x00
22
保留,0x31
23
保留,0x0D
24
保留,0x0A
image007.png
接下来,发现遇到一个奇怪的问题:第一次插入之后运行数据什么数值都没有,就是说:设备上电之后不会主动发送数据出来,而我抓取的数据都是先运行 UT325D的软件查看设备能否正常工作之后才有的。
猜测是运行配套软件之后,上位机的软件发送了什么命令给设备,设备才会打开输出输出的功能。为此,用 USBlyzer录制启动软件后的通讯。
可以看到,按下上位机软件的 USB Connection 之后,有三条可疑的指令(确定肯定是上位机触发的,因此在 OUT 的通讯中查找即可),一个是 Set Report 60 09 0000 03,另外两个是 HID  02 5A 00 00 00 00 00 00 01 01 00 00 00 00 0000
image008.png
为了便于实验,使用SimpleHIDWrite3 这个软件,它是专门针对 HID设备的测试软件,能够在无需编程的情况下直接发送命令。
打开工具后选择 UT325D 这个 USB 设备,在 SimpleHIDWrite3 这个软件中,该设备名称是 USB to Serial (这个软件使用 Device Descriptor 中的iProduct字符串作为设备名)
image009.png
再进一步,我们使用 Info 按钮查看设备信息,可以看到如下内容:
image010.png
特别注意的是,对于这个设备 HID ReportSize 9字节(1 Report ID + 8 个自定义内容),Feature Report 的字节是6个。
经过测试,首先使用这个工具SetFeature  6009 00 00 03给设备数据即可开始发送全0的数据,然后需要再使用工具发送 HID 01 01 00 00 00 0000 00,这个设备即可像自带工具一样发送正常数据了。
整个代码是基于我们之前编写的 HIDSend,不同点在于我们引入了HidD_SetFeature API 针对设备发送 SetFeature命令
                                                     //发送报告的缓冲区,1字节报告ID+8字节报告数据。
                                                     UCHAR WriteReportBuffer[6];
                                                     WriteReportBuffer[0]= 0x00;
                                                      WriteReportBuffer[1] = 0x60;
                                                     WriteReportBuffer[2]= 0x09;
                                                     WriteReportBuffer[3]= 0x00;
                                                     WriteReportBuffer[4]= 0x00;
                                                     WriteReportBuffer[5]= 0x03;
                                                     //调用HidD_SetFeature函数发送数据
                                                     Result= HidD_SetFeature(
                                                            hUsb,
                                                            WriteReportBuffer,
                                                            6);
这步完成之后,再使用WriteFile发送我们的 HID 数据:
                                                     WriteReportBuffer[0]= 0x00;
                                                     WriteReportBuffer[1]= 0x01;
                                                     WriteReportBuffer[2]= 0x01;
                                                     WriteReportBuffer[3]= 0x00;
                                                     WriteReportBuffer[4]= 0x00;
                                                     WriteReportBuffer[5]= 0x00;
                                                     WriteReportBuffer[6]= 0x00;
                                                     WriteReportBuffer[7]= 0x00;
                                                     DWORD lpNumberOfBytesWritten;
                                                     //调用WriteFile函数发送数据
                                                     Result= WriteFile(hUsb,
                                                            WriteReportBuffer,
                                                            9,
                                                            &lpNumberOfBytesWritten,
                                                            NULL);
上述完成之后就可以正常接收数据了,使用ReadFile反复读取
                                                     //调用ReadFile 接收数据
                                                     Result= ReadFile(
                                                            hUsb,
                                                            ReadReportBuffer,
                                                            9,
                                                            &lpNumberOfBytesRead,
                                                            NULL);
之后再对收到的数据进行解析,需要注意的是,每次收到的 HID报文中,只有第三个数值是有效的,因此我还引入counter变量进行解析。也正是因为这样解析的缘故,所以输出的时间格式是:SS“ MM’
                                 //if (counter == 6) { printf("%c", ReadReportBuffer[2]);}
                                 if (counter == 7) { printf("%c", ReadReportBuffer[2]); }
                                 if (counter == 8) { printf("%c", ReadReportBuffer[2]); }
                                 if (counter == 9) { printf("%c", ReadReportBuffer[2]); }
                                 if (counter == 10) { printf("%c", ReadReportBuffer[2]); }
                                 if ((counter ==11)&&(ReadReportBuffer[2]==0x31)) { printf("C"); }
                                 if ((counter == 11) &&(ReadReportBuffer[2] == 0x32)) { printf("F"); }
                                 if ((counter == 11) &&(ReadReportBuffer[2] == 0x33)) { printf("K"); }
                                 if (counter == 15) { printf(" %c", ReadReportBuffer[2]); }
                                 if (counter == 16) { printf("%c\"",ReadReportBuffer[2]); }
                                 if (counter == 17) { printf("%c", ReadReportBuffer[2]); }
                                 if (counter == 18) { printf("%c'", ReadReportBuffer[2]); }
                                 if ((counter == 19) &&(ReadReportBuffer[2] == 0x30)) { printf("T1"); }
                                 if ((counter == 19) &&(ReadReportBuffer[2] == 0x31)) { printf("T2"); }
                                 if ((counter == 19) &&(ReadReportBuffer[2] == 0x32)) { printf("T1-T2"); }
                                                     
                                 if (ReadReportBuffer[2] == 0xA) {
                                                     printf("\n"); counter = 0;
                                                     }
运行结果如下:
image011.png
参考:
1. https://sigrok.org/wiki/WCH_CH9325
3. http://www.uni-trend.com.cn/productsdetail_1302_460_460.html

打赏作者鼓励一下!

该用户从未签到

 楼主| 发表于 2018-7-12 12:53 | 显示全部楼层
完整代码下载
UT325D.zip (65.79 KB, 下载次数: 3)
打赏作者鼓励一下!
您需要登录后才可以回帖 登录 | 立即注册  

本版积分规则

热门推荐

Uno A4988驱动42步进电机若干问题?求高手进
Uno A4988驱动42步进电机
上代码: void setup() { pinMode(8, OUTPUT); //8引脚为使能引脚
arduino可以控制cw250驱动器吗
arduino可以控制cw250驱动
我想用arduino来控制cw250步进电机驱动器,实现步进电机的运转,求大神给解释一下如何
Arduino的一个小问题。
Arduino的一个小问题。
像这种,第一个划线处定义了变量tepTimer ,,后面根本没有赋初值就直接用了,,为什么
原创 drawbot平面关节机械臂 教程直播贴
原创 drawbot平面关节机械
这个项目上个月就在做了,结构和代码反反复复改了多次,加上自己又太忙,一直没来得及
DS18B20代码编译出错
DS18B20代码编译出错
这个是DallsTemperature的示例,但是报了一个错,不知是为何
Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   ( 蜀ICP备14017632号-3 )
快速回复 返回顶部 返回列表