qt 之usb(hid)与单片机通信

前言:

 

usb 不仅仅hid通信方式,还有其余的usb通信方式,但hid的好处就是无需安装驱动,热插拔直接用,等,具体详细介绍自行百度。

目的:

此处插补一个写此文章的目的:

下位机与上位机串口通信连接不同usb接口,避免每次自动重新配置连接的串口端口号 三种方式:
1.修改下位机程序,上位机程序不变
下位机程序输出接口改为usb虚拟串口模式,硬件外设采用usb接口,参考正点原子库函数库例程(USB虚拟串口试验),这样不论usb插哪一个接口,均为同一虚拟串口。

2.下位机硬件和程序不变,上位机采用轮询连接当前设备可用串口,连接后通信测试,测试成功代表串口正确。

3.下位机硬件加上ttl转usb芯片,程序不变,上位机添加usb设备识别,即此篇文章的目的。

环境:

qt5.7 (msvc2013 32bit)

准备:

本文介绍采用hid方式,所以提供的连接都是hid的

参考链接:Qt USB通信--hidapi的使用_www.wowothink.com的博客-CSDN博客_-lhidapi

参考链接:Ubuntu/Windows下利用“HIDAPI”库函数实现与Hid类USB设备通信 - Ch_Y_Q - 博客园

下载资料链接:USBDEVICE.rar-QT工具类资源-CSDN下载

正文:

首先是qt上位机部分,我是拿的hid无线鼠标试验的,在设备管理器找到鼠标的vid和pid

已配置设备 HID\VID_1EA7&PID_0064&Col02\6&37799645&0&0001。

 代码如下。hid_read函数目前不可用,使用程序就会报异常,目前只能write和获取设备一些信息,但是无法看出来实际的效果,暂时停止进展,等待用单片机做一个串口转hid usb的出来,或者单片机直接写好usb hid 的底层驱动,在具体通信实验。

记录下当前时间:2019年8月23日12:38:58

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "hidapi.h"

#define MAX_STR 255

//#pragma comment(lib, "D:/QT57/workspace/My/untitled1/hidapi.lib")
//#pragma comment(lib, "hidapi.lib")

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    int res;
    unsigned char buf[128];
    wchar_t wstr[MAX_STR];
    hid_device *handle;
    int i;

    // Open the device using the VID, PID,
    // and optionally the Serial number.
    handle = hid_open(0x1EA7, 0x0064, NULL);
    qDebug()<<"handle"<<handle;
    //目前只能写入,不能读取,等待  串口ttl转hid usb芯片到货在试验
    //res = hid_read(handle, buf, 128);

    qDebug()<<"buf0"<<buf[0];
    qDebug()<<"buf1"<<buf[1];



    // Read the Manufacturer String
    res = hid_get_manufacturer_string(handle, wstr, MAX_STR);
    wprintf(L"Manufacturer String: %s\n", wstr);

    // Read the Product String
    res = hid_get_product_string(handle, wstr, MAX_STR);
    wprintf(L"Product String: %s\n", wstr);

    // Read the Serial Number String
    res = hid_get_serial_number_string(handle, wstr, MAX_STR);
    wprintf(L"Serial Number String: (%d) %s\n", wstr[0], wstr);

    // Read Indexed String 1
    res = hid_get_indexed_string(handle, 1, wstr, MAX_STR);
    wprintf(L"Indexed String 1: %s\n", wstr);

    // Toggle LED (cmd 0x80). The first byte is the report number (0x0).
    buf[0] = 0x0;
    buf[1] = 0x80;
    res = hid_write(handle, buf, 65);

    // Request state (cmd 0x81). The first byte is the report number (0x0).
    buf[0] = 0x0;
    buf[1] = 0x81;
    res = hid_write(handle, buf, 65);

    //Read requested state
    //hid_read(handle, buf, 65);

    //Print out the returned buffer.
    for (i = 0; i < 4; i++)
        printf("buf[%d]: %d\n", i, buf[i]);

    //return 0;

}


MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{

}

2019年11月29日16:43:09补更新

距离发帖已经很久了,之前没能解决这个问题,这会趁着空闲,腾出时间抓紧时间又研究了一下这个,发现拿hid的鼠标键盘测试是不靠谱的,还是用了一个ch9326模块,串口转换usb,再用串口转ttl模块模仿下位机与电脑通讯,如图所示

这个每个模块,应该说是每个芯片 都有对应固定的vid和pid,我这个模块对应的id是0x1A86, 0xE010,加了一个线程专门接收usb数据,这个不像是串口有readyread这种中断机制可以调回调函数去处理,下面话不多说上代码

 初始化:

    hid_init();//不初始化也可以。在open里会初始化
    qDebug()<<handle;
    handle = hid_open(0x1A86, 0xE010, NULL);//模块
    qDebug()<<handle;
    if(handle==0)
        QMessageBox::information(this, "warn", "未检测到设备,使用可能导致异常!");
    else{
        hid_set_nonblocking(handle, 1);
        thread1=new USB_Thread;
        thread1->start();
        connect(thread1,&USB_Thread::updateString11,this,&MainWindow::updateStr);
    }

发送接收:

//自动接收
void MainWindow::updateStr(QString str1)
{
    if(!str1.isEmpty())
    {
        ui->textEdit->setText(str1);
    }
}
//手动接收
void MainWindow::on_pushButton_clicked()
{
    qDebug("hid read start");
    int res;
    QString show_text;
    for(int i=0;i<32;i++)
      buf_IN[i]=0x0b;
    start_flag=true;
    //while (start_flag) {
        QCoreApplication::processEvents();
        res = hid_read(handle,buf_IN,32);
        for(int i = 0;i < 32;i++){
            qDebug("buf[%d]:0x%02x",i,buf_IN[i]);
            show_text+=tr("%1,").arg(buf_IN[i]);
        }
        ui->textEdit->setText(show_text);
        show_text.clear();
   //}
}
//手动发送
void MainWindow::on_pushButton_3_clicked()
{
    int res;	// 如果返回-1表示发送失败
    unsigned char buf[10];
     buf[0] = 0;	// 这就是Report ID
     buf[1] = 0x0a;
     for(int i=0;i<10;i++)
        buf[2+i] = i;
     //QCoreApplication::processEvents();
     res = hid_write(handle, buf, 33);//此处必须是33或这大于一些的数字,不知为什么
     qDebug()<<res;
}

线程:

void USB_Thread::run()
{
    unsigned char rbuf[32];
    QString str;
    while (1)
    {
        if(isStop)
            return;

        for(int i=0;i<32;i++)
          rbuf[i]=0x0b;
        hid_read(handle,rbuf,32);//读一包数据,判断是否有数据进来
        sleep(1);//此处延时不可省略,否则接收数据不完全
        if(rbuf[0]!=0x0b&&rbuf[31]!=0x0b){//判断包头包尾是否自己写入的
            while(1){
                for(int i = 1;i < 32;i++){//从1开始,跳过数据长度第一位
                   str+=tr("%1,").arg(rbuf[i]);
                }
                //qDebug()<<str;
                for(int i=0;i<32;i++)
                  rbuf[i]=0x0b;
                hid_read(handle,rbuf,32);//读一包数据,判断是否数据读取完毕,最大支持接收(32-1)*n=31*n字节数据
                if(rbuf[0]==0x0b&&rbuf[31]==0x0b)
                    break;
            }
            //qDebug()<<str;
            emit updateString11(str);
        }
        else
            str.clear();
    }
}

核心的地方应该算是在线程里处理数据的地方了,在线程中,首先一直判断是否接收到数据,若接收到数据,在嵌入一层逻辑关系去判断什么时候把来的数据接收完毕,这个usb发送数据是一包一包的发送,每包发送32字节,第一字节是长度,其余31字节才是有效数据,数据不足31则补0,在读取数据前像buf里写数是为了判断是否接收到数据。理解还是很容易的,usb发送接收功能都可以实现。

结语:

经历了这么长时间的帖子,最后也算是完美收工,结贴!

资源补充:

在 配置过程中可能需要用到一些dll和其他的工具

资源如下

上面例程源码(win8+64  qt5.7):USB上下位机通信.rar-QT代码类资源-CSDN下载

图片中各项资源链接:Desktop.rar-QT工具类资源-CSDN下载

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大桶矿泉水

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值