本文将自己的QT+VS2020环境的PCAN上位机开发分享给技术爱好者。
一、使用介绍
PCANBasic开发包包好了的几个主要文件说明:
PCANBasic.h:为接口头文件,定义了PCAN操作的一些指令和接口说明;
PCANBasic.dll:动态库文件;
PCANBasic.lib:静态库文件;
二、上位机界面
配置界面
配置完成界面
以上上位机界面由于是标准化界面,因此默认显示两个CAN端口,实际PCAN只有1个CAN端口,数据会在CAN0上显示
数据接收显示
以上界面支持查看详细信息,和历史数据导出。
三、关键驱动代码
驱动加载分为静态加载和动态加载:本文按照静态加载方式设计,如果有需要动态加载的可以看本人的资源中可以下载资源,里面的案例即通过动态加载DLL文件,并通过名字获取接口操作指针的。
程序目录如下,其中箭头所指为PCAN关键所在:
1、扫描PCAN设备:
void PcanMathod::Pcan_Seach()
{
TPCANChannelInformation* info;
TPCANStatus ret;
DWORD pcan_ChannelsCount;
ret = CAN_GetValue(PCAN_NONEBUS, PCAN_ATTACHED_CHANNELS_COUNT, (void*)&pcan_ChannelsCount, sizeof(pcan_ChannelsCount));
if (ret == PCAN_ERROR_OK)
{
info = new TPCANChannelInformation[pcan_ChannelsCount];
ret = CAN_GetValue(PCAN_NONEBUS, PCAN_ATTACHED_CHANNELS, (void*)info, pcan_ChannelsCount * sizeof(TPCANChannelInformation));
if (ret == PCAN_ERROR_OK)
// Include only connectable channels
//
for (int i = 0; i < (int)pcan_ChannelsCount; i++) {
if (info[i].channel_condition & PCAN_CHANNEL_AVAILABLE) //通道有效,且未被使用
{
bIsFD = info[i].device_features & FEATURE_FD_CAPABLE; //判断是否是FD设备
m_HwInfo.append(info[i]);
}
}
Pcan_SetChannel(0); //默认设置为通道0
delete[] info;
}
}
2、配置并开启PCAN
/*
* 设备开启
*/
void PcanMathod::Open(quint32 bd_rate)
{
qint16 stsResult;
if (bIsFD) {
char txtBitrate[] = "f_clock_mhz=20, nom_brp=5, nom_tseg1=2, nom_tseg2=1, nom_sjw=1, data_brp=2, data_tseg1=3, data_tseg2=1, data_sjw=1";
stsResult = InitializeFD(txtBitrate);
}
else {
TPCANBaudrate rate = PCAN_BAUD_250K;
switch (bd_rate) {
case 1000:
rate = PCAN_BAUD_1M;
break;
case 800:
rate = PCAN_BAUD_800K;
break;
case 500:
rate = PCAN_BAUD_500K;
break;
case 250:
rate = PCAN_BAUD_250K;
break;
case 125:
rate = PCAN_BAUD_125K;
break;
case 100:
rate = PCAN_BAUD_100K;
break;
case 95:
rate = PCAN_BAUD_95K;
break;
case 83:
rate = PCAN_BAUD_83K;
break;
case 50:
rate = PCAN_BAUD_50K;
break;
case 47:
rate = PCAN_BAUD_47K;
break;
case 33:
rate = PCAN_BAUD_33K;
break;
case 20:
rate = PCAN_BAUD_20K;
break;
case 10:
rate = PCAN_BAUD_10K;
break;
case 5:
rate = PCAN_BAUD_5K;
break;
}
stsResult = Initialize(rate, PCAN_TYPE_ISA, 0x100, 0x03);//后面两个参数固定
}
if (stsResult != PCAN_ERROR_OK) {
if (stsResult != PCAN_ERROR_CAUTION) {
dev_status = false;
qDebug() << QObject::tr("can open failed!");
return;
}
else {
qDebug() << QObject::tr("The bitrate being used is different than the given one");
return;
}
}
else {
dev_status = true;
QTimer::singleShot(300, this, [=]() { //延时300ms后发送启动当前USB线程
QFuture featrue0 = QtConcurrent::run(&PcanMathod::DataSendFture, this);//将任务放入线程池中运行
QFuture featrue1 = QtConcurrent::run(&PcanMathod::DataReadFture, this);//将任务放入线程池中运行
});
qDebug() << QObject::tr("can open success!");
}
}
3、数据发送
/*
* 数据发送接口
*/
void PcanMathod::SendData(CAN_DATA_FRAME* frame)
{
TPCANMsg msg;
tagTPCANMsgFD msgfd;
msg.ID = *(quint32*)frame->CanId;
msg.LEN = frame->Dlc;
if (frame->IDE == CAN_IDE_EXT) {
msg.MSGTYPE = PCAN_MESSAGE_EXTENDED;
}
else if (frame->IDE == CAN_IDE_STD) {
msg.MSGTYPE = PCAN_MESSAGE_STANDARD;
}
memcpy(msg.DATA, frame->CanDta, frame->Dlc);
TPCANStatus stsResult;
// The message is sent
stsResult = bIsFD ? WriteFD(&msgfd) : Write(&msg);
// The Hardware was successfully sent
if (stsResult == PCAN_ERROR_OK) {
//发送成功
}
else {
qDebug() << tr("pcan send err");
}
return;
}
4、数据接收
/*
* 数据接收线程
*/
void PcanMathod::DataReadFture()
{
TPCANMsg CANMsg;
TPCANTimestamp CANTimeStamp;
TPCANStatus stsResult;
while (dev_status) {
stsResult = Read(&CANMsg, &CANTimeStamp);
if (stsResult != PCAN_ERROR_QRCVEMPTY) {
Pcan_Analysis_Package(CANMsg, CANTimeStamp);
}
else {
}
}
}
/*
* NPCW数据解析接口
*/
void PcanMathod::Pcan_Analysis_Package(TPCANMsg msg, TPCANTimestamp timestamp)
{
CAN_DATA_FRAME rev_frame;
quint64 m_tt = timestamp.micros + (1000ULL * timestamp.millis) + (0x100'000'000ULL * 1000ULL * timestamp.millis_overflow);
memcpy(rev_frame.CanDta, msg.DATA, msg.LEN);
memcpy(rev_frame.CanId, (quint8*)&msg.ID, sizeof(msg.ID));
rev_frame.CanNo = CAN0_TYPECODE;//PCAN只有一个CAN,定义他为CAN0
rev_frame.Dir = true; //数据接收
rev_frame.Dlc = msg.LEN;
if (msg.MSGTYPE == PCAN_MESSAGE_STANDARD) {
rev_frame.IDE = CAN_IDE_STD;
}
else if (msg.MSGTYPE == PCAN_MESSAGE_EXTENDED) {
rev_frame.IDE = CAN_IDE_EXT;
}
else if (msg.MSGTYPE == PCAN_MESSAGE_ERRFRAME) {
rev_frame.IDE = CAN_IDE_ERR;
}
rev_frame.Time = QTime::currentTime().msecsSinceStartOfDay();
emit DataReady(rev_frame);
}
5、关闭设备
/*
* 设备关闭
*/
void PcanMathod::Close()
{
dev_status = false;
Uninitialize();
}