QT 新手小白USBCAN 学习

一、 介绍CAN总线

 CAN总线介绍

二、USBCAN总线

  2.1 产品介绍

        USBCAN 转换器模块实现了将 CAN 总线接口与 USB 接口进行相互转换。可以 简单方便的通过电脑监视 CAN 总线网络,同时可以实现工业现场数据稳定的双 向通信。模块广泛应用与工业控制、汽车电子、安防监控等领域的通信、控制、 数据传输。

       本模块是在电脑上将 USB 接口虚拟成串口设备实现通信,用户在电脑上只需 要掌握串口通信相关知识即可使用,具有使用方便、二次开发简单、稳定可靠等特点。

  2.2 接口说明

(1)MODE:将该跳线连接上,将强制产品进入设置模式

(2)RES:终端匹配电阻。将跳线连接上,则 CAN 总线接入 120 欧姆终端匹配电阻,跳线断开则没有终端匹配电阻接入。

(3) CAN_H 和 CAN_L:CAN 总线信号,和其他设备连接时 CAN_H 连 CAN_H 信号,CAN_L 连 CAN_L 信号,注意不能接反。 

(4)GND:模块内部地信号,非必须信号,如果线缆有屏蔽层,用户可自由选 择是否将该信号连接与屏蔽增连接。 

  2.3 包模式

         包模式下,串口处为固定 16byte 包长,数据不足部分补 0。这种模式下用户可以随意控制 CAN 总线上发出报文。串口处包格式说明:

 三、QT调用第三方库环境搭建

首先在QT工程中新建一个项目,并编译运行程序(在项目中把Shadow build去掉)把库函数文件都放在工作目录下。库函数文件总共有三个文件:ControlCAN.h、 ControlCAN.lib、ControlCAN.dll 和一个文件夹 kerneldlls。在.pro文件中加入

LIBS += -L$$PWD/./ ControlCAN.lib ControlCAN.dll

INCLUDEPATH += $$PWD\ControlCAN.h

 并在构造函数中添加 #include "ControlCAN.h"  #include<QDebug>头文件和测试

 1.选择32位

            2.去掉Shadow build

      3. 编译运行

 4. 将库放入把库函数文件都放在工作目录下

      5 .pro中添加环境变量 

                6 添加测试代码编译运行通过

                           7. 运行成功 (用的双头usbcan口同时插入电脑后编译通过)

四、USBCAN第三方库函数介绍

使用流程图

  整体流程分六个步骤:

1.打开设备  VCI_OpenDevice()

VCI_OpenDevice(DWORD DevType, DWORD DevIndex, DWORD Reserved);

2.初始化某一路  VCI_InitCAN()

VCI_InitCAN(DWORD DevType, DWORD DevIndex, DWORD CANIndex, PVCI_INIT_CONFIG pInitConfig);

3.启动某一路  VCI_StartCAN()

VCI_StartCAN(DWORD DevType, DWORD DevIndex, DWORD CANIndex);

4.读取CAN帧  VCI_Receive()

VCI_Receive(DWORD DevType, DWORD DevIndex, DWORD CANIndex, PVCI_CAN_OBJ pReceive, ULONG Len, INT WaitTime=-1);

5.发送CAN帧  VCI_Transmit()

VCI_Transmit(DWORD DevType, DWORD DevIndex, DWORD CANIndex, PVCI_CAN_OBJ pSend, ULONG Len);

6.关闭设备  VCI_CloseDevice()

 VCI_CloseDevice(DWORD DevType, DWORD DevIndex);

通用类型:

DevType

设备类型号。对应不同的产品型号。

DevIndex

设备索引号。比如当只有一个 PCIe-9221 时,索引号为 0,这时再插入一个 PCIe-9221

那么后面插入的这个设备索引号就是 1,以此类推。

CANIndex

第几路 CAN。即对应卡的 CAN 通道号,CAN0 0CAN1 1,以此类推。

详细看CAN API使用说明

5  QT下CAN总线代码编写思路

(代码质量很一般仅学习。)

mainwindow.h


#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "ControlCAN.h"
#include <QThread>
#include "recever.h"
#include"send_thread.h"
#include<QMutex>

#define DevType   4  // PCIe-9221
#define DevIndex  0 // 索引号0
#define CANIndex  0   //CAN0通道



QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow

{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();


    bool Start();

    void Stop();

    bool InitSerial();

    void setUI();

    void Close();

    void ResetCAN();

 signals:

   void receve();

   void Write(const QString &data,BYTE ,BYTE ,BYTE );

private slots:

    void on_btn_openConsole_clicked();

    void on_btn_openConsole_2_clicked();

    void on_btn_openConsole_3_clicked();

    void on_btn_recev_clicked();

    void Readdata(const QString &);

    void on_btn_send_clicked();

    void on_pushButton_3_clicked();

private:

    Ui::MainWindow *ui;

    bool IsRunning_ = false;


    recever *mrecever;

    send_thread *Send_thread;

    QThread mThread;

    QThread sendThread;

    DWORD REL;

    VCI_INIT_CONFIG Init;

    QMutex mutex;


};

#endif // MAINWINDOW_H

 recever.h

#ifndef RECEVER_H
#define RECEVER_H
#include <QObject>
#include "ControlCAN.h"
#define DevType   4  // PCIe-9221
#define DevIndex  0 // 索引号0
#define CANIndex  0   //CAN0通道

class recever: public QObject
{
    Q_OBJECT

public:
    explicit recever(QObject *parent = nullptr);

     void VCI_Rece();

    DWORD dwRel=false;

    bool CloseREL=false;

public slots:
   void readData();

signals:
    void SignalRead(const QString &);

private:
   DWORD ReceiveNum;
    VCI_CAN_OBJ Receive[100];

};

#endif // RECEVER_H

send_thread.h


#ifndef SEND_THREAD_H
#define SEND_THREAD_H
#include <QObject>
#include "ControlCAN.h"
#define DevType   4  // PCIe-9221
#define DevIndex  0 // 索引号0
#define CANIndex  0   //CAN0通道

class send_thread : public QObject
{
    Q_OBJECT
public:
    explicit send_thread(QObject *parent = nullptr);

     QByteArray  HexStringToByteArray(QString hex, bool *ok);
signals:

public slots:
      void SlotDoWrite(const QString &data,BYTE ,BYTE ,BYTE);

private:
    VCI_CAN_OBJ vco;
};

#endif // SEND_THREAD_H

mainwindow.c

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QMessageBox>

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

    setUI();
    mrecever = new recever;
    Send_thread = new send_thread;
    mrecever->moveToThread(&mThread);
    Send_thread->moveToThread(&sendThread);

    qRegisterMetaType<DWORD>("DWORD");

    qDebug()<< "main::SlotSessionDisConnected " << QThread::currentThreadId();
    connect(this,&MainWindow::receve,mrecever,&recever::readData);
    connect(mrecever,&recever::SignalRead,this,&MainWindow::Readdata,Qt::DirectConnection);
    connect(this,&MainWindow::Write,Send_thread,&send_thread::SlotDoWrite);

}

MainWindow::~MainWindow()
{
   // disconnect(this,&Widget::receve,mComservice,&ComService::readData);
    //disconnect(mComservice,&ComService::SignalRead,this,&Widget::Readdata);
    this->Close();
    mThread.quit();
    mThread.wait();
    sendThread.quit();
    sendThread.wait();
     delete mrecever;
    delete Send_thread;
    delete ui;
}


void MainWindow::setUI()
{
    setFixedHeight(446);
    setFixedWidth(544);
    ui->btn_recev->setEnabled(false);
    ui->btn_send->setEnabled(false);
    ui->btn_openConsole_2->setEnabled(false);
    ui->btn_openConsole_3->setEnabled(false);

    ui->comboBox->addItem("正常发送");
    ui->comboBox->addItem("单次发送");
    ui->comboBox->addItem("自发自收");
    ui->comboBox->addItem("单次自发自收");

    ui->comboBox_2->addItem("标准帧");
    ui->comboBox_2->addItem("扩展帧");

    ui->comboBox_3->addItem("数据帧");
    ui->comboBox_3->addItem("远程帧");

}

bool MainWindow::Start()
{
    if(IsRunning_)
        return true;
    mThread.start();
    sendThread.start();
    IsRunning_ = true;
    return true;

}

void MainWindow::Stop()
{
    if(!IsRunning_)
        return;
    mThread.quit();
    mThread.wait();
    sendThread.quit();
    sendThread.wait();
    IsRunning_=false;


}

bool MainWindow::InitSerial()
{
    mrecever->dwRel=false;
    mrecever->CloseREL=false;

    REL=VCI_OpenDevice(DevType,DevIndex,0);

    if(REL!= 1) return FALSE;  //打开设备

    Init.Timing0=0;
    Init.Timing1=0x1C;
    Init.Mode=0;
    Init.AccMask=0xFFFFFFFF;
    Init.Filter=1;

    if(VCI_InitCAN(DevType,DevIndex,CANIndex,&Init)!= 1) FALSE;      //初始化设备

    if(VCI_StartCAN(DevType,DevIndex,CANIndex)!=1)  FALSE ;          //运行设备

    return true;
}


void MainWindow::on_btn_openConsole_clicked()
{

    if(ui->btn_openConsole->text()==tr("打开CAN口"))
    {

        if(!Start())
            return;

        if(!InitSerial())
        {
            QMessageBox::information(this,"打开CAN口","CAN口打开失败");
            return;
        }
        QMessageBox::information(this,"打开CAN口","CAN口打开成功");

        if(!mrecever->dwRel||!mrecever->CloseREL)
        {
            mrecever->CloseREL=0;
            mrecever->dwRel=0;

            emit receve();

        }

        ui->btn_recev->setEnabled(false);
        ui->btn_send->setEnabled(true);
        ui->btn_openConsole_2->setEnabled(true);
        ui->btn_openConsole_3->setEnabled(true);
        ui->btn_openConsole->setEnabled(false);
    }


}


void MainWindow::on_btn_openConsole_2_clicked()
{
    // if(VCI_CloseDevice(DevType, DevIndex) != 1) qDebug()<<"error";

     Close();

    if(mrecever->CloseREL)
    {
        ui->btn_openConsole->setEnabled(true);
        ui->btn_openConsole_2->setEnabled(false);
        ui->btn_openConsole_3->setEnabled(false);
        ui->btn_send->setEnabled(false);
        ui->btn_recev->setEnabled(false);
        QMessageBox::information(this,"关闭CAN口","CAN口关闭成功");
        Stop();
    }

}


void MainWindow::Close()
{
    mutex.lock();
    qDebug()<< "SerialThreadsClose::SlotSessionDisConnected123 " << QThread::currentThreadId();
    if(!mrecever->CloseREL)
    {
    if(VCI_CloseDevice(DevType, DevIndex)==1)
    {
        qDebug()<<"CAN口关闭成功";
        mrecever->CloseREL=TRUE;
    }
    }

    mutex.unlock();
    // mutex.unlock();
}

void MainWindow::Readdata(const QString &temp)
{
    ui->textEdit_recv->append(temp.toLocal8Bit());
}

void MainWindow::on_btn_openConsole_3_clicked()
{
    ResetCAN();

    if(mrecever->dwRel)
    {
        ui->btn_recev->setEnabled(true);
    }
    qDebug()<<mrecever->dwRel;
}

void MainWindow::ResetCAN()
{
    mutex.lock();

    mrecever->dwRel= VCI_ResetCAN(DevType, DevIndex, CANIndex);

    if(mrecever->dwRel!=1) qDebug()<<"error";

    if(VCI_StartCAN(DevType, DevIndex, CANIndex)!=1) qDebug()<<"error";

    else  qDebug()<<"复位成功";

    mutex.unlock();
}


//接收
void MainWindow::on_btn_recev_clicked()
{

    qDebug()<<mrecever->dwRel<<mrecever->CloseREL;
    if(!mrecever->dwRel||!mrecever->CloseREL)
    {
        mrecever->CloseREL=0;
        mrecever->dwRel=0;
        emit receve();
        ui->btn_recev->setEnabled(false);
    }
    else qDebug()<<"接收中ing";
}

//发送





void MainWindow::on_btn_send_clicked()
{

        qRegisterMetaType<BYTE>("BYTE") ;
        BYTE SendType=0; BYTE RemoteFlag=0;  BYTE ExternFlag=0;

        if(ui->comboBox->currentText()=="正常发送")    SendType=0;
            if(ui->comboBox->currentText()=="单次发送")    SendType=1;
            if(ui->comboBox->currentText()=="自发自收")    SendType=2;
            if(ui->comboBox->currentText()=="单次自发自收") SendType=3;

            if(ui->comboBox_2->currentText()=="标准帧")    RemoteFlag=0;
            if(ui->comboBox_2->currentText()=="扩展帧")    RemoteFlag=1;

            if(ui->comboBox_3->currentText()=="数据帧")    ExternFlag=0;
            if(ui->comboBox_3->currentText()=="远程帧")    ExternFlag=1;

            qDebug()<<"扩展帧"<<SendType<<RemoteFlag<<ExternFlag;
            QString sendMsg = ui->textEdit_send->toPlainText();


            if(sendMsg.isEmpty())

            sendMsg="00 00 00 00 00 00 00 00";

            qDebug()<<"sendMsg"<<sendMsg;

             emit Write(sendMsg,SendType,RemoteFlag,ExternFlag);


}


void MainWindow::on_pushButton_3_clicked()
{
     ui->textEdit_recv->clear();
}

 recever.c


#include "recever.h"
#include <QDebug>
#include<QThread>
recever::recever(QObject *parent)
    : QObject{parent}
{

}


void recever::readData()
{
    BYTE num;
    qDebug() << "receve::SlotDoWrite threadID:"<< QThread::currentThreadId();

    while(1)
    {
        QThread::msleep(500);

        //qDebug()<<num;
        num=VCI_GetReceiveNum(DevType,DevIndex,CANIndex);
        qDebug()<<num;


        if(num)
        {
            VCI_Rece();
        }
        qDebug()<<dwRel<<dwRel;
        if(dwRel||CloseREL)
        {

            return;
        }

    }


}

void recever::VCI_Rece()
{
    qDebug()<< "VCI_Rece::SlotSessionDisConnected123 " << QThread::currentThreadId();

    QByteArray strData;
    strData.resize(8);

    ReceiveNum=  VCI_Receive(DevType,DevIndex,CANIndex,Receive,10,-1);
    qDebug()<<"ReceiveNum:"<<ReceiveNum;
    for (int i = 0; i < ReceiveNum; i++)
    {

        strData[0]  = Receive[i].Data[0];
        strData[1]  = Receive[i].Data[1];
        strData[2]  = Receive[i].Data[2];
        strData[3]  = Receive[i].Data[3];
        strData[4]  = Receive[i].Data[4];
        strData[5]  = Receive[i].Data[5];
        strData[6]  = Receive[i].Data[6];
        strData[7]  = Receive[i].Data[7];

        QString string_temp = (QString(strData.toHex(' ').toUpper().append(' ')));
        qDebug()<<ReceiveNum<<":data:"<<string_temp;
        emit SignalRead(string_temp);
        return;
    }
}

send_thread.c


#include "send_thread.h"
#include <QDataStream>
#include <QDebug>
#include<QThread>
#include<QtCore>

send_thread::send_thread(QObject *parent)
    : QObject{parent}
{

}

void send_thread::SlotDoWrite(const QString &data,BYTE SendType,BYTE RemoteFlag,BYTE ExternFlag)
{
    qDebug() << "write::SlotDoWrite threadID:"<< QThread::currentThreadId();

    vco.SendType = SendType; // 正常发送
    vco.RemoteFlag = RemoteFlag; // 数据帧
    vco.ExternFlag = ExternFlag; // 标准帧
    vco.DataLen = 8; // 数据长度1个字节


    bool ok;
    QByteArray buff=HexStringToByteArray(data, &ok);



   // QByteArray buff=HexStringToByteArray(data, &ok);
    qDebug()<<buff.toHex().toUpper();

    //QDataStream out(buff);


    vco.Data[0] = static_cast<unsigned char>(buff.at(0));
    vco.Data[1] = static_cast<unsigned char>(buff.at(1));
    vco.Data[2] = static_cast<unsigned char>(buff.at(2));
    vco.Data[3] = static_cast<unsigned char>(buff.at(3));
    vco.Data[4] = static_cast<unsigned char>(buff.at(4));
    vco.Data[5] = static_cast<unsigned char>(buff.at(5));
    vco.Data[6] = static_cast<unsigned char>(buff.at(6));
    vco.Data[7] = static_cast<unsigned char>(buff.at(7));

    if(VCI_Transmit(DevType,  DevIndex, CANIndex,&vco , 1)<0)   qDebug()<<"发送失败" ;

}


QByteArray send_thread:: HexStringToByteArray(QString hex, bool *ok)
{
    int p;

    QByteArray ret;
    QStringList lst = hex.simplified().split(' ');//转化为字符串数组
    ret.resize(lst.count());
    for(int i = 0; i < lst.count(); i++)
    {
        p = lst[i].toInt(ok, 16);
        if(!(*ok) || p > 255 )
        {
            return 0;
        }
        ret[i] = p;
    }
    return ret;
}

 最终效果图

猜你喜欢

转载自blog.csdn.net/m0_52467164/article/details/131186864