好久没上来了,不久前有一个兄弟问我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();