STM32CubeMX實現STM32 USBHID雙向64字節通信(Qt上位機部分)附源代碼

1.軟件界面

在這裏插入圖片描述

2.軟件功能

  • 自動搜尋usbhid設備並添加到下拉列表中
  • 64字節USBHID的發送功能
  • 10ms一次的定時查詢有無新的USBHID消息,並顯示出來

3.程序結構

在這裏插入圖片描述

4.程序代碼

Qt_USB-HID_timer.pro
#-------------------------------------------------
#
# Project created by QtCreator 2020-02-26T15:36:22
#
#-------------------------------------------------

QT       += core gui
QT       += serialport

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = Qt_USB-HID_demo
TEMPLATE = app

# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0


SOURCES += \
        main.cpp \
        mainwindow.cpp

HEADERS += \
        mainwindow.h

FORMS += \
        mainwindow.ui

LIBS += -L$$_PRO_FILE_PWD_/  -lhidapi

mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "hidapi.h"
#include <QDateTime>


namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    QByteArray HexStringToByteArray(QString HexString);
    QString ByteArrayToHexString(QByteArray data);
    void Receive_USBHID_message();

private slots:
    void on_pushButton_detectusb_clicked();

    void on_pushButton_usblock_clicked();

    void on_comboBox_usbhid_currentTextChanged();

    void on_pushButton_ClearSend_clicked();

    void on_pushButton_ClearReceive_clicked();

    void on_checkBox_HexReceive_clicked();

    void on_checkBox_HexSend_clicked();

    void on_pushButton_HIDSend_clicked();

private:
    Ui::MainWindow *ui;
    /*usbhid*/
    hid_device *handle;
    unsigned short vendor_id;
    unsigned short product_id;
    bool USBHID_Rev_Enable;
    unsigned char usb_data[65];
};

#endif // MAINWINDOW_H

main.cpp
#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.setWindowTitle("USB-HID 發送與接收64Byte");
    w.show();

    return a.exec();
}

mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QMessageBox>
#include <QTimer>


using namespace std;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->pushButton_HIDSend->setEnabled(false);
    ui->checkBox_HexReceive->setCheckState(Qt::Checked);
    ui->checkBox_HexSend->setCheckState(Qt::Checked);
    ui->checkBox_HexReceive->setEnabled(false);

    USBHID_Rev_Enable = false;

    QTimer *timer1 = new QTimer(this);
    connect(timer1, &QTimer::timeout, this, &MainWindow::Receive_USBHID_message);
    timer1->start(10);
}

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

void MainWindow::on_pushButton_detectusb_clicked()
{
    hid_init();
    struct hid_device_info * P_device;

    P_device = hid_enumerate(0, 0);

    //清空usbhid設備框
    ui->comboBox_usbhid->clear();

    if(P_device != NULL)
        statusBar()->showMessage("檢測到USBHID設備",3000);

    while(P_device != NULL)
    {
        ui->comboBox_usbhid->addItem(QString::fromWCharArray(P_device->product_string));
        P_device = P_device->next;
    }

    hid_free_enumeration(P_device);
    hid_exit();
}

void MainWindow::on_pushButton_usblock_clicked()
{
    char s[100];

    if(ui->pushButton_usblock->text()==QString("打開"))
    {
        hid_init();
        struct hid_device_info * P_device;

        P_device = hid_enumerate(0, 0);
        while(P_device != NULL)
        {
            if((ui->comboBox_usbhid->currentText()) == (QString::fromWCharArray(P_device->product_string)))
            {
                this->vendor_id = P_device->vendor_id;
                this->product_id = P_device->product_id;
                break;
            }
            P_device = P_device->next;
        }

        //已經獲得選中項的vid&pid,釋放設備鏈表
        hid_free_enumeration(P_device);

        this->handle = hid_open(this->vendor_id , this->product_id, NULL);

        if(NULL != this->handle)
        {
            USBHID_Rev_Enable = true;
            qDebug("成功打開vid=0x%04x,pid=0x%04x 的usbhid設備!", this->vendor_id, this->product_id);
            sprintf(s,"成功打開vid=0x%04x,pid=0x%04x 的usbhid設備!", this->vendor_id, this->product_id);
            statusBar()->showMessage(QString(s),3000);
            ui->pushButton_usblock->setText(QString("關閉"));      //usb進入打開狀態

            //在界面顯示vid和pid
            char s[40];
            sprintf(s,"VID:0x%04X", this->vendor_id);
            QString vid_str = s;
            ui->label_vid->setText(vid_str);
            sprintf(s,"PID:0x%04X", this->product_id);
            QString pid_str = s;
            ui->label_pid->setText(pid_str);

            //以下控件失效
            ui->pushButton_detectusb->setEnabled(false);
            ui->comboBox_usbhid->setEnabled(false);
            //以下控件使能
            ui->pushButton_HIDSend->setEnabled(true);
        }else
        {
            qDebug("打開vid=0x%04x,pid=0x%04x 的usbhid設備失敗!", this->vendor_id, this->product_id);
            sprintf(s,"打開vid=0x%04x,pid=0x%04x 的usbhid設備失敗!", this->vendor_id, this->product_id);
            statusBar()->showMessage(QString(s),3000);
            return;
        }
    }
    else
    {
        hid_close(this->handle);
        USBHID_Rev_Enable = false;
        qDebug("成功關閉vid=0x%04x,pid=0x%04x 的usbhid設備!", this->vendor_id, this->product_id);
        sprintf(s,"成功關閉vid=0x%04x,pid=0x%04x 的usbhid設備!", this->vendor_id, this->product_id);
        statusBar()->showMessage(QString(s),3000);

        hid_exit();
        ui->pushButton_usblock->setText(QString("打開"));      //usb進入關閉狀態

        QString vid_str = "VID:";
        QString pid_str = "PID:";
        ui->label_vid->setText(vid_str);
        ui->label_pid->setText(pid_str);

        //以下控件使能
        ui->pushButton_detectusb->setEnabled(true);
        ui->comboBox_usbhid->setEnabled(true);
        //以下控件失效
        ui->pushButton_HIDSend->setEnabled(false);
    }
}

void MainWindow::on_comboBox_usbhid_currentTextChanged()
{
    hid_init();
    struct hid_device_info * P_device;

    P_device = hid_enumerate(0, 0);
    while(P_device != NULL)
    {
        if((ui->comboBox_usbhid->currentText()) == (QString::fromWCharArray(P_device->product_string)))
        {
            this->vendor_id = P_device->vendor_id;
            this->product_id = P_device->product_id;
            break;
        }
        P_device = P_device->next;
    }

    //已經獲得選中項的vid&pid,釋放設備鏈表
    hid_free_enumeration(P_device);

    char s[100];
    sprintf(s,"VID:0x%04X", this->vendor_id);
    QString vid_str = s;
    ui->label_vid->setText(vid_str);
    sprintf(s,"PID:0x%04X", this->product_id);
    QString pid_str = s;
    ui->label_pid->setText(pid_str);

    sprintf(s,"設備屬性:vid=0x%04x,pid=0x%04x", this->vendor_id, this->product_id);
    statusBar()->showMessage(QString(s),3000);
}

void MainWindow::on_pushButton_ClearSend_clicked()
{
    ui->textEdit_send->clear();
    statusBar()->showMessage("清空發送區成功",3000);
}

void MainWindow::on_pushButton_ClearReceive_clicked()
{
    ui->textEdit_receive->clear();
    statusBar()->showMessage("清空接收區成功",3000);
}

void MainWindow::on_checkBox_HexReceive_clicked()
{
    if(ui->checkBox_HexReceive->isChecked()==true)
    {
        qDebug("以16進制顯示");
        statusBar()->showMessage("以16進制顯示",3000);
    }else if(ui->checkBox_HexReceive->isChecked()==false)
    {
        qDebug("取消以16進制顯示");
        statusBar()->showMessage("取消以16進制顯示",3000);
    }
}

void MainWindow::on_checkBox_HexSend_clicked()
{
    if(ui->checkBox_HexSend->isChecked()==true)
    {
        qDebug("以16進制發送");
        statusBar()->showMessage("以16進制發送",3000);
    }else if(ui->checkBox_HexSend->isChecked()==false)
    {
        qDebug("取消以16進制發送");
        statusBar()->showMessage("取消以16進制發送",3000);
    }
}

/*
 * @breif 將16進制字符串轉換爲對應的字節序列
 */
QByteArray MainWindow::HexStringToByteArray(QString HexString)
{
    bool ok;
    QByteArray ret;
    HexString = HexString.trimmed();
    HexString = HexString.simplified();
    QStringList sl = HexString.split(" ");

    foreach (QString s, sl) {
        if(!s.isEmpty())
        {
            char c = s.toInt(&ok,16)&0xFF;
            if(ok){
                ret.append(c);
            }else{
                qDebug()<<"非法的16進制字符:"<<s;
                QMessageBox::warning(0,tr("錯誤:"),QString("非法的16進制字符: \"%1\"").arg(s));
            }
        }
    }
    //qDebug()<<ret;
    return ret;
}

/*
 * @breif 將字節序列轉換爲對應的16進制字符串
 */
QString MainWindow::ByteArrayToHexString(QByteArray data){
    QString ret(data.toHex().toUpper());
    int len = ret.length()/2;
    qDebug()<<len;
    for(int i=1;i<len;i++)
    {
        //qDebug()<<i;
        ret.insert(2*i+i-1," ");
    }

    return ret;
}

void MainWindow::Receive_USBHID_message()
{

    if(USBHID_Rev_Enable)
    {
        int res = hid_read_timeout(this->handle, usb_data, 64, 1);

        if(res>0)
        {
            QDateTime time = QDateTime::currentDateTime();
            QString time_qstr = time.toString("yyyy-MM-dd hh:mm:ss");

            QString qstr = "接收時間:"+time_qstr+"\r\n----------------------\r\n";


            for(int i=0; i<64; i++)
            {
                qstr += QString(QByteArray((char *)&usb_data[i],1).toHex()).toUpper();
                qstr += " ";
            }

            qstr = qstr + "\r\n\r\n" + ui->textEdit_receive->toPlainText() ;
            ui->textEdit_receive->setText(qstr);
            statusBar()->showMessage("USBHID收到新數據! "+time_qstr,3000);
        }
    }
}

void MainWindow::on_pushButton_HIDSend_clicked()
{
    unsigned char usb_data[65];
    char s[100];

    //獲取界面上的數據並轉換成utf8格式的字節流
    QString sendMsg = ui->textEdit_send->toPlainText();
    QByteArray data = sendMsg.toLatin1();

    //如果以16進制發送
    if(ui->checkBox_HexSend->isChecked() == true)
    {
        data = HexStringToByteArray(sendMsg);
    }

    for(int i=1; i<65; i++)
    {
        if(i<data.length()+1)
            usb_data[i]=data.data()[i-1];
        else
            usb_data[i]=0xff;
    }

    int res = hid_write(this->handle, usb_data, 65);    //至少寫入64字節,協議64字節,第一個字節作廢

    qDebug("寫入結果res = %d", res);
    if(-1 == res)
    {
        qDebug("USBHID寫入字節錯誤!");
        statusBar()->showMessage("USBHID寫入字節錯誤!",3000);
        return;
    }
    else
    {
        qDebug("USBHID寫入成功,實際寫入了 %d 個字節!", res-1);
        sprintf(s,"USBHID寫入成功,實際寫入了 %d 個字節!", res-1);
        statusBar()->showMessage(QString(s),3000);
    }
}

相關鏈接:
1.STM32CubeMX實現STM32 USBHID雙向64字節通信(下位機部分)
2.STM32CubeMX實現STM32 USBHID雙向64字節通信(下位機部分)源代碼
3.Qt_USB-HID_timer 源代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章