PCAN的使用简单demo
参考 PCAN示例资源文件介绍:PCAN示例资源文件介绍 - GitCode
安装驱动 https://www.peak-system.com/produktcd/Drivers/PeakOemDrv.exe
无脑下一步就行
此处就是界面上添加了一个 按钮,用于创建连接,界面代码自己简单做一个
pro中添加 serialbus
QT += serialbus
.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QCanBusDevice> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; //std::unique_ptr<QCanBusDevice> m_canDevice; QCanBusDevice *m_canDevice=nullptr; QList<QCanBusDeviceInfo> m_interfaces; short tacomathrottle; short tacomasteer; short tacomaspeed; bool tacomabrake; private slots: void processReceivedFrames(); void processErrors(QCanBusDevice::CanBusError) const; void canconnectclicked(); }; #endif // MAINWINDOW_H
.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | #include "mainwindow.h" #include "ui_mainwindow.h" #include <QCanBus> #include <QDebug> #include <QCanBusFrame> #include <QTimer> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui( new Ui::MainWindow) { ui->setupUi( this ); connect(ui->canBT,&QPushButton::clicked, this ,&MainWindow::canconnectclicked); } MainWindow::~MainWindow() { delete ui; } void MainWindow::processErrors(QCanBusDevice::CanBusError error) const { switch (error) { case QCanBusDevice::ReadError: case QCanBusDevice::WriteError: case QCanBusDevice::ConnectionError: case QCanBusDevice::ConfigurationError: case QCanBusDevice::UnknownError: qDebug()<<m_canDevice->errorString(); break ; default : break ; } } void MainWindow::processReceivedFrames() { if (!m_canDevice) return ; while (m_canDevice->framesAvailable()) { const QCanBusFrame frame = m_canDevice->readFrame(); //qDebug()<<frame.error(); // qDebug()<<frame.frameId();//frame id,it's decimal //qDebug()<<frame.frameType();//1 means dataframe //qDebug()<<m_canDevice->state(); QString view; if (frame.frameType() == QCanBusFrame::ErrorFrame) { view = m_canDevice->interpretErrorFrame(frame); } else if (frame.frameType()==QCanBusFrame::DataFrame) { view=frame.toString(); } qDebug()<<view; } } void MainWindow::canconnectclicked() { //QCanBus::instance()->plugins(); const QString plugin= "peakcan" ; int bitrate=500000; bitrate=125000; bool connectflag= false ; QString errorString; //const QString plugin="virtualcan"; // qDebug()<< QCanBus::instance()->plugins(); m_interfaces = QCanBus::instance()->availableDevices(plugin); if (!m_interfaces.empty()) { qDebug()<<m_interfaces.begin()->name(); m_canDevice=QCanBus::instance()->createDevice(plugin, m_interfaces.begin()->name(), &errorString); } else { qDebug()<< "do not find available interface for pcan" ; } if (!m_canDevice) { qDebug() << "createDevice error" <<errorString; } else { /***peakcan do not support configuration key RawFilterKey***/ // QCanBusDevice::Filter filter; // QList<QCanBusDevice::Filter> filterList; // // filter all CAN bus packages with id 0x444 (base) or 0xXXXXX444 (extended) // filter.frameId = 0x444u; // qDebug()<<filter.frameId; // filter.frameIdMask = 0x0u; // filter.format = QCanBusDevice::Filter::MatchBaseFormat; // filter.type = QCanBusFrame::DataFrame; // filterList.append(filter); // m_canDevice->setConfigurationParameter(QCanBusDevice::RawFilterKey, QVariant::fromValue(filterList)); m_canDevice->setConfigurationParameter(QCanBusDevice::BitRateKey,QVariant(bitrate)); connectflag= m_canDevice->connectDevice(); qDebug()<< "connecflag" <<connectflag; } if (connectflag) { connect(m_canDevice, &QCanBusDevice::errorOccurred, this , &MainWindow::processErrors); connect(m_canDevice, &QCanBusDevice::framesReceived, this , &MainWindow::processReceivedFrames); ui->canBT->setEnabled( false ); // writeFrame QTimer *mytimer= new QTimer() ; connect(mytimer,&QTimer::timeout, this ,[=](){ QCanBusFrame frame; frame.setFrameId(0x123); // 设置CAN ID QByteArray payload; payload.append(0x01); // 设置要发送的数据 payload.append(0x02); payload.append(0x03); payload.append(0x04); payload.append(0x05); payload.append(0x06); payload.append(0x07); payload.append(0x08); frame.setFrameType(QCanBusFrame::DataFrame); // frame.setExtendedFrameFormat(false); frame.setExtendedFrameFormat( true ); frame.setPayload(payload); // 设置帧数据 m_canDevice->writeFrame(frame); }); mytimer->start(1000); } } |
连线图 参考 https://zhuanlan.zhihu.com/p/420285500
自己封装的接口
canlib.h
#ifndef CANLIB_H #define CANLIB_H #include <QCanBusDevice> #include <QStringList> #include <QTimer> #include <QtCore> #include <QMutex> #include<windows.h> //修改日志 //20211103-1050 将传统单线程接收修改为多线程+锁的方式,目前测试无问题 锁使用 QMutexLocker locker(&mutex); 这个利用构造析构来加锁解锁,更安全.其实此处如何使用,无所谓 class Q_DECL_EXPORT CANLib : public QThread { Q_OBJECT public: CANLib(); void run(); ~CANLib(); QStringList getUSBCANList();//得到当前 USBCAN list int openUSBCAN(int DevIndex, int channelIndex, int baudRate);//设置波特率 默认数据8位,无流控 无校验 1位停止位 void closeUSBCAN();//关闭串口 int sendInfo(QStringList list,int interval = 5);//发送数据 int sendInfo(QString info); int canStatus();// signals: void sigReceivedInfo(QString tem); void sigCANStateInfo(QString tem); private: void _my_msleepByCPU(double mSleepTime);//设置ms延时 void _my_usleepByCPU(double uSleepTime);//设置微秒延时 QCanBusDevice *m_canDevice=nullptr; int openedUSBCAN = -1; //打开的设备编号 int openedChannel = -1; //已经打开的channel,在打开按钮处赋值 int openedBaudRate = -1; //记录当前使用的波特率,点击不同的波特率时候 需要关闭之前的通讯 0 125k 1 250k QCanBusFrame candata[1024]; //缓存,用于接受数据 QCanBusFrame sendData[1024]; //缓存,用于发送数据 QTimer *timerReadData; //用于定时读取设备数据//建议40ms一次或者100ms一次 int startFlag = 0; //开启关闭标志,不使用terminal QMutex mutex; }; #endif // CANLIB_H
canlib.cpp
#include "canlib.h" #include <QTimer> #include <QDebug> #include <QMap> #include <QDateTime> #include <QTime> #include <QList> #include <QCanBus> #include <QTimer> #include <QCanBusFrame> #define myDebugMsg(msg) qDebug()<<QString("[Debug] Time:%0 File:%1 Line:%2 Function:%3 Msg:%4").arg(QTime::currentTime().toString("hh:mm:ss.zzz")).arg(__FILE__).arg(__LINE__).arg(__FUNCTION__).arg(msg); #define myDebugNum(msg) qDebug()<<QString("[Debug] Time:%0 File:%1 Line:%2 Function:%3 Msg:%4").arg(QTime::currentTime().toString("hh:mm:ss.zzz")).arg(__FILE__).arg(__LINE__).arg(__FUNCTION__).arg(QString::number(msg)); #define myDebugInfo(msg) qDebug()<<msg; #define myDebug qDebug()<<QString("[Debug] Time:%0 File:%1 Line:%2 Function:%3").arg(QTime::currentTime().toString("hh:mm:ss.zzz")).arg(__FILE__).arg(__LINE__).arg(__FUNCTION__); #define opendebuginfosend 0 //#define opendebuginforecv 1 #include <QCoreApplication> CANLib::CANLib() : QThread() { startFlag=1; //初始化时,定义好变量//计划每毫秒读取一次缓存 timerReadData = new QTimer(this); timerReadData->setTimerType(Qt::PreciseTimer); connect(timerReadData,&QTimer::timeout,this,[=]() mutable{ // }); } void CANLib::run() { while (startFlag==1) { Sleep(1000); //_my_usleepByCPU(1000);//延时1ms // if(openedUSBCAN<0 || openedChannel<0)continue; // int recvnum = VCI_GetReceiveNum(VCI_USBCAN2,openedUSBCAN,openedChannel); // QString res = ""; // int ret = 0; // if(recvnum>=1023)recvnum = 1023; // { // QMutexLocker locker(&mutex); // ret = VCI_Receive(VCI_USBCAN2,openedUSBCAN,openedChannel,candata,1023); // } //// mutex.lock(); //// ret = VCI_Receive(VCI_USBCAN2,openedUSBCAN,openedChannel,candata,1023); //// mutex.unlock(); // if(ret != 0xffffffff){ // //遍历数据,并调用显示数据显示结果 // for(int i=0;i<ret;i++){ // //emit ... // res = "00000000"+QString::number(candata[i].ID,16); // if(candata[i].ExternFlag==0){ // res = res.right(3)+":"; // } // else{ // res = res.right(8)+":"; // } // for(int j=0;j<candata[i].DataLen;j++){ // int a = candata[i].Data[j]; // res += QString("00"+QString::number(a,16)).right(2); // } //#ifdef opendebuginforecv // myDebugMsg(res.toUpper()); //#endif // emit sigReceivedInfo(res.toUpper()); // } // } } } CANLib::~CANLib() { closeUSBCAN(); timerReadData->deleteLater(); } QStringList CANLib::getUSBCANList() { QStringList list; // int devNum = VCI_ScanDevice(1); // for(int i=0;i<devNum;i++){ list.append(QString("USBCAN %1").arg(i));} list.append(QString("USBCAN0")); return list; } int CANLib::canStatus() { if(m_canDevice==nullptr){return -1;} if(m_canDevice->state()!=QCanBusDevice::CanBusDeviceState::ConnectedState){return -1;} return 1; } int CANLib::openUSBCAN(int DevIndex, int channelIndex, int baudRate) { // const QString plugin="virtualcan"; // qDebug()<< QCanBus::instance()->plugins(); const QString plugin="peakcan"; const int bitrate=baudRate*1000; bool connectflag=false; QString errorString; // QList<QCanBusDeviceInfo> m_interfaces; QList<QCanBusDeviceInfo> m_interfaces = QCanBus::instance()->availableDevices(plugin); if(!m_interfaces.empty()){ qDebug()<<m_interfaces.begin()->name(); m_canDevice=QCanBus::instance()->createDevice(plugin, m_interfaces.begin()->name(), &errorString); } else{ qDebug()<<"do not find available interface for pcan"; return -1; } if (!m_canDevice) { qDebug() <<"createDevice error" <<errorString; return -2; } else { /***peakcan do not support configuration key RawFilterKey***/ // QCanBusDevice::Filter filter; // QList<QCanBusDevice::Filter> filterList; // // filter all CAN bus packages with id 0x444 (base) or 0xXXXXX444 (extended) // filter.frameId = 0x444u; // qDebug()<<filter.frameId; // filter.frameIdMask = 0x0u; // filter.format = QCanBusDevice::Filter::MatchBaseFormat; // filter.type = QCanBusFrame::DataFrame; // filterList.append(filter); // m_canDevice->setConfigurationParameter(QCanBusDevice::RawFilterKey, QVariant::fromValue(filterList)); m_canDevice->setConfigurationParameter(QCanBusDevice::BitRateKey,QVariant(bitrate)); connectflag= m_canDevice->connectDevice(); qDebug()<<"connecflag"<<connectflag; } if(connectflag){ connect(m_canDevice, &QCanBusDevice::errorOccurred,this, [=](QCanBusDevice::CanBusError error) mutable{ switch (error) { // case QCanBusDevice::ReadError: // case QCanBusDevice::WriteError: case QCanBusDevice::ConnectionError: case QCanBusDevice::ConfigurationError: case QCanBusDevice::UnknownError: // case QCanBusDevice::OperationError: // case QCanBusDevice::TimeoutError: // qDebug()<<m_canDevice->errorString(); // emit sigCANStateInfo("closed"); closeUSBCAN(); break; default: break; } }); connect(m_canDevice, &QCanBusDevice::framesReceived,this, [=]() mutable{ if (!m_canDevice){return;} while (m_canDevice->framesAvailable()){ QCanBusFrame frame = m_canDevice->readFrame(); //qDebug()<<frame.error(); //qDebug()<<frame.frameId();//frame id,it's decimal //qDebug()<<frame.frameType();//1 means dataframe //qDebug()<<m_canDevice->state(); QString view; if (frame.frameType() == QCanBusFrame::ErrorFrame){ view = m_canDevice->interpretErrorFrame(frame); } else if(frame.frameType()==QCanBusFrame::DataFrame){ view=frame.toString(); QString hexString=""; if(frame.hasExtendedFrameFormat()){ hexString = QString::number(frame.frameId(), 16).toUpper().rightJustified(8, '0'); } else{ hexString = QString::number(frame.frameId(), 16).toUpper().rightJustified(3, '0'); } hexString+=":"; hexString+=frame.payload().toHex().toUpper(); emit sigReceivedInfo(hexString); // for (int j=0;j<Message[i].LEN;j++) { // hexString+=QString::number(Message[i].DATA[j], 16).toUpper().rightJustified(2, '0'); // } } //qDebug()<<view; } }); // this->start(); return 1; } return -3; } void CANLib::closeUSBCAN() { // startFlag = 0; // //timerReadData->stop(); // if(openedChannel>=0)VCI_ResetCAN(VCI_USBCAN2,openedUSBCAN,openedChannel); // else{ return; } // VCI_CloseDevice(VCI_USBCAN2,openedUSBCAN); // openedChannel = -1; // openedUSBCAN = -1; // openedBaudRate = -1; if(m_canDevice!=nullptr){ m_canDevice->disconnectDevice(); delete m_canDevice; m_canDevice=nullptr; emit sigCANStateInfo("closed"); } } int CANLib::sendInfo(QStringList list, int interval) { if(openedChannel<0)return -1; int len = list.size(); int all=0; for(int i=0;i<len;i++){ int res=sendInfo(list.at(i)); if(res==1){all+=1;} if(interval>0){ QCoreApplication::processEvents(QEventLoop::AllEvents); Sleep(interval); } } return all; // if(interval>0){ // for(int i=0;i<len;i++){ // sendInfo(list.at(i)); // QCoreApplication::processEvents(QEventLoop::AllEvents); // Sleep(interval); // } // } // else{ // for(int i=0;i<len;i++){ // QStringList li = list.at(i).split(":"); // sendData[i].ID = li[0].toUInt(Q_NULLPTR,16); // sendData[i].SendType = 0; // sendData[i].RemoteFlag = 0; // sendData[i].ExternFlag = 0; // for(int i=0;i<li[1].length()/2;i++){ // sendData[i].Data[i] = li[1].mid(2*i,2).toUInt(Q_NULLPTR,16); // } // sendData[i].DataLen = li[1].length()/2; // } // int sendCount = 0; // { // QMutexLocker locker(&mutex); // sendCount = VCI_Transmit(VCI_USBCAN2,openedUSBCAN,openedChannel,sendData,len); // } //// mutex.lock(); //// sendCount = VCI_Transmit(VCI_USBCAN2,openedUSBCAN,openedChannel,sendData,len); //// mutex.unlock(); // if(sendCount!=len){ return -1;} // else{return 1;} // } // return 1; } int CANLib::sendInfo(QString info) { #ifdef opendebuginfosend myDebugMsg(info); #endif //if(openedChannel<0)return -1; //数据格式 001:3132333435363738 if(info.contains(":")==false){return -1;} if(m_canDevice==nullptr){return -1;} if(m_canDevice->state()!=QCanBusDevice::CanBusDeviceState::ConnectedState){return -1;} QStringList li = info.split(":"); QCanBusFrame frame; frame.setFrameId(li[0].toUInt(nullptr,16)); if(frame.frameId()>0x7ff||li[0].length()>3){frame.setExtendedFrameFormat(true);} else{frame.setExtendedFrameFormat(false);} QByteArray arr; for(int i=0;i<li[1].length()/2;i++){ arr.append(li[1].mid(2*i,2).toUInt(nullptr,16)); } frame.setPayload(arr); //qDebug() <<"frame send:" <<frame.toString(); //qDebug() <<"m_canDevice->busStatus():" <<m_canDevice->busStatus(); //qDebug() <<"m_canDevice->state():" <<m_canDevice->state(); return m_canDevice->writeFrame(frame); } // 精确延时毫秒 void CANLib::_my_msleepByCPU(double mSleepTime) { LARGE_INTEGER litmp; LONGLONG Qpart1,Qpart2; double dfMinus = 0,dfFreq = 0,dfTime = 0;//不初始化是一个不好的习惯,而且会有bug //获得CPU计时器的时钟频率 QueryPerformanceFrequency(&litmp);//取得高精度运行计数器的频率f,单位是每秒多少次(n/s), dfFreq = (double)litmp.QuadPart; QueryPerformanceCounter(&litmp);//取得高精度运行计数器的数值 Qpart1 = litmp.QuadPart; //开始计时 while((mSleepTime-dfTime*1000.000)>0.0000001){ QueryPerformanceCounter(&litmp);//取得高精度运行计数器的数值 Qpart2 = litmp.QuadPart; //终止计时 dfMinus = (double)(Qpart2 - Qpart1);//计算计数器值 dfTime = dfMinus / dfFreq;//获得对应时间,单位为秒,可以乘1000000精确到微秒级(us) // qDebug()<<"ms"<<QString::number(dfTime*1000.00,'f',9); } } void CANLib::_my_usleepByCPU(double uSleepTime) { LARGE_INTEGER litmp; LONGLONG Qpart1,Qpart2; double dfMinus = 0,dfFreq = 0,dfTime = 0;//不初始化是一个不好的习惯,而且会有bug //获得CPU计时器的时钟频率 QueryPerformanceFrequency(&litmp);//取得高精度运行计数器的频率f,单位是每秒多少次(n/s), dfFreq = (double)litmp.QuadPart; QueryPerformanceCounter(&litmp);//取得高精度运行计数器的数值 Qpart1 = litmp.QuadPart; //开始计时 while((uSleepTime-dfTime*1000000.000)>0.0000001){ QueryPerformanceCounter(&litmp);//取得高精度运行计数器的数值 Qpart2 = litmp.QuadPart; //终止计时 dfMinus = (double)(Qpart2 - Qpart1);//计算计数器值 dfTime = dfMinus / dfFreq;//获得对应时间,单位为秒,可以乘1000000精确到微秒级(us) // qDebug()<<"us"<<QString::number(dfTime*1000000.00,'f',9); } }
使用
// can toolCANLib = new CANLib(); connect(toolCANLib, &CANLib::sigReceivedInfo,this,&MainWindow::receivedInfoAll); connect(toolCANLib, &CANLib::sigCANStateInfo,this,[=](QString cmd){ if(cmd=="closed"){ ui->btn_conn_close->setEnabled(false); ui->btn_conn_open->setEnabled(true); update_set_state("通讯关闭",-1); } }); // 按钮打开关闭 connect(ui->btn_conn_open, &QPushButton::clicked,this,[=](){ ui->stackedWidget->setEnabled(false); toolCANLib->closeUSBCAN(); QCoreApplication::processEvents(QEventLoop::AllEvents); str_data_version="";//软件版本清空,打开通讯就重读 int baudRate=0; if(ui->data_conn_baud->currentText().toUpper().contains("125K")){baudRate = 125;} else if(ui->data_conn_baud->currentText().toUpper().contains("250K")){baudRate = 250;} else if(ui->data_conn_baud->currentText().toUpper().contains("500K")){baudRate = 500;} else if(ui->data_conn_baud->currentText().toUpper().contains("800K")){baudRate = 800;} else if(ui->data_conn_baud->currentText().toUpper().contains("1M")){baudRate = 1000;} else{ui->stackedWidget->setEnabled(true);return ;} int res = toolCANLib->openUSBCAN(0,0,baudRate); if(res<0){ toolCANLib->closeUSBCAN(); } else { ui->btn_conn_open->setEnabled(false); ui->btn_conn_close->setEnabled(true); ui->btn_conn_open->setStyleSheet(""); ui->btn_conn_close->setStyleSheet("background-color: green;"); update_set_state("通讯打开成功"); } ui->stackedWidget->setEnabled(true); }); connect(ui->btn_conn_close, &QPushButton::clicked,this,[=](){ ui->btn_conn_close->setEnabled(false); ui->btn_conn_open->setEnabled(true); ui->btn_conn_close->setStyleSheet(""); ui->btn_conn_open->setStyleSheet("background-color: green;"); update_set_state("通讯关闭",-1); toolCANLib->closeUSBCAN(); }); ui->btn_conn_close->click();
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
2021-11-22 qt 使用CRUD方式操作excel