USB HID 连接TH20BL温湿度计读取实时温湿度的JAVA例子
import com.codeminders.hidapi.ClassPathLibraryLoader; import com.codeminders.hidapi.HIDDeviceInfo; import com.codeminders.hidapi.HIDManager; import com.codeminders.hidapi.HIDDevice; public class USBHIDExample { public static void main(String[] args) { try { ClassPathLibraryLoader.loadNativeHIDLibrary(); HIDManager hidManager = HIDManager.getInstance(); HIDDeviceInfo[] devices = hidManager.listDevices(); HIDDevice thDevice = getOneTHDevice(devices); GetRealtimeTH(thDevice); if(thDevice !=null) { thDevice.close(); } } catch (Exception e) { e.printStackTrace(); } } public static HIDDevice getOneTHDevice(HIDDeviceInfo[] devices) { HIDDeviceInfo hidDeviceInfo = null; for (HIDDeviceInfo deviceInfo : devices) { String deviceName = deviceInfo.getProduct_string(); //温湿度的usb设备名称里面有 HHW字符串 if(deviceName !=null && deviceName.contains("HHW")) { System.out.println(deviceName); hidDeviceInfo = deviceInfo; break; } } if(hidDeviceInfo != null) { try { HIDDevice hd = hidDeviceInfo.open(); return hd; } catch (Exception e) { e.printStackTrace(); } } return null; } public static void GetRealtimeTH(HIDDevice hidDevice) { // Convert the hexadecimal string to bytes // 8bytes 01 默认站号 04 功能码 00 00 02 数据个数 71 CB CRC。 这里以站号1做的例子,如果其他站号,指令要修改 //00 00 08 01 04 00 00 00 02 71 CB byte[] dataToSend = Helper.StrToHexByte("00000801040000000271CB"); try { hidDevice.write(dataToSend); // Receive data from the device byte[] receivedData = new byte[11]; hidDevice.read(receivedData); String receiveData = Helper.byteToHexStr(receivedData); System.out.println(Helper.byteToHexStr(receivedData)); parseRealtimeTH(receiveData); } catch (Exception e) { e.printStackTrace(); } } private static void parseRealtimeTH(String s) { int len = Integer.parseInt(s.substring(0, 1)); if (len == 9) { String validData = s.substring(1, len * 2 + 1); System.out.println(validData); float t = Helper.ConvertHexToSInt(validData.substring(6, 10)) / 10.0f; float h = Helper.ConvertHexToSInt(validData.substring(10, 14)) / 10.0f; System.out.println("实时温度:" + t + ", 实时湿度:" + h); } } }
import java.math.BigInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Helper { //16进制字符串转化为16进制byte数组 public static byte[] StrToHexByte(String hexString) { if (IsNullOrEmpty(hexString)) { return null; } hexString=hexString.toUpperCase(); int length = hexString.length()/2; char[] hexChars = hexString.toCharArray(); byte[] d= new byte[length]; for(int i = 0; i < length; i++) { int pos = i * 2; d[i] = (byte)(charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); } return d; } private static byte charToByte(char c) { return (byte)"0123456789ABCDEF".indexOf(c); } // byte[] to HexString public static String byteToHexStr(byte[] bytes) { /*在Java中,new BigInteger(1, bytes).toString(16)和手动迭代字节数组并转换为16进制字符串的方法之间的区别在于处理字节数组中的前导零。 new BigInteger(1, bytes).toString(16)会忽略字节数组中的前导零,导致生成的16进制字符串不包含前导零。 手动迭代字节数组并转换为16进制字符串的方法会保留字节数组中的前导零,生成的16进制字符串会包含前导零。 因此,如果您希望保留字节数组中的前导零,可以使用手动迭代字节数组的方法。如果您希望忽略前导零,可以使用new BigInteger(1, bytes).toString(16)方法。选择哪种方法取决于您的需求和预期的结果。 */ String result = new BigInteger(1,bytes).toString(16); return result; // StringBuilder sb = new StringBuilder(); // for(byte b:bytes){ // sb.append(String.format("%02x",b)); // } // return sb.toString(); } /// <summary> /// 将16进制转换为有符号的10进制 /// </summary> /// <param name="hexstr"></param> /// <returns></returns> public static String ConvertHexToSIntStr(String hexstr) { if (hexstr.startsWith("0x")) { hexstr = hexstr.substring(2); } //如果不是有效的16进制字符串或者字符串长度大于16或者是空,均返回NULL if (!IsHexadecimal(hexstr) || hexstr.length() > 16 || IsNullOrEmpty(hexstr)) { return null; } if (hexstr.length() > 8) { return String.valueOf(Integer.valueOf(hexstr,16).longValue()); } else if (hexstr.length() > 4) { return String.valueOf(Integer.valueOf(hexstr,16).intValue()); } else { return String.valueOf(Integer.valueOf(hexstr,16).shortValue()); } } public static long ConvertHexToSInt(String hexstr) { if (hexstr.startsWith("0x")) { hexstr = hexstr.substring(2); } //如果不是有效的16进制字符串或者字符串长度大于16或者是空,均返回NULL if (!IsHexadecimal(hexstr) || hexstr.length() > 16 || IsNullOrEmpty(hexstr)) { return 99999; } if (hexstr.length() > 8) { return Integer.valueOf(hexstr,16).longValue(); } else if (hexstr.length() > 4) { return Integer.valueOf(hexstr,16).intValue(); } else { return Integer.valueOf(hexstr,16).shortValue(); } } //one byte public static String ConverIntToHexStr2(int t) { //显示为2个16进制字符 return String.format("%02x",t); } //two byte public static String ConverIntToHexStr4(int t) { String rs = ""; //leng 4; //显示为4个16进制字符 if (t >= 0) { rs= String.format("%04x",t); } else { //负数显示处理(这个是根据实际运行中显示的数据长度进行的处理),负数是4个字节表示,高2位为ffff String j = String.format("%04x",t); rs= j.substring(j.length()/2); } //返回末尾4个字符 return rs.substring(rs.length()-4).toUpperCase(); } /// <summary> /// 判断是否是十六进制格式字符串 /// </summary> /// <param name="str"></param> /// <returns></returns> public static boolean IsHexadecimal(String str) { String PAT = "[A-Fa-f0-9]+$"; return Pattern.matches(PAT, str); } public static boolean IsNullOrEmpty(String str) { if(str==null || str.length() == 0) return true; return false; } //标准modbus crc 2个字节 低前高后 public static int crc16_modbus(byte[] modbusdata, int length) { int i, j; int crc16 = 0x0000ffff; for (i = 0; i < length; i++) { crc16 ^= ((int)modbusdata[i]&0x000000ff); for (j = 0; j < 8; j++) { if ((crc16 & 0x00000001) == 1) { crc16 = (crc16 >> 1) ^ 0x0000a001; } else { crc16 = crc16 >> 1; } } } //little在前,high在后 return ((crc16 & 0xff) << 8) + (crc16 >> 8); } //计算crcm public static int CRC16(String s) { byte[] a = Helper.StrToHexByte(s); int len = a.length; int crc = Helper.crc16_modbus(a, len); return (crc + 4660); } }