转自http://blog.sina.com.cn/s/blog_948ce9dd01017yy2.html
硬件设备是DSP电机板的CAN通信模块和周立功公司生产的USBCAN-I/II智能CAN接口卡组成的进行数据传输,上位机实质是将can接口卡中收到的数据读取出来在pc机上处理以及发送命令或数据给CAN接口卡,CAN接口卡采用CAN协议发送给DSP电机板的CAN通信模块,间接实现上位机与DSP的CAN通信。
由于上位机只需和CAN接口卡进行数据交换,因此,上位机的协议将简化,充分利用周立功公司提供的CAN接口卡的接口函数库即可轻松开发出适用于自己的CAN上位机。接口函数库的下载地址http://www.embedcontrol.com/products/PCI/USBCAN.asp
在上位机程序中,主要需要使用的函数有DWORD__stdcallVCI_OpenDevice(DWORDDevType,DWORDDevIndex,DWORDReserved);
DWORD__stdcallVCI_CloseDevice(DWORD DevType,DWORD DevIndex);
DWORD __stdcall VCI_InitCan(DWORD DevType, DWORD DevIndex, DWORD CANIndex, PVCI_INIT_CONFIG
DWORD__stdcallVCI_StartCAN(DWORD DevType,DWORD DevIndex,DWORD CANIndex);
DWORD__stdcallVCI_ResetCAN(DWORD DevType,DWORD DevIndex,DWORD CANIndex);
ULONG__stdcallVCI_Receive(DWORD DevType,DWORD DevIndex,DWORD CANIndex,PVCI_CAN_OBJ pReceive,ULONG Len,INT WaitTime=-1);
ULONG__stdcallVCI_Transmit(DWORD
首先,把库函数文件都放在工作目录下。库函数文件总共有三个文件:ControlCAN.h、ControlCAN.lib、ControlCAN.dll和一个文件夹kerneldlls。
其次 (1)在扩展名为.CPP的文件中包含ControlCAN.h头文件。
如:#include“ControlCAN.h”
(2) 在工程的连接器设置中连接到ControlCAN.lib文件。
如:在VC7环境下,在项目属性页里的配置属性→连接器→输入→附加依赖项中添加
ControlCAN.lib
或者,在源文件的包含头文件处添加#pragma comment(lib,"controlcan.lib")、
//接口卡设备类型定义
#define VCI_PCI5121
#define VCI_PCI9810
#define VCI_USBCAN1
#define VCI_USBCAN2
#define VCI_USBCAN2A
#define VCI_PCI9820
#define VCI_CAN232
#define VCI_PCI5110
#define VCI_CANLITE
#define VCI_ISA9620
#define VCI_ISA5420
#define VCI_PC104CAN
#define VCI_CANETUDP
#define VCI_CANETE
#define VCI_DNP9810
#define VCI_PCI9840
#define VCI_PC104CAN2
#define VCI_PCI9820I
#define VCI_CANETTCP
#define VCI_PEC9920
#define VCI_PCI5010U
#define VCI_USBCAN_E_U
#define VCI_USBCAN_2E_U
#define VCI_PCI5020U
#define VCI_EG2OT_CAN
VCI_InitCan时要用到的结构体参数VCI_INIT_CONFIG,这个结构体定义了初始化CAN的配置,设置CAN的波特率、屏蔽码。对于设备类型为PCI-5010-U/PCI-5020-U/USBCAN-E-U/USBCAN-2E-U时,对滤波和波特率的设置应该放到VCI_SetReference里设置,这里pInitConfig中的成员只有Mode需要设置,其他的6个成员可以忽略。
typedefstruct_INIT_CONFIG{
DWORD AccCode;
DWORD AccMask;
DWORD Reserved;
UCHAR Filter;
UCHAR Timing0;
UCHAR Timing1;
UCHAR Mode;
}VCI_INIT_CONFIG,*PVCI_INIT_CONFIG;
设置结构体参数的Timing0和Timing1可以设置CAN的波特率,常见的波特率设置如下:
CAN波特率
5Kbps
10Kbps
20Kbps
40Kbps
50Kbps
80Kbps
100Kbps
125Kbps
200Kbps
250Kbps
400Kbps
500Kbps
666Kbps
800Kbps
1000Kbps
VCI_Receive和VCI_Transmit时需要用到PVCI_CAN_OBJ结构体,这个结构体用来传送CAN的信息帧。
typedefstruct_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;
成员参数的含义:
ID
报文ID。
TimeStamp
接收到信息帧时的时间标识,从CAN控制器初始化开始计时。
TimeFlag
是否使用时间标识,为1时TimeStamp有效,TimeFlag和TimeStamp只在此帧为接收帧时有意义。
SendType
发送帧类型,=0时为正常发送,=1时为单次发送,=2时为自发自收,=3时为单次自发自收,只在此
帧为发送帧时有意义。(当设备类型为EG20T-CAN时,发送方式在VCI_InitCan中通过设置,此处的
设置无效,设置为自发自收模式后EG20T-CAN不能从总线上接收数据,只能收到自己发出的数据)RemoteFlag
是否是远程帧。
ExternFlag
是否是扩展帧。
DataLen
8
数据长度(<=8),即Data的长度。
Data
报文的数据。
Reserved
系统保留。
接收信息创建一个线程,在线程中接收数据。AfxBeginThread(ReceiveThread,this);注意,如果线程函数是类的成员函数,需要声明为静态的。全局函数不需要声明为静态。原因是类的静态函数不属于该类的任何一个对象,而是属于类本身,所以不受对象局部变量的影响,在运行时可以直接调用类的静态函数,从而启动线程!普通成员函数再参数传递时编译器会加一个this指针,而静态不会,否则你编译的时候会出错.
函数操作流程:
MFC主要代码
void CCanTestDlg::OnBnClickedButtoninitial
{
}
void CCanTestDlg::OnBnClickedButtonsend()
{
}
int CCanTestDlg::CharToInt(unsigned char chardata, unsigned char *intdata)
{
}
int CCanTestDlg::StrToInt(unsigned char* str, unsigned char* intdata, int length, int flag)
{
}
return 0;
}
void CCanTestDlg::ShowList(CString str)
{
}
unsigned int CCanTestDlg::ReceiveThread(void *param)
{
}
void CCanTestDlg::OnBnClickedButtonclear()
{
}
void CCanTestDlg::OnBnClickedButtonpause()
{
}
注意:
1,线程声明要声明为静态函数,AfxBeginThread返回值是一个CWinThread 的指针,定义时,CWinThread *m_thread;
2,GetDlgItem(IDC_DataList)的类型转换要在引用成员函数前进行,即,要注意括号的位置。
((CListBox *)GetDlgItem(IDC_DataList))->ResetContent();若在CListBox外不加双括号,其成员函数会找不到ResetContent函数。
3,线程的暂停继续,可以实现接收数据的暂停和继续。m_thread->SuspendThread();