HarmonyOS鸿蒙Next中开发应用怎么对接usb串口

HarmonyOS鸿蒙Next中开发应用怎么对接usb串口 使用的SDK 是5.0.5(17)版本的,目前文档上虽然有串口通信 但是我这版本不支持,且大部分的手机都是鸿蒙5.0以下的版本,在应用中需要用到串口通信的一个功能 1 当前应用中暂时使用的是

import { usbManager } from '@kit.BasicServicesKit';

通过这个usb管理来获取链接设备,并进行通信,前提是 手机需要安装一个串口联调应用先进行波特率数据的配置才能在 自己开发的应用上面使用,且当usb断开连接后 在应用中也进行了关闭通道处理,但是在次插入usb连接时进行发送编码通信就不行了 usb通道就没有响应数据了导致应用阻塞并且重启,然后usb通道就一直不通了 需要关机重启 重新配置才能再次使用,哪位大佬指点一下 usb代码如下

import { usbManager } from '@kit.BasicServicesKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { buffer } from '@kit.ArkTS';
import hilog from '@ohos.hilog';

const TAG: string = 'SerialPort';

export class USBCommunication {
  private usbDevice: usbManager.USBDevice | null = null;
  private devicePipe: usbManager.USBDevicePipe | null = null;
  private usbInterface: usbManager.USBInterface | undefined;
  private usbEndpoint: usbManager.USBEndpoint | undefined;
  private readEndpoint: usbManager.USBEndpoint | undefined;
  private mIsReadFree: boolean = true; // 读通道是否空闲
  private mIsWriteFree: boolean = true; // 写通道是否空闲

  constructor() {}

  public async initialize() {
    // 获取当前链接设备
    if(!this.usbDevice){
      this.usbDevice = this.getUSBDevice();
    }else{
      this.close()
    }

    if (this.usbDevice) {
      // 如果有设备的情况下判断是否有权限
      console.log(JSON.stringify(this.usbDevice))
      const hasPermission = await this.checkUSBPermission(this.usbDevice);
      console.log(hasPermission+'设备权限')
      if (hasPermission) {
        // 有设备权限的情况下获取设备列表中的参数,用来做数据的传输
        this.setupUSBInterface(this.usbDevice);
      }
    }
  }

  private getUSBDevice(): usbManager.USBDevice | null {
    const deviceList: Array<usbManager.USBDevice> = usbManager.getDevices();
    console.info(`Device List: ${JSON.stringify(deviceList)}`);
    if (deviceList.length === 0) {
      hilog.error(0x0002, TAG, "Device list is empty");
      return null;
    }
    return deviceList[0];
  }

  private async checkUSBPermission(us: usbManager.USBDevice): Promise<boolean> {
    const deviceName: string = us.name;
    console.log(deviceName+1)
    try {
      const hasRight: boolean = await usbManager.requestRight(deviceName);
      hilog.info(0x0002, TAG, hasRight ? "Permission granted" : "Permission denied");
      return hasRight;
    } catch (error) {
      console.error(`USB device request right failed: ${error}`);
      return false;
    }
  }

  // 移除权限
  private async removeRight(us: usbManager.USBDevice): Promise<boolean> {
    const deviceName: string = us.name;
    console.log(deviceName+2)
    try {
      const removeRightData: boolean = await usbManager.removeRight(deviceName);
      console.log('权限移除');
      return removeRightData;
    } catch (error) {
      console.error(`USB device request right failed: ${error}`);
      return false;
    }
  }

  private setupUSBInterface(usbDevice: usbManager.USBDevice) {
    console.log('Setting up USB interface');
    // 获取设备中的数据传输通道
    const res= this.getUsbInterface(usbDevice);
    if (res[0] &&res[1]) {
      this.usbInterface = res[0];
      this.usbEndpoint = res[1];
      this.readEndpoint = res[2];
      // 打开设备,获取数据传输通道。
      this.devicePipe = this.registerInterface(usbDevice, this.usbInterface, this.usbEndpoint );
    }
  }

  private getUsbInterface(usbDevice: usbManager.USBDevice): [usbManager.USBInterface | undefined, usbManager.USBEndpoint | undefined, usbManager.USBEndpoint | undefined] {
    let usbConfigs: usbManager.USBConfiguration[] = usbDevice.configs;
    let usbInterface: usbManager.USBInterface | undefined;
    let usbEndpoint: usbManager.USBEndpoint | undefined;
    let readEndpoint: usbManager.USBEndpoint | undefined;

    for (const config of usbConfigs) {
      for (const iface of config.interfaces) {
        usbEndpoint = iface.endpoints.find(value => value.direction === 0 && value.type === 2);
        readEndpoint = iface.endpoints.find(value => value.direction === 128 && value.type === 2);

        if (usbEndpoint) {
          usbInterface = iface;
          break;
        }
      }
      if (usbInterface) break;
    }

    if (!usbEndpoint) {
      console.error(`USB endpoint not found`);
    }

    return [usbInterface, usbEndpoint, readEndpoint];
  }

  private registerInterface(usbDevice: usbManager.USBDevice, usbInterface: usbManager.USBInterface, usbEndpoint: usbManager.USBEndpoint) {
    this.devicePipe = usbManager.connectDevice(usbDevice);
    // 声明对USB设备某个接口的控制权。
    const claimInterfaceResult: number = usbManager.claimInterface(this.devicePipe, usbInterface, true);
    console.log(claimInterfaceResult + ' Interface claimed successfully');

    if (claimInterfaceResult !== 0) {
      console.error(`Claim interface error = ${claimInterfaceResult}`);
      return null;
    }
      // 如果通道是实时的情况下重新设置控制
    if (usbEndpoint.type === 1) {
      const setInterfaceResult = usbManager.setInterface(this.devicePipe, usbInterface);
      if (setInterfaceResult !== 0) {
        console.error(`Set interface error = ${setInterfaceResult}`);
        return null;
      }
    }
    return this.devicePipe;
  }
  // 进行设备通信的数据发送
  public async sendData(data: string) {
    if (!this.devicePipe || !this.usbEndpoint) {
      console.error("Device pipe or USB endpoint is not initialized");
      return;
    }

    console.log('Sending data: ' + data);
    // 使用将十六进制中去除0x前缀
    const cleanHex = this.sanitizeHex(data);
    if (!cleanHex || cleanHex.length % 2 !== 0) return;

    try {
      const dataLength = await usbManager.bulkTransfer(this.devicePipe, this.usbEndpoint, new Uint8Array(buffer.from(cleanHex, 'hex').buffer), 15000);
      if (dataLength >= 0) {
        console.info(`USB write data result: write length = ${dataLength}`);
        usbManager.releaseInterface(this.devicePipe!, this.usbInterface!);
      } else {
        this.close()
        console.error("USB write data failed");
      }
    } catch (error) {
      this.close()
      console.error(`USB write data error: ${error}`);
    }
  }

  // 进行读取设备数值
  public receiveData(): Promise<string> {
    return new Promise((resolve, reject) => {
      if (!this.devicePipe || !this.readEndpoint) {
        console.error("Device pipe or read endpoint is not initialized");
        reject(new Error("Device pipe or read endpoint is not initialized"));
        return;
      }
      if (!this.mIsReadFree) {
        console.error("通道被占用");
        reject(new Error("Channel is busy"));
        return;
      }
      this.mIsReadFree = false

      const dataUint8Array: Uint8Array = new Uint8Array(1024);
      usbManager.bulkTransfer(this.devicePipe, this.readEndpoint, dataUint8Array, 15000)
        .then((dataLength: number) => {
          usbManager.releaseInterface(this.devicePipe!, this.usbInterface!);
          this.mIsReadFree = true
          if (dataLength >= 0) {
            const validData = dataUint8Array.subarray(0, dataLength);
            const hexString = Array.from(validData, byte => byte.toString(16).padStart(2, '0')).join('');
            // console.info(`Hex data: 0x${hexString}`);
            const byteBuffer = buffer.from(hexString, 'hex');
            // const resultString = byteBuffer.toString('utf-8');
            const resultString = byteBuffer.toString('ascii');
            // console.log(`Final result: ${resultString}`);
            resolve(resultString); // 返回读取到的字符串
          } else {
            console.error("USB read data failed");
            this.close()
            reject(new Error("USB read data failed"));
          }
        })
        .catch((error: BusinessError) => {
          console.error(`USB read data error: ${error}`);
          this.close()
          this.mIsReadFree = true
          reject(error); // 拒绝 Promise
        });
    });
  }

  public close() {
    if (this.devicePipe) {
      usbManager.releaseInterface(this.devicePipe!, this.usbInterface!);
      usbManager.closePipe(this.devicePipe);
      this.devicePipe = null
      console.info("Device pipe closed");
    }
  }
  // 移除权限并关闭设备和释放通信接口
  public async removeReset(){
    console.log(JSON.stringify(this.usbDevice)+'222')
    if(this.usbDevice){
       let removeRes =  await this.removeRight(this.usbDevice)
      console.log('移除权限'+removeRes)
         if(removeRes){
            this.close()
         }
    }
  }



  private sanitizeHex(hexInput: string): string {
    return hexInput.replace(/^0x/i, '').replace(/[^0-9a-fA-F]/g, '');
  }
}

在应用中的使用代码如下

  @Monitor('assist.isLink') // 监听所有子属性
  async onIsLinkChange(mon: IMonitor) {
    console.log('设备链接'+this.assist.isLink)
    if(this.usbTimeId){
      clearInterval(this.usbTimeId)
      this.usbTimeId = null
    }
    if(this.assist.isLink){
      this.executeCommands()
    }else{
      // 当断开连接时需要关闭和清除设备链接通道和断开通信
      this.USBCommunication.removeReset()
    }
    // mon.dirty.forEach(path => console.log(`路径 ${path} 变化`));
  }
  async  executeCommands() {
    try {
      // 清空直接解析量和粉碎解析量
      this.assist.directList =[]
      this.assist.smashList =[]
      // 发送第一个指令
      await this.USBCommunication.initialize(); // 初始化 USB 通信
     this.USBCommunication.sendData('0x9d');
      console.log('指令 0x9d 发送成功。');

      // 等待第一个指令的响应
      let res = await this.USBCommunication.receiveData();
      console.log(`指令 0x9d 的响应: ${res}`);

      // 发送第二个指令
      await this.USBCommunication.initialize(); // 初始化 USB 通信
      this.USBCommunication.sendData('0x56');
      console.log('指令 0x56 发送成功。');

      // 等待第二个指令的响应
      let res2 = await this.USBCommunication.receiveData();
      console.log(`指令 0x56 的响应: ${res2}`);

      // 在发送两个指令并接收到响应后,开始定时器
      this.usbTimeId = setInterval(async () => {
        try {
          await this.USBCommunication.initialize(); // 初始化 USB 通信
          const response = await this.USBCommunication.receiveData();
          const numberString = response.split('=')[1]?.trim()
          // 转换为数值 除以1000 得到每分钟ml的数值
          const value = Number((numberString ? parseFloat(numberString) : 0)) / 1000; // 使用 parseFloat 转换为浮点数
          console.log(`定时响应: ${value}`);

          // 直接测定开始时将获取的数据存储在存储到数组中
          if(this.measureModel==1){
            this.assist.directList.push(value)
          }

          // 粉碎测定开始时将获取的数据存储在存储到数组中
          if(this.measureModel==2){
            this.assist.smashList.push(value)
          }
          // 当开始读取usb设备数据时 就可以点击测定开始按钮
          this.assist.directBtn = true
        } catch (error) {
          if(this.usbTimeId){
            clearInterval(this.usbTimeId)
            this.usbTimeId = null
          }
          console.error(`接收数据时出错: ${error}`);
        }
      }, 200);
    } catch (error) {
      console.error(`执行指令时出错: ${error}`);
      if(this.usbTimeId){
        clearInterval(this.usbTimeId)
        this.usbTimeId = null
      }
    } finally {
      // 可选:在某个时刻关闭通信
      // usbComm.close(); // 如果希望立即关闭,可以取消注释
    }
  }

更多关于HarmonyOS鸿蒙Next中开发应用怎么对接usb串口的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

在HarmonyOS Next中对接USB串口,需使用@ohos.usbV9接口。首先在module.json5中声明USB设备使用权限和设备过滤信息。通过usb.getDevices()获取设备列表,使用usb.openDevice()打开指定设备。获取设备接口后,使用usb.claimInterface()声明接口。通过usb.bulkTransfer()进行批量数据传输,或使用usb.controlTransfer()进行控制传输。使用完毕后,调用usb.releaseInterface()usb.closeDevice()释放资源。

更多关于HarmonyOS鸿蒙Next中开发应用怎么对接usb串口的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


根据你的代码分析,主要问题在于USB接口和管道的管理逻辑。在sendDatareceiveData方法中,每次传输后都调用了releaseInterface,这会释放对接口的占用。但在下一次传输时,代码没有重新claimInterface,导致后续操作失败。

问题核心在sendData方法:

if (dataLength >= 0) {
  console.info(`USB write data result: write length = ${dataLength}`);
  usbManager.releaseInterface(this.devicePipe!, this.usbInterface!); // 这里释放了接口
}

同样在receiveData的Promise回调中也有:

usbManager.releaseInterface(this.devicePipe!, this.usbInterface!);

修改建议:

  1. 移除sendDatareceiveData中的releaseInterface调用
  2. 只在真正需要关闭连接时(如设备断开、应用退出)调用releaseInterface
  3. 确保每次initialize时,如果已有devicePipe,先正确关闭再重新初始化

initialize方法中,当usbDevice已存在时调用close()是正确做法,但需要确保close方法完全释放资源。

另外,在应用代码中频繁调用initialize()也可能导致问题。建议在连接建立后保持USB状态,而不是每次发送/接收都重新初始化。

回到顶部