1. CANバスの概要
2.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 パッケージモード
パケット モードでは、シリアル ポートのパケット長は 16 バイトに固定されており、欠落したデータは 0 で埋められます。このモードでは、ユーザーは CAN バス上で送信されるメッセージを自由に制御できます。シリアルポートのパケットフォーマットの説明:
3. QT はサードパーティのライブラリ環境を呼び出して構築します
まず、QT プロジェクト内に新しいプロジェクトを作成し、プログラムをコンパイルして実行し (プロジェクト内のシャドウ ビルドを削除します)、すべてのライブラリ関数ファイルを作業ディレクトリに配置します。ライブラリ関数ファイルには、ControlCAN.h、ControlCAN.lib、ControlCAN.dllおよびフォルダーkerneldllsの合計 3 つのファイルがあります。.pro ファイルに追加
LIBS += -L$$PWD/./ ControlCAN.lib ControlCAN.dll
INCLUDEPATH += $$PWD\ControlCAN.h
#include "ControlCAN.h" #include<QDebug> ヘッダー ファイルを追加し、コンストラクターでテストします。
1. 32ビットを選択します
2.シャドウビルドを削除する
3. コンパイルして実行する
4. ライブラリを配置し、すべてのライブラリ関数ファイルを作業ディレクトリに配置します。
5.proに環境変数を追加する
6. テストコードを追加し、コンパイルして実行し、合格します。
7. 操作は成功しました (使用されたデュアルヘッド USBCAN ポートが同時にコンピューターに挿入され、コンパイルされて渡されました)
4. USBCAN サードパーティ ライブラリ関数の概要
フローチャートを使用する
全体的なプロセスは 6 つのステップに分かれています。
1. デバイスを開きます VCI_OpenDevice()
VCI_OpenDevice (DWORD DevType、DWORD DevIndex、DWORD 予約済み);
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);
一般的なタイプ:
開発タイプ
デバイスのタイプ番号。さまざまな製品モデルに対応します。
開発インデックス
デバイスのインデックス番号。たとえば、 PCIe-9221 が1 つだけある場合、インデックス番号は0であり、別のPCIe-9221を挿入します。
その後、後で挿入されたデバイスのインデックス番号は1 、というように続きます。
CANIdex
どのCANチャネルですか? つまり、カードのCANチャネル番号に対応して、 CAN0は0 、CAN1は1などとなります。
詳細については、CAN API の使用手順を参照してください。
QT で CAN バス コードを記述するための 5 つのアイデア
(コードの品質は学習用としては非常に平均的です。)
メインウィンドウ.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
受信する.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
メインウィンドウ.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();
}
受信.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;
}
最終レンダリング