《Can通信模块详细设计说明书.doc》由会员分享,可在线阅读,更多相关《Can通信模块详细设计说明书.doc(22页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、Can.cpp模块设计说明1. 总则:传送故障记录数据或运行记录数据时,不传送参数数据和实时数据。传送参数数据和实时数据可同时传送。在界面层:1. 读故障记录数据BUTTON和运行记录数据BUTTON和记录实时数据BUTTON没有按下,参数没有操作时,才能按下读故障记录数据BUTTON或运行记录数据BUTTON。否则弹出信息框。2. 按下故障记录数据BUTTON后,把运行记录数据BUTTON和记录实时数据BUTTON变灰,参数MENU和参数界面上的读和修改BUTTON变灰,故障记录数据读完后,上述按钮复原。对按下运行记录数据BUTTON作同样处理。3. 按下记录实时数据BUTTON时,把故障记
2、录数据BUTTON和运行记录数据BUTTON变灰。按下停止记录实时数据BUTTON时,把故障记录数据BUTTON和运行记录数据BUTTON复原。4. 对参数上载和修改时,把故障记录数据BUTTON和运行记录数据BUTTON变灰,完成操作后把故障记录数据BUTTON和运行记录数据BUTTON复原。CAN和以太网类似,相应7种事件:关闭CAN、实时数据请求、读参数、写参数、发送心跳报文,读故障记录,读运行记录。2 功能 模块类名为:Class Can 类对象定义在Can.cpp中,是一个全局对象。Class Lan g_Can;该模块的功能为:1. 通过USB转CAN与下位机进行实时数据请求和参数
3、的上传下载, 读故障记录,读运行记录;2. 通过PCI插卡与下位机进行实时数据请求和参数的上传下载, 读故障记录,读运行记录;3. 出错处理。3 流程逻辑CAN部分由线程CanThread()完成5个事件。OpenCan(DWORD DevType,DWORD DevIndex,DWORD Reserved)函数通过调用API函数VCI_OpenDevice(DWORD DevType,DWORD DevIndex,DWORD Reserved)打开CAN;CloseCan(DWORD DevType,DWORD DevIndex)函数通过调用API函数VCI_CloseDevice(DWOR
4、D DevType,DWORD DevIndex)关闭CAN;StartCanThread()函数用于开启Can线程;SuspendedCanThread()函数用于关闭线程;CanThread()为Can线程函数,用于执行五种事件:关闭Can、发送实时数据请求、读参数、写参数和发送心跳报文。SendCanPacket(int iEvent,int Index = 0,int SubIndex = 0,*Data = NULL)为CAN发送报文函数,iEvent为事件值,Index、SubIndex、Data用于参数的读写事件。根据不同的事件,发送相应的报文。RecvCanPacket()Ju
5、dgeOvertime();以上函数形参封装在以下的数据结构中:typedef struct _CAN_DEVICE_PARM_DWORD dwDevType;/设备类型号DWORD dwDevIndex;/设备索引号DWORD dwReserved;/保留DWORD dwCANIndex;/Can第几路DWORD dwChecCode;/验收码DWORD dwMask;/屏蔽码DWORD m_dwMode;/模式int iTimer0;/定时器int iTimer1;/定时器int iFilterType;/滤波方式CAN_DEVICE_PARM;typedef struct _VCI_CA
6、N_OBJUINTuiID;UINTuiTimeStamp;BYTEbyTimeFlag;BYTEbySendType;BYTEbyRemoteFlag;/是否是远程帧BYTEbyExternFlag;/是否是扩展帧BYTEbyDataNbytes;BYTEbyDataBuf8;BYTEbyReserved3;VCI_CAN_OBJ,*PVCI_CAN_OBJ;成员uiID:报文ID;uiTimeStamp:接收到信息帧的时间标识,从CAN控制器初始化开始计时;byTimeFlag:是否使用时间标识,为1时uiTimeStamp有效,byTimeFlag和uiTimeStamp只在此帧为接收帧
7、时有意义;bySendType:发送帧类型,0为正常发送,1为单次发送,2为自发自收,3为单次自发自收只在此帧为发送帧时有意义;byRemoteFlag:是否为远程帧;byExternFlag:是否为扩展帧;byDataNbytes:数据长度(=8),即Data的长度;byDataBuf:报文的数据;byReserved:系统保留。typedef struct _VCI_INIT_CONFIGDWORDdwAccCode;DWORDdwAccMask;DWORDdwReserved;UCHARucFilter;UCHARucTiming0;UCHARucTiming1;UCHARucMode;
8、VCI_INIT_CONFIG,*PVCI_INIT_CONFIG;成员:dwAccCode:验收码;dwAccMask:屏蔽码;dwReserved:系统保留;ucFilter:滤波方式,1为单波方式,0为双波方式;ucTiming0:定时器0;ucTiming1:定时器1;ucMode:模式。0为正常模式,1为只听模式在Datalayer.cpp中添加成员变量:BYTE m_byCANRealTimeBuffer;BYTE m_byCANParmBuffer;添加成员函数:int GetDataFromCANPacket();对CAN接收到的数据进行解析分类,将数据存于他对应的地方。CAN
9、从界面层到通讯层的整体流程图:OpenCAN()函数流程图:SendCanPacket()流程图:CANThread()流程图:RecvCanPacket()流程图:1)如收到的是心跳报文“,则丢掉IDDLDLByte0Byte1Byte2Byte3Byte4Byte5Byte6Byte70x7020x01State00000002)如收到的是中止SDO请求报文(最后4个字节是16进制中止代码之一0601 0000,其功能描述是“对象不支持访问”)CANIDDLDLByte0Byte1Byte2Byte3Byte4Byte5Byte6Byte70x5820x080x80IndexSub-ind
10、ex00000106则上位机通知参数设定界面,参数设定界面弹出对话框告知参数INDEX 或SUBINDEX出错。上位机停止上传/下载系统参数。4 实时数据和参数通信过程(供参考)4.1 数据结构:在InternalDef.h中增加#defineLIMIT_CAN_RECV_ONE_PACKET_TIMEOUT_MS 200#definePACKET_TIMEOUT2在PdasConfig中增加Intm_iCanRecvOnePacketTimeoutMs;在PdasCong.cpp中m_iCanRecvOnePacketTimeoutMs=LIMIT_CAN_RECV_ONE_PACKET_T
11、IMEOUT_MS在DataLayer.h中增加intm_iCanRealTimeDataNbytes;/UDP收到的数据长度BYTEm_byCanRealTimeData500;在Can.h中增加BYTEm_byRealTimeData128Intm_iIndexOfRealTimeData;BOOLm_bFirstRealTimeBlock4.2 程序伪代码:1. 初始化m_byRealTimeData为全0,且m_byRealTimeData00=0xff;m_bFirstRealTimeBlock=TRUE2.在应该发送的时刻调用 SendNmi(0x01)函数该函数组织报文(00,0
12、2,01,02,00,00,00,00,00,00)然后调用VCI_Trasmit()3. BOOLbShouldSave=FALSE;While(TRUE)If(ShouldSendParmPacket(.)/有上载参数报文或修改参数报文要发送OrganizeParmPacket(.)/组织发送VCI_Transmit(.)iNbytes=VCI_Receive(.),超时时间用变量g_PdasConfig.CanRecvOnePacketTimeoutMs;iState=ProcessPossibleTimeOut(.)/返回PACKET_TIMEOUT或DEVICE_FAULTIf(iS
13、tate=PACKET_TIMEOUT)Continue;Else if(iState=DEVICE_FAULT)g_DataLayer.iDeviceStateDEVICE_CAN=DEVICE_FAULTBreak;iPacketType=JudgeReceivedPacketType(.)If(iPacketType=REAL_TIME_DATA| =LAST_REAL_TIME_DATA)/收到实时数据报文根据ID,DL,Byte放入相应m_byRealTimeData?Else if(iPacketType=UPLOAD_PARM)ProcessUpLoadParm(.)/参数报文处
14、理Else if(iPacketType=MODITY_PARM)ProcessModityParm(.)/参数报文处理If(iPacketType=LAST_REAL_TIME_DATA)/(0x484,0x08,0x0B)收到If( m_iReadRecordStage=BEGIN)break/退出循环,去读故障记录数据If(m_bFirstRealTimeBlock=TRUE)If(12个报文全收到)m_bFirstRealTimeBlock=FALSEbShouldSave=TRUEElsebShouldSave=TRUEIf(bShouldSave)bShouldSave=FALSE
15、;g_DataLayer.PutRealTimeData(m_byRealTimeData,iErrorCode,DEVICE_CAN);/end of While()5 传送故障记录数据或运行记录数据过程(供参考)5.1 数据结构:InternalDef.h中增加#defineNON_RECORD0#defineFAULT_RECORD1#defineNORMAL_RECORD2#defineBEGIN_RECORD1.#defineCOMPLETE_RECORDxx#defineFIRST_INDEX_OF_FAULT_RECORD0x2000#defineFIRST_INDEX_OF_N
16、ORMAL_RECORD0x3000#defineLAST_INDEX_OF_FAULT_RECORD(0x3000-1)#defineLAST_INDEX_OF_NORMAL_RECORD(0x4000-1)/现由周提供PdasConfig.h中增加Intm_iFirstIndexOfFaultRecordIntm_iFirstIndexOfNormalRecordIntm_iLastIndexOfFaultRecordIntm_iLastIndexOfNormalRecordPdasConfig.cpp中增加对它们赋初值Can类中增加Intm_iRecvRecordTypeInt m_iR
17、ecvRecordStageBYTEm_byRecordData128Intm_iIndexOfRecordData;Intm_iSubIndexOfRecordDataIntm_iBlockSizeOfRecordDataDalaLayer中增加RecvFaultRecord(.)RecvNormalRecord(.)5.2 伪代码1. 对故障记录数据,界面调用 g_DataLayer.RecvFaultRecord().g_DataLayer.RecvFaultRecord()的工作:-设置变量 Can.m_iRecvRecordStage = BEGIN还是设置事件 m_EventRec
18、vRecord ? 讨论-设置Can.m_iRecvRecordType=FAULT_RECORD对故障记录数据,界面调用 g_DataLayer.RecvNormalRecord().g_DataLayer.RecvNormalRecord()的工作:-设置变量 Can.m_iRecvRecordStage = BEGIN_RECORD还是设置事件 m_EventRecvRecord ? 讨论-设置Can.m_iRecvRecordType=NORMAL_RECOED初始化 m_byRecordData128 为0 和 m_byReacordData00 为0xFF。2. CanThread
19、 的代码在适当时刻检查 一系列变量(事件?),当检查到 m_iRecvRecord Stage= BEGIN_RECORD 时,做:OpenRecordFile()/伪代码后面提供-设置m_iRecvRecordType=NORMAL_RECOED初始化 m_byRecordData128 为0 和 m_byReacordData00 为0xFF。-设置 m_iReadRecordStage=SEND_SDO1-设置If(m_iReadRecordType=FAULT_RECORD)m_iIndexOfRecordData = g_PdasConfig.m_iFirstIndexOfFault
20、RecordElse (m_iReadRecordType=NORMAL_RECORD)m_iIndexOfRecord Data= g_PdasConfig.m_iFirstIndexOfNormalRecord-设置m_iSubIndexOfRecordData=0;m_iBlockSizeOfRecordData=128- 调用 SendNmi(0x80)函数该函数组织报文(00,02,80,02,00,00,00,00,00,00)然后调用VCI_Trasmit()3. 调用 SendSdo1()函数该函数组织报文SDO1IDDLDLByte0Byte1Byte2Byte3Byte4B
21、yte5Byte6Byte70x6020x080xA4m_iIndexm_iSubIndexm_iBlockSize000然后调用VCI_Transmit()-设置 m_iReadRecordStage=RECV_SDO24.CanThread等待接收报文Sdo2调用VCI_Receive(),超时时间用变量g_PdasConfig.CanRecvOnePacketTimeoutMsiState=ProcessPossibleTimeOut(.)/返回PACKET_TIMEOUT或DEVICE_FAULTIf(iState=PACKET_TIMEOUT)超时处理?Else if(iState=
22、DEVICE_FAULT)g_DataLayer.iDeviceStateDEVICE_CAN=DEVICE_FAULT故障处理?-如果准确,即收到的是SDO2IDDLDLByte0Byte1Byte2Byte3Byte4Byte5Byte6Byte70x5820x080xC6IndexSub-indexsize000000调用 SendSdo3()函数该函数组织报文SDO3IDDLDLByte0Byte1Byte2Byte3Byte4Byte5Byte6Byte70x6020x080xA3000000然后调用VCI_Transmit()发送设置 m_iReadRecordStage=RECV
23、_DATA5. 接收报文调用VCI_Receive(),超时时间用变量g_PdasConfig.CanRecvOnePacketTimeoutMsiState=ProcessPossibleTimeOut(.)/返回PACKET_TIMEOUT或DEVICE_FAULTIf(iState=PACKET_TIMEOUT)超时处理?Else if(iState=DEVICE_FAULT)g_DataLayer.iDeviceStateDEVICE_CAN=DEVICE_FAULT故障处理?-如果准确,即收到的是SDOIDDLByte0Byte1Byte2Byte3Byte4Byte5Byte6By
24、te7Bit7Bit6-010x5820x0800xxxxxxxxxxxxxx20x5820x0801xxxxxxxxxxxxxx30x5820x0802xxxxxxxxxxxxxxN-10x5820x080N-1xxxxxxxxxxxxxxN0x5820x081Nxxxxxxxxxxxxxx根据ID,DL,Byte0的Bit6-0位把Byte0到Byte7放入m_byRecordData.If(Byte0的Bit7为1)m_iReadRecordStage=SEND_SDO4iLastBlockNo=Byte0的Bit6-0的值否则继续56. 调用 SendSdo4()函数该函数组织报文SD
25、O4IDDLDLByte0Byte1Byte2Byte3Byte4Byte5Byte6Byte70x6020x080xA21blksize00000然后调用VCI_Transmit()-设置 m_iReadRecordStage=RECV_SDO57 CanThread等待接收报文Sdo5调用VCI_Receive(),超时时间用变量g_PdasConfig.CanRecvOnePacketTimeoutMsiState=ProcessPossibleTimeOut(.)/返回PACKET_TIMEOUT或DEVICE_FAULTIf(iState=PACKET_TIMEOUT)超时处理?El
26、se if(iState=DEVICE_FAULT)g_DataLayer.iDeviceStateDEVICE_CAN=DEVICE_FAULT故障处理?-如果准确,即收到的是SDO5IDDLDLByte0Byte1Byte2Byte3Byte4Byte5Byte6Byte70x5820x08byPacketCmdbyPacketCrc00000注:byPacketcmd=(0x065)|(7-size%7)2)|0x01),其中size表示所要上传的数据数量(字节数)。byPacketCrc为整个数据的CRC校验。/PC计算cmd和CRC(使用变量byMyCmd,byMyCrc)byMyC
27、md=CalCmd(&m_byRecordData,iLastBlockNo);byMyCrc=CalCrc(&m_byRecordData,iLastBlockNo);If(byMyCmd=byPacketCmd & byMyCrc=byPacketCrc)则file.write(m_byRecordBuf, LIMIT_BLOCK_NBYTES)+m_iSubIndexOfRecordData;If(m_iSubIndexOfRecord=0) m_iIndexOfRecordData+;设置 m_iRecvRecordStage=RECV_SDO68. 调用 SendSdo6()函数该函
28、数组织报文SDO6IDDLDLByte0Byte1Byte2Byte3Byte4Byte5Byte6Byte70x6020x080xA10000000然后调用VCI_Transmit()-设置 m_iRecvRecordStage=SEND_SDO1if(m_RecvRecordType=FAULT_RECORD)If(m_iIndexOfRecordData=g_PdasConfig.m_iIndexOfLastFaultRecord+1)m_iRecvRecordStage=COMPLETE_RECORDElse if(m_RecvRecordType=NORMAL_RECORD)If(m
29、_iIndexOfRecord=g_PdasConfig.m_iIndexOfLastFaultRecord+1)m_iRecvRecordStage=COMPLET_RECORTDIf (m_iRecvRecordStage=SEND_SDO1)goto step 3Else if(m_iRecvRecordStage=COMPLET_RECORD)Close file/finishedOpenRecordFile()CSaveDateSaveData;CString strFullPathFileName;If(m_iReadRecordType=FAULT_RECOED)strFileFormat= FAULT_RECORD_FILE_FORMAT;elsestrFileFormat= NORMAL_RECORD_FILE_FORMAT;strFullPathFileName=SaveData.GetFullPathFileName(RECORD_DATA_SUB_DIRECTORY_NAME,strFileFormat);char* pcName = FilePath.GetBuffer(FilePath.GetLength();CFile file(pcName,CFile :modeCreate|CFile:modeWrite);