基于CAN总线的汽车诊断协议--Windows上位机设计

3 篇文章 2 订阅
3 篇文章 0 订阅

CAN总线的上位机设计,本章将基于windows平台做出相关讲解。

CAN总线上位机的开发,若我们不是开发CAN卡的厂商,基本来说都是二次开发。我们需借助当前使用的CAN卡设备,利用CAN卡提供的动态库或静态库,做相应的应用开发。

前期准备:

1.UI选择方案:VS自带的MFC C# 或当下流行的QT等(这个主要看各人习惯,对哪种平台熟悉,选哪种吧)

2.对多线程开发的理解(建议采用多线程)

3.CAN卡和二次开发库

4.下位机(具有CAN外设,软件实现CAN基本功能)

5.具备15765 14229的协议基础

接下来我们看看如何实现基本的二次开发吧

一、二次开发库及其资料解读(这里笔者就用国外的PCAN和国内的ITEKON举例)

 

        其实不管哪一家的CAN卡,都提供了常规平台的demo,如:vc qt labview等等,查阅提供的函数手册,我们就可以实现基本的设备查询读写操作了。如PCAN提供了及其完整的工程和执行文件,如下:

讲到这里了是不是很简单,别人提供了源码工程和手册,我们只需要提供的二次开发库,定制自己的上位机。

二、平台基本元素介绍,如下两家sdk基础包都差不多,设备初始化读写关闭等等:

TPCANStatus __stdcall CAN_Initialize(
        TPCANHandle Channel, 
        TPCANBaudrate Btr0Btr1, 
        TPCANType HwType _DEF_ARG,
		DWORD IOPort _DEF_ARG, 
		WORD Interrupt _DEF_ARG);

TPCANStatus __stdcall CAN_InitializeFD(
    TPCANHandle Channel,
	TPCANBitrateFD BitrateFD);

TPCANStatus __stdcall CAN_Uninitialize(
        TPCANHandle Channel);

TPCANStatus __stdcall CAN_Reset(
        TPCANHandle Channel);

TPCANStatus __stdcall CAN_GetStatus(
        TPCANHandle Channel);

TPCANStatus __stdcall CAN_Read(
        TPCANHandle Channel, 
        TPCANMsg* MessageBuffer, 
        TPCANTimestamp* TimestampBuffer);

TPCANStatus __stdcall CAN_ReadFD(
    TPCANHandle Channel,
	TPCANMsgFD* MessageBuffer, 
	TPCANTimestampFD *TimestampBuffer);

TPCANStatus __stdcall CAN_Write(
        TPCANHandle Channel, 
        TPCANMsg* MessageBuffer);

TPCANStatus __stdcall CAN_WriteFD(
    TPCANHandle Channel,
	TPCANMsgFD* MessageBuffer);

TPCANStatus __stdcall CAN_FilterMessages(
        TPCANHandle Channel, 
        DWORD FromID, 
        DWORD ToID, 
        TPCANMode Mode);

TPCANStatus __stdcall CAN_GetValue(
        TPCANHandle Channel, 
        TPCANParameter Parameter,  
        void* Buffer, 
        DWORD BufferLength);

TPCANStatus __stdcall CAN_SetValue(
        TPCANHandle Channel,
        TPCANParameter Parameter,
        void* Buffer,
		DWORD BufferLength);

TPCANStatus __stdcall CAN_GetErrorText(
        TPCANStatus Error, 
        WORD Language, 
        LPSTR Buffer);
DWORD __stdcall VCI_OpenDevice(DWORD DeviceType,DWORD DeviceInd,DWORD Reserved);
DWORD __stdcall VCI_CloseDevice(DWORD DeviceType,DWORD DeviceInd);
DWORD __stdcall VCI_InitCAN(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd, PVCI_INIT_CONFIG pInitConfig);

DWORD __stdcall VCI_ReadBoardInfo(DWORD DeviceType,DWORD DeviceInd,PVCI_BOARD_INFO pInfo);
DWORD __stdcall VCI_ReadErrInfo(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_ERR_INFO pErrInfo);
DWORD __stdcall VCI_ReadCANStatus(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_STATUS pCANStatus);

DWORD __stdcall VCI_GetReference(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,DWORD RefType,PVOID pData);
DWORD __stdcall VCI_SetReference(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,DWORD RefType,PVOID pData);

ULONG __stdcall VCI_GetReceiveNum(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
DWORD __stdcall VCI_ClearBuffer(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);

DWORD __stdcall VCI_StartCAN(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
DWORD __stdcall VCI_ResetCAN(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);

ULONG __stdcall VCI_Transmit(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_OBJ pSend,ULONG Len);
ULONG __stdcall VCI_Receive(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_OBJ pReceive,ULONG Len,INT WaitTime=-1);

添加动态库到工程,如VS为例(具体怎么添加库可找教程,网上一大把):

 

 三、基本框架搭建(demo采用MFC)

void CCAN_UDS_Win32Dlg::OnBnClickedButtonOpen()
{
	/*先清空MessageBox 参数*/
	m_LstBoxMessage.ResetContent();

	if (IsConnect == TRUE)
	{
		MessageBox(_T("The device is connect!"));
		return;
	}

	/*开启设备相关初始化工作*/
	VCI_INIT_CONFIG init_config;
	int baud;
	UpdateData(true);

	init_config.AccCode = 0;
	init_config.AccMask = 0xffffff;
	init_config.Filter = 0;
	init_config.Mode = 0;

	/*Select User Baud rate*/
	baud = m_ComboBaud.GetCurSel();
	switch (baud)
	{
	case 0: //1000
		init_config.Timing0 = 0;
		init_config.Timing1 = 0x14;
		break;

	case 1: //800
		init_config.Timing0 = 0;
		init_config.Timing1 = 0x16;
		break;

	case 2: //666
		init_config.Timing0 = 0x80;
		init_config.Timing1 = 0xb6;
		break;

	case 3: //500
		init_config.Timing0 = 0;
		init_config.Timing1 = 0x1c;
		break;

	case 4://400
		init_config.Timing0 = 0x80;
		init_config.Timing1 = 0xfa;
		break;

	case 5://250
		init_config.Timing0 = 0x01;
		init_config.Timing1 = 0x1c;
		break;

	case 6://200
		init_config.Timing0 = 0x81;
		init_config.Timing1 = 0xfa;
		break;

	case 7://125
		init_config.Timing0 = 0x03;
		init_config.Timing1 = 0x1c;
		break;

	case 8://100
		init_config.Timing0 = 0x04;
		init_config.Timing1 = 0x1c;
		break;

	case 9://80
		init_config.Timing0 = 0x83;
		init_config.Timing1 = 0xff;
		break;

	case 10://50
		init_config.Timing0 = 0x09;
		init_config.Timing1 = 0x1c;
		break;
	}

	if (VCI_OpenDevice(m_devtype, 0, 0) != STATUS_OK)
	{
		//MessageBox(_T("Open device fault!"), _T("Alarm"), MB_OK | MB_ICONQUESTION);
		InsertMessageToListBox(TEXT("Open device fault!"));
		return;
	}

	if (VCI_InitCAN(m_devtype, 0, 0, &init_config) != STATUS_OK)
	{
		//MessageBox(_T("Init can fault!"), _T("Alarm"), MB_OK | MB_ICONQUESTION);
		InsertMessageToListBox(TEXT("Init can fault!"));
		VCI_CloseDevice(m_devtype, 0);
		return;
	}

	if (VCI_StartCAN(m_devtype, 0, 0) != 1)
	{
		//MessageBox(_T("The device start false!"));
		InsertMessageToListBox(TEXT("The device start false!"));
	}
	else
	{
		InsertMessageToListBox(TEXT("Open device success!"));
		/*创建收发线程*/
		hThread[0] = (HANDLE)_beginthreadex(NULL, 0, xCAN_TxThread, pThis, 0, NULL);
		hThread[1] = (HANDLE)_beginthreadex(NULL, 0, xCAN_RxThread, pThis, 0, NULL);
		
		IsConnect = TRUE;
	}

}

void CCAN_UDS_Win32Dlg::OnBnClickedButtonReset()
{
	if (IsConnect == FALSE)
	{
		return;
	}

	/*断开设备相关*/
	if (VCI_ResetCAN(m_devtype, 0, 0) == TRUE)
	{
		IsConnect = FALSE;
		MessageBox(_T("The device reset ok!"));
	}
	else
	{
		MessageBox(_T("The device reset false!"));
	}
}

unsigned int WINAPI xCAN_TxThread(PVOID lpParameter)
{
	CCAN_UDS_Win32Dlg* dlg = (CCAN_UDS_Win32Dlg*)lpParameter;
	UINT8 frameReqStatus = REQ_FALSE;
	UINT8 reqStatus = xCAN_FAILURE;

	while(1)
	{	
		WaitForSingleObject(hCAN_TxEvent, INFINITE);

		if (xCAN_SUCCESS == dlg->my_UDSCAN.xCAN_FrameReq(&frameReqStatus))
		{
			/*获取帧请求后的状态:1.准备继续发送,*/
			switch (frameReqStatus)
			{
			case REQ_SFSUCCESS:
			case REQ_FFSUCCESS:
			case REQ_CFSUCCESS:
				ResetEvent(hCAN_TxEvent);
				break;

			case REQ_CFWAITE:

				break;

			default:

				break;		
			}
		
		}
	
		Sleep(dlg->cycleTimer); 
	}

	return 0;
}

unsigned int WINAPI xCAN_RxThread(PVOID lpParameter)
{
	CCAN_UDS_Win32Dlg* dlg = (CCAN_UDS_Win32Dlg*)lpParameter;
	
	while(1)
	{
		WaitForSingleObject(hCAN_RxEvent, INFINITE);
		
		xCAN_ReceiveFrameData(dlg);
			
		ResetEvent(hCAN_RxEvent);	
	}
}

         除此之外,需要对文件分析做相关了解(主机厂对文件格式有要求:srec,hex等等),文件内容大致两部分,一个是bin二进制文件(要烧录到ROM的),一个是描述其地址确切位置,这里不展开介绍,网上可以搜索资料了解。另外这里补充一句,嵌入式IDE像Keil IAR等等,都有针对文件格式转换的工具,具体可了解相关文档。

四、实现UDS功能(UDS是一套完整的标准协议,其实只需要熟透ISO 15765-2 和 ISO 14229-1 用代码形式表达出来就可以了。因为有保密协议,笔者就不展示核心代码了)

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值