概述
好久没上来了,不久前有一个兄弟问我can通讯实现,这东西用了很久了,正好整理下资料,分享下。其实这个根据开发资料去做个简单demo还是很easy的,不过真实项目中使用,就应该注意处理通信中的性能,发送数据与接受数据都应该在线程中去处理。废话不多说,上干货。
准备:
- Can卡硬件有pci接口和usb接口的。pci性能上相对要更强,价格也贵很多,usb的性能上一般也能满足大多数通信需要,而且比较便宜,本例以usb接口为例;
- can通信相关资料,就以当前市面上最常见的产品为例, hZLG致远电子-广州致远电子有限公司这里面有各种型号的硬件以及驱动下载;还有各种实现示例;
- 计算机连接can硬件,并安装好驱动;
- 所用的dll库为所提供资料中主要是调用ControlCAN.dll中的接口,将ControlCAN.dll和kerneldlls文件夹一起放入到自己工程中;
使用c++实现:
为了提高性能,一定要将can的发送和接受在线程中来实现;
封装can管理类CANManager:
CANManager.h
class CANManager
{
private:
CANManager(void);
public:
~CANManager(void);
bool InitCan();
bool CloseCan();
void StartAllThread();
void CloseAllThread();
void SetCmdToQueue(VCI_CAN_OBJ* OBJ);
void ReceiveMsgCan1();//接收CAN1消息
bool SendCommandToCan1();//发送消息
static CANManager * getInstance();
static unsigned __stdcall SendTheardCAN1(LPVOID);
static unsigned __stdcall RecvTheardCAN1(LPVOID);
private:
bool m_bCanOpenSuc;
bool m_bStartThread;
CRITICAL_SECTION lockQ1;
HANDLE m_Rec1Thread;
HANDLE m_Send1Thread;
HANDLE m_hEventExitSend1;
HANDLE m_hEventExitRecv1;
std::queue<VCI_CAN_OBJ*> m_QSendCAN1; //CAN1发送队列
ZLG *m_CAN1;
};
CANManager.cpp
CANManager::CANManager(void)
{
m_bCanOpenSuc = false;
m_bStartThread = false;
InitializeCriticalSection(&lockQ1);
}
CANManager::~CANManager(void)
{
}
CANManager * CANManager::getInstance()
{
static CANManager g_CANManager;
return &g_CANManager;
}
//初始化CAN
bool CANManager::InitCan()
{
CAN_PROPERTY_PARAM Init_PAram;//这个结构为什么这么赋值,请看资料,主要是配置can类型、索引、超时、模式、can通道以及波特率;
Init_PAram.enUSBorPCI = USBCAN;
Init_PAram.dwCANCardIndex = 0;
Init_PAram.dwCANCardType = 21;
Init_PAram.sendTimeout = 100;
Init_PAram.mode = 0;
Init_PAram.Baud.nBaudForPCICAN = 0x1C;
Init_PAram.Baud.nBaudForUSBCAN = 0x1C;
//打开CAN1
Init_PAram.dwCANChannelIndex = 0;
m_CAN1 = new ZLG();
m_CAN1->setCanProperty(Init_PAram);
if (!m_CAN1->openDevice())
{
return false;
}
m_bCanOpenSuc = true;
return true;
}
//关闭CAN
bool CANManager::CloseCan()
{
if (!m_bCanOpenSuc){
//already closed
return true;
}
m_bCanOpenSuc = false;
//关闭CAN
if (!m_CAN1->closeDevice())
{
return false;
}
delete m_CAN1;
m_CAN1 = NULL;
return true;
}
void CANManager::StartAllThread()
{
if (m_bCanOpenSuc)
{
m_bStartThread = true;
m_hEventExitSend1 = CreateEvent(NULL, TRUE, TRUE, NULL);
ResetEvent(m_hEventExitSend1);
m_Send1Thread = (HANDLE)_beginthreadex(NULL, 0, CANManager::SendTheardCAN1, this, 0, 0);
m_hEventExitRecv1 = CreateEvent(NULL, TRUE, TRUE, NULL);
ResetEvent(m_hEventExitRecv1);
m_Rec1Thread = (HANDLE)_beginthreadex(NULL, 0, CANManager::RecvTheardCAN1, this, 0, 0);
}
}
void CANManager::CloseAllThread()
{
if ((!m_bCanOpenSuc) || (!m_bStartThread)) {
//already closed
return;
}
m_bStartThread = false;
if (WAIT_OBJECT_0 == WaitForSingleObject(m_hEventExitSend1, 500))
{
CloseHandle(m_Send1Thread);
m_Send1Thread = INVALID_HANDLE_VALUE;
}
if (WAIT_OBJECT_0 == WaitForSingleObject(m_hEventExitRecv1, 500))
{
CloseHandle(m_Rec1Thread);
m_Rec1Thread = INVALID_HANDLE_VALUE;
}
EnterCriticalSection(&lockQ1);
while (!m_QSendCAN1.empty()) {
delete m_QSendCAN1.front();
m_QSendCAN1.pop();
}
LeaveCriticalSection(&lockQ1);
}
void CANManager::SetCmdToQueue(VCI_CAN_OBJ * OBJ)
{
EnterCriticalSection(&lockQ1);
m_QSendCAN1.push(OBJ);
LeaveCriticalSection(&lockQ1);
}
//CAN1===============================================
unsigned __stdcall CANManager::SendTheardCAN1(LPVOID Owner)
{
((CANManager*)Owner)->SendCommandToCan1();
return 0;
}
bool CANManager::SendCommandToCan1()
{
while (m_bStartThread)
{
if (m_QSendCAN1.size() == 0)
{
Sleep(1);
}
else
{
//Sleep(1);
EnterCriticalSection(&lockQ1);
m_CAN1->transmit(m_QSendCAN1.front()->ID, m_QSendCAN1.front()->Data);
delete m_QSendCAN1.front();
m_QSendCAN1.pop();
LeaveCriticalSection(&lockQ1);
}
}
SetEvent(m_hEventExitSend1);
return true;
}
unsigned __stdcall CANManager::RecvTheardCAN1(LPVOID Owner)
{
((CANManager*)Owner)->ReceiveMsgCan1();
return 0;
}
void CANManager::ReceiveMsgCan1()
{
int RecLength = 0;
VCI_CAN_OBJ RecOBJ[50];
while (m_bStartThread) {
RecLength = m_CAN1->receive(RecOBJ, 50, 100);//一次接受CAN消息最大个数
if (RecLength <= 0) {
Sleep(1);
continue;
}
for (int i = 0; i < RecLength; ++i) {
ControlManager::getInstance()->ReceiveCanMsg(RecOBJ[i]);
}
}
SetEvent(m_hEventExitRecv1);
return;
}
控制管理类ControlManager: 依赖上个类
//ControlManager.h
class ControlManager
{
public:
ControlManager(void);
~ControlManager(void);
static ControlManager * getInstance();
bool InitSC(std::string strCanType);
bool sendCmdToDev();
void ReceiveCanMsg(VCI_CAN_OBJ OBJ);
void ExitSC();
private:
void DecodeCANMsg(VCI_CAN_OBJ OBJ);
CANManager * m_pCanManager;
};
//ControlManager.cpp
ControlManager::ControlManager(void)
{
m_pCanManager = CANManager::getInstance();
}
ControlManager::~ControlManager(void)
{
}
ControlManager * ControlManager::getInstance()
{
static ControlManager g_sSCManager;
return &g_sSCManager;
}
bool ControlManager::InitSC()
{
//初始化CAN口
if (!m_pCanManager->InitCan())
{ return false;
}
writeInfoLog(0, "ControlManager::InitSC:", "init can Success!");
//CAN打开成功,启动发送与接收线程
m_pCanManager->StartAllThread();
return true;
}
bool ControlManager::sendCmdToDev()
{
VCI_CAN_OBJ* OBJ = new VCI_CAN_OBJ();
//OBJ赋值....................根据发送接收协议进行赋值发送
m_pCanManager->SetCmdToQueue(OBJ);//指令存入到CAN发送队列
return true;
}
void ControlManager::ReceiveCanMsg(VCI_CAN_OBJ OBJ)//接收到CAN1 消息
{
if (OBJ.Data == NULL){
return;
}
DecodeCANMsg(OBJ);
}
void ControlManager::DecodeCANMsg(VCI_CAN_OBJ OBJ)
{
.....根据发送接收双方协议进行解析
}
void ControlManager::ExitSC()
{
m_pCanManager->CloseAllThread();
m_pCanManager->CloseCan();
}
架子已经搭好,就剩下如何封装can通讯接口了;
封装类ZLG
ZLG.h:
typedef struct _VCI_CAN_OBJ_ZLG{ //帧结构
UINT ID;
UINT TimeStamp;
BYTE TimeFlag;
BYTE SendType;
BYTE RemoteFlag;//是否远程帧
BYTE ExternFlag;//是否扩展帧
BYTE DataLen;
BYTE Data[8];
BYTE Reserved[3];
}VCI_CAN_OBJ_ZLG,*PVCI_CAN_OBJ_ZLG;
//初始化的数据类型
typedef struct _VCI_INIT_CONFIG_ZLG{
DWORD AccCode;
DWORD AccMask;
DWORD Reserved;
UCHAR Filter;
UCHAR Timing0;
UCHAR Timing1;
UCHAR Mode;
}VCI_INIT_CONFIG_ZLG,*PVCI_INIT_CONFIG_ZLG;
//接口卡信息的数据类型
typedef struct _VCI_BOARD_INFO_ZLG{
USHORT hw_Version;
USHORT fw_Version;
USHORT dr_Version;
USHORT in_Version;
USHORT irq_Num;
BYTE can_Num;
CHAR str_Serial_Num[20];
CHAR str_hw_Type[40];
USHORT Reserved[4];
} VCI_BOARD_INFO_ZLG,*PVCI_BOARD_INFO_ZLG;
enum USBCANorPCICAN//can接口类型
{
USBCAN=1,
PCICAN=2,
};
struct CAN_PROPERTY_PARAM//属性定义
{
USBCANorPCICAN enUSBorPCI;
DWORD dwCANCardType;
DWORD dwCANCardIndex;
DWORD dwCANChannelIndex;
union unBaud
{
int nBaudForUSBCAN;
int nBaudForPCICAN;
}Baud;
int mode;
int sendTimeout;
};
class ZLG
{
public:
ZLG();
~ZLG();
void setCanProperty(const CAN_PROPERTY_PARAM & SetProperty);
BOOL openDevice();
BOOL transmit(const UINT uInfoHead, const BYTE * pData, UINT ExternFlag = 0, UINT RemoteFlag = 0);
UINT getReceiveNum();
UINT receive(VCI_CAN_OBJ * pReceive, const ULONG Len, const INT WaitTime);
BOOL closeDevice();
public:
BOOL initCan();
BOOL startCan();
BOOL clearBuffer();
private:
bool bSetProperty;
bool bOpen;
bool bClosed;
HANDLE ghd_OneCanCardOnlyOpenOnce; //防止重复打开
HANDLE ghd_OneCanCardsOneChannelOnlyOpenOnce;//防止重复打开
CAN_PROPERTY_PARAM m_CanProperty;
};
ZLG.cpp: initCan中的VCI_INIT_CONFIG字段mode如果测试可以设置为2,这样就是自发自收,便于测试;
const DWORD GCanBrTab[10] = {//波特率
0x060003, 0x060004, 0x060007,
0x1C0008, 0x1C0011, 0x160023,
0x1C002C, 0x1600B3, 0x1C00E0,
0x1C01C1
};
ZLG::ZLG() :bSetProperty(false),
bOpen(false),
bClosed(false),
ghd_OneCanCardOnlyOpenOnce(NULL),
ghd_OneCanCardsOneChannelOnlyOpenOnce(NULL)
{
}
ZLG::~ZLG()
{
if (!bClosed)
{
closeDevice();
}
if (ghd_OneCanCardOnlyOpenOnce != NULL)
{
CloseHandle(ghd_OneCanCardOnlyOpenOnce);
ghd_OneCanCardOnlyOpenOnce = NULL;
}
if (ghd_OneCanCardsOneChannelOnlyOpenOnce != NULL)
{
CloseHandle(ghd_OneCanCardsOneChannelOnlyOpenOnce);
ghd_OneCanCardsOneChannelOnlyOpenOnce = NULL;
}
}
void ZLG::setCanProperty(const CAN_PROPERTY_PARAM & SetProperty)
{
m_CanProperty = SetProperty;
bSetProperty = true;
}
BOOL ZLG::openDevice()
{
if (!bSetProperty)
{
return FALSE;
}
char HandleSTring[30];
sprintf_s(HandleSTring, "ThisCanCardIndex%d", m_CanProperty.dwCANCardIndex);
ghd_OneCanCardOnlyOpenOnce = CreateMutex(NULL, TRUE, HandleSTring);
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
CloseHandle(ghd_OneCanCardOnlyOpenOnce);
ghd_OneCanCardOnlyOpenOnce = NULL;
if (!initCan())
{
bOpen = false;
return FALSE;
}
else
{
if (!startCan())
{
bOpen = false;
return FALSE;
}
else
{
if (!clearBuffer())
{
bOpen = false;
return FALSE;
}
else
{
bOpen = true;
BYTE byStartDataAny[8];
memset(byStartDataAny, 'X', 8);
if (!transmit(0, byStartDataAny))
{
bOpen = false;
return FALSE;
}
else
{
bOpen = true;
bClosed = false;
return TRUE;
}
}
}
}
}
else
{
if (STATUS_OK != VCI_OpenDevice(m_CanProperty.dwCANCardType, m_CanProperty.dwCANCardIndex, m_CanProperty.mode))
{
bOpen = false;
return FALSE;
}
else
{
if (!initCan())
{
bOpen = false;
return FALSE;
}
else
{
if (!startCan())
{
bOpen = false;
return FALSE;
}
else
{
if (!clearBuffer())
{
bOpen = false;
return FALSE;
}
else
{
bOpen = true;
bClosed = false;
return TRUE;
}
}
}
}
}
}
BOOL ZLG::closeDevice()
{
if (ghd_OneCanCardOnlyOpenOnce != NULL)
{
CloseHandle(ghd_OneCanCardOnlyOpenOnce);
ghd_OneCanCardOnlyOpenOnce = NULL;
}
if (ghd_OneCanCardsOneChannelOnlyOpenOnce != NULL)
{
CloseHandle(ghd_OneCanCardsOneChannelOnlyOpenOnce);
ghd_OneCanCardsOneChannelOnlyOpenOnce = NULL;
}
VCI_CloseDevice(m_CanProperty.dwCANCardType, m_CanProperty.dwCANCardIndex);
bClosed = true;
bOpen = false;
return TRUE;
}
BOOL TZLG::initCan()
{
char HandleSTring[50];
sprintf_s(HandleSTring, "ThisCanCardIndexChannelInd%d%d", m_CanProperty.dwCANCardIndex, m_CanProperty.dwCANChannelIndex);
ghd_OneCanCardsOneChannelOnlyOpenOnce = CreateMutex(NULL, TRUE, HandleSTring);
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
CloseHandle(ghd_OneCanCardsOneChannelOnlyOpenOnce);
ghd_OneCanCardsOneChannelOnlyOpenOnce = NULL;
return FALSE;
}
else
{
if (PCICAN == m_CanProperty.enUSBorPCI)
{
VCI_INIT_CONFIG init_config;
init_config.AccCode = 0;
init_config.AccMask = 0xffffffff;
init_config.Filter = 0;
init_config.Mode = 0;//此字段如果设置为2 就可以自发自收,便于测试
init_config.Timing0 = 0;
init_config.Timing1 = m_CanProperty.Baud.nBaudForPCICAN;
if (STATUS_OK != VCI_InitCAN(m_CanProperty.dwCANCardType, m_CanProperty.dwCANCardIndex, m_CanProperty.dwCANChannelIndex, &init_config))
{
return FALSE;
}
else
{
return TRUE;
}
}
else if (USBCAN == m_CanProperty.enUSBorPCI)
{
DWORD band = GCanBrTab[2];
if (VCI_SetReference(m_CanProperty.dwCANCardType, m_CanProperty.dwCANCardIndex, 0, 0, &band) != STATUS_OK)
{
return FALSE;
}
VCI_INIT_CONFIG init_config;
init_config.AccCode = 0;
init_config.AccMask = 0xffffffff;
init_config.Filter = 0;
init_config.Mode = 0;
init_config.Timing0 = 0;
init_config.Timing1 = m_CanProperty.Baud.nBaudForUSBCAN;
if (STATUS_OK != VCI_InitCAN(m_CanProperty.dwCANCardType, m_CanProperty.dwCANCardIndex, m_CanProperty.dwCANChannelIndex, &init_config))
{
return FALSE;
}
else
{
return TRUE;
}
}
}
return FALSE;
}
BOOL ZLG::startCan()
{
if (STATUS_OK != VCI_StartCAN(m_CanProperty.dwCANCardType, m_CanProperty.dwCANCardIndex, m_CanProperty.dwCANChannelIndex))
{
return FALSE;
}
else
{
return TRUE;
}
}
BOOL ZLG::clearBuffer()
{
if (STATUS_OK != VCI_ClearBuffer(m_CanProperty.dwCANCardType, m_CanProperty.dwCANCardIndex, m_CanProperty.dwCANChannelIndex))
{
return FALSE;
}
else
{
return TRUE;
}
}
BOOL ZLG::transmit(const UINT uInfoHead, const BYTE * pData, UINT ExternFlag, UINT RemoteFlag)
{
if (!bOpen || pData == NULL)
{
return FALSE;
}
VCI_CAN_OBJ frameinfo;
frameinfo.ID = uInfoHead;
frameinfo.DataLen = 8;
frameinfo.ExternFlag = ExternFlag; //0:标准帧, 1:扩展帧
frameinfo.RemoteFlag = RemoteFlag; //0:数据帧, 1:远程帧
frameinfo.SendType = 0;
memcpy(frameinfo.Data, pData, frameinfo.DataLen);
DWORD ask = VCI_SetReference(m_CanProperty.dwCANCardType, m_CanProperty.dwCANCardIndex, m_CanProperty.dwCANChannelIndex, 3, &m_CanProperty.sendTimeout);
DWORD ask_transmit = VCI_Transmit(m_CanProperty.dwCANCardType, m_CanProperty.dwCANCardIndex, m_CanProperty.dwCANChannelIndex, &frameinfo, 1);
if (ask_transmit != STATUS_OK)
{
return FALSE;
}
return TRUE;
}
UINT ZLG::getReceiveNum()
{
if (!bOpen)
{
return 0;
}
VCI_ERR_INFO errinfo;
ULONG RecvNum = 0;
RecvNum = VCI_GetReceiveNum(m_CanProperty.dwCANCardType, m_CanProperty.dwCANCardIndex, m_CanProperty.dwCANChannelIndex);
if (RecvNum <= 0)
{
VCI_ReadErrInfo(m_CanProperty.dwCANCardType, m_CanProperty.dwCANCardIndex, m_CanProperty.dwCANChannelIndex, &errinfo);
}
return RecvNum;
}
UINT ZLG::receive(VCI_CAN_OBJ* pReceive, const ULONG Len, const INT WaitTime)
{
if (!bOpen)
{
return 0;
}
ULONG Rlen = 0;
VCI_ERR_INFO errinfo;
Rlen = VCI_Receive(m_CanProperty.dwCANCardType, m_CanProperty.dwCANCardIndex, m_CanProperty.dwCANChannelIndex, pReceive, Len, WaitTime);
if (Rlen < 0)
{
VCI_ReadErrInfo(m_CanProperty.dwCANCardType, m_CanProperty.dwCANCardIndex, 0, &errinfo);
}
return Rlen;
}
厂商提供的接口头文件
//接口卡类型定义
#define VCI_PCI5121 1
#define VCI_PCI9810 2
#define VCI_USBCAN1 3
#define VCI_USBCAN2 4
#define VCI_USBCAN2A 4
#define VCI_PCI9820 5
#define VCI_CAN232 6
#define VCI_PCI5110 7
#define VCI_CANLITE 8
#define VCI_ISA9620 9
#define VCI_ISA5420 10
#define VCI_PC104CAN 11
#define VCI_CANETUDP 12
#define VCI_CANETE 12
#define VCI_DNP9810 13
#define VCI_PCI9840 14
#define VCI_PC104CAN2 15
#define VCI_PCI9820I 16
#define VCI_CANETTCP 17
#define VCI_PEC9920 18
#define VCI_PCIE_9220 18
#define VCI_PCI5010U 19
#define VCI_USBCAN_E_U 20
#define VCI_USBCAN_2E_U 21
#define VCI_PCI5020U 22
#define VCI_EG20T_CAN 23
#define VCI_PCIE9221 24
//CAN错误码
#define ERR_CAN_OVERFLOW 0x0001 //CAN控制器内部FIFO溢出
#define ERR_CAN_ERRALARM 0x0002 //CAN控制器错误报警
#define ERR_CAN_PASSIVE 0x0004 //CAN控制器消极错误
#define ERR_CAN_LOSE 0x0008 //CAN控制器仲裁丢失
#define ERR_CAN_BUSERR 0x0010 //CAN控制器总线错误
#define ERR_CAN_BUSOFF 0x0020 //总线关闭错误
//通用错误码
#define ERR_DEVICEOPENED 0x0100 //设备已经打开
#define ERR_DEVICEOPEN 0x0200 //打开设备错误
#define ERR_DEVICENOTOPEN 0x0400 //设备没有打开
#define ERR_BUFFEROVERFLOW 0x0800 //缓冲区溢出
#define ERR_DEVICENOTEXIST 0x1000 //此设备不存在
#define ERR_LOADKERNELDLL 0x2000 //装载动态库失败
#define ERR_CMDFAILED 0x4000 //执行命令失败错误码
#define ERR_BUFFERCREATE 0x8000 //内存不足
//函数调用返回状态值
#define STATUS_OK 1
#define STATUS_ERR 0
#define CMD_DESIP 0
#define CMD_DESPORT 1
#define CMD_CHGDESIPANDPORT 2
#define CMD_SRCPORT 2
#define CMD_TCP_TYPE 4 //tcp 工作方式,服务器:1 或是客户端:0
#define TCP_CLIENT 0
#define TCP_SERVER 1
//服务器方式下有效
#define CMD_CLIENT_COUNT 5 //连接上的客户端计数
#define CMD_CLIENTS 6 //连接上的客户端
#define CMD_DISCONN_CLINET 7 //断开一个连接
typedef struct tagRemoteClient{
int iIndex;
DWORD port;
HANDLE hClient;
char szip[32];
}REMOTE_CLIENT;
//1.ZLGCAN系列接口卡信息的数据类型。
typedef struct _VCI_BOARD_INFO{
USHORT hw_Version;
USHORT fw_Version;
USHORT dr_Version;
USHORT in_Version;
USHORT irq_Num;
BYTE can_Num;
CHAR str_Serial_Num[20];
CHAR str_hw_Type[40];
USHORT Reserved[4];
} VCI_BOARD_INFO,*PVCI_BOARD_INFO;
//2.定义CAN信息帧的数据类型。
typedef struct _VCI_CAN_OBJ{
UINT ID;
UINT TimeStamp;
BYTE TimeFlag;
BYTE SendType;
BYTE RemoteFlag;//是否是远程帧
BYTE ExternFlag;//是否是扩展帧
BYTE DataLen;
BYTE Data[8];
BYTE Reserved[3];
}VCI_CAN_OBJ,*PVCI_CAN_OBJ;
//3.定义CAN控制器状态的数据类型。
typedef struct _VCI_CAN_STATUS{
UCHAR ErrInterrupt;
UCHAR regMode;
UCHAR regStatus;
UCHAR regALCapture;
UCHAR regECCapture;
UCHAR regEWLimit;
UCHAR regRECounter;
UCHAR regTECounter;
DWORD Reserved;
}VCI_CAN_STATUS,*PVCI_CAN_STATUS;
//4.定义错误信息的数据类型。
typedef struct _VCI_ERR_INFO{
UINT ErrCode;
BYTE Passive_ErrData[3];
BYTE ArLost_ErrData;
} VCI_ERR_INFO,*PVCI_ERR_INFO;
//5.定义初始化CAN的数据类型
typedef struct _VCI_INIT_CONFIG{
DWORD AccCode;
DWORD AccMask;
DWORD Reserved;
UCHAR Filter;
UCHAR Timing0;
UCHAR Timing1;
UCHAR Mode;
}VCI_INIT_CONFIG,*PVCI_INIT_CONFIG;
typedef struct _tagChgDesIPAndPort
{
char szpwd[10];
char szdesip[20];
int desport;
BYTE blistenonly;
}CHGDESIPANDPORT;
/ new add struct for filter /
typedef struct _VCI_FILTER_RECORD{
DWORD ExtFrame; //是否为扩展帧
DWORD Start;
DWORD End;
}VCI_FILTER_RECORD,*PVCI_FILTER_RECORD;
#define EXTERNC extern "C"
EXTERNC DWORD __stdcall VCI_OpenDevice(DWORD DeviceType,DWORD DeviceInd,DWORD Reserved);
EXTERNC DWORD __stdcall VCI_CloseDevice(DWORD DeviceType,DWORD DeviceInd);
EXTERNC DWORD __stdcall VCI_InitCAN(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd, PVCI_INIT_CONFIG pInitConfig);
EXTERNC DWORD __stdcall VCI_ReadBoardInfo(DWORD DeviceType,DWORD DeviceInd,PVCI_BOARD_INFO pInfo);
EXTERNC DWORD __stdcall VCI_ReadErrInfo(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_ERR_INFO pErrInfo);
EXTERNC DWORD __stdcall VCI_ReadCANStatus(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_STATUS pCANStatus);
EXTERNC DWORD __stdcall VCI_GetReference(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,DWORD RefType,PVOID pData);
EXTERNC DWORD __stdcall VCI_SetReference(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,DWORD RefType,PVOID pData);
EXTERNC ULONG __stdcall VCI_GetReceiveNum(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
EXTERNC DWORD __stdcall VCI_ClearBuffer(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
EXTERNC DWORD __stdcall VCI_StartCAN(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
EXTERNC DWORD __stdcall VCI_ResetCAN(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
EXTERNC ULONG __stdcall VCI_Transmit(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_OBJ pSend,ULONG Len);
EXTERNC ULONG __stdcall VCI_Receive(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_OBJ pReceive,ULONG Len,INT WaitTime=-1);
搞定!
最后
以上就是听话枫叶为你收集整理的Can通讯的全部内容,希望文章能够帮你解决Can通讯所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复