預備知識
1.熟悉CAN2.0B協議,及相關硬件驅動開發
2.熟悉SAE J1939協議<http://blog.csdn.net/xietongxueflyme/article/details/74276702/>
程序移植流程
移植示例(demo)
以下示例,對德國英飛凌XMC4500(MCU)芯片自帶的CAN模塊上移植J1939協議源代碼,代碼中can驅動函數,can的驅動結構體,可供移植參考
#ifndef __J1939_Config_H
#define __J1939_Config_H
#include "J1939.H"
#include "../UserApp/includes.h"//用戶,自己工程必要的聲明頭文件
/******************************J1939地址和標識符配*********************************/
//設備默認的地址(地址命名是有規定的,參考J1939的附錄B 地址和標識符的分配)
#define J1939_STARTING_ADDRESS 243
//如果聲明不爲0,表示我們的ECU(電子控制單元)支持網絡中申請的任意地址,(參考J1939的網絡層)
#define J1939_ARBITRARY_ADDRESS 0x00
#define J1939_INDUSTRY_GROUP 0
#define J1939_VEHICLE_INSTANCE 0
#define J1939_CA_NAME7 (J1939_ARBITRARY_ADDRESS | (J1939_INDUSTRY_GROUP << 4) | J1939_VEHICLE_INSTANCE)
#define J1939_VEHICLE_SYSTEM 0
#define J1939_CA_NAME6 (J1939_VEHICLE_SYSTEM << 1)
#define J1939_FUNCTION 0
#define J1939_CA_NAME5 J1939_FUNCTION
#define J1939_FUNCTION_INSTANCE 0
#define J1939_ECU_INSTANCE 0
#define J1939_CA_NAME4 ((J1939_FUNCTION_INSTANCE << 3) | J1939_ECU_INSTANCE)
#define J1939_MANUFACTURER_CODE 0
#define J1939_IDENTITY_NUMBER 50
#define J1939_CA_NAME3 (J1939_MANUFACTURER_CODE >> 3)
#define J1939_CA_NAME2 (((J1939_MANUFACTURER_CODE & 0x07) << 5) | (J1939_IDENTITY_NUMBER >> 16))
#define J1939_CA_NAME1 ((J1939_IDENTITY_NUMBER >> 8) & 0xFF)
#define J1939_CA_NAME0 (J1939_IDENTITY_NUMBER & 0xFF)
/******************************J1939功能配置******************************************/
//是否使用接受協議(對TP協議的支持,參考J1939-21)
#define J1939_ACCEPT_CMDADD J1939_FALSE
#define J1939_RX_QUEUE_SIZE 3
//當mcu來不及處理消息,接收消息列隊是否允許被新的消息覆蓋
#define J1939_OVERWRITE_RX_QUEUE J1939_FALSE
#define J1939_TX_QUEUE_SIZE 3
//當mcu來不及處理消息,發送消息列隊是否允許被新的消息覆蓋
#define J1939_OVERWRITE_TX_QUEUE J1939_FALSE
//是否使用輪詢模式(否則使用中斷模式)
#define J1939_POLL_ECAN J1939_TRUE
#define J1939_PRIORITIZED_INT J1939_TRUE
/******************************J1939移植配置函數******************************************/
#define Port_CAN_Transmit(MsgPtr) J1939_CAN_Transmit(MsgPtr)
#define Port_CAN_Receive(MsgPtr) J1939_CAN_Receive(MsgPtr)
#define Port_SetAddressFilter(Address) J1939_SetAddressFilter(Address)
#define Port_RXinterruptEnable() J1939_RXinterruptEnable()
#define Port_RXinterruptDisable() J1939_RXinterruptDisable()
#define Port_TXinterruptEnable() J1939_TXinterruptEnable()
#define Port_TXinterruptDisable() J1939_TXinterruptDisable()
/******************************J1939與CAN驅動接口函數************************************/
void J1939_SetAddressFilter(unsigned char Ps_Address)
{
CAN_NODE3_DEBUG.lmobj_ptr[0]->mo_ptr->can_id_mask &=0XFFFF00FF;
CAN_NODE3_DEBUG.lmobj_ptr[0]->mo_ptr->can_id_mask |= (Ps_Address<<8);
CAN_NODE_MO_Init(CAN_NODE3_DEBUG.lmobj_ptr[0]);
}
void ChangeGroupIDofLMO(const CAN_NODE_LMO_t *lmo_ptr,J1939_MESSAGE *MsgPtr)
{
int _i=0;
lmo_ptr->mo_ptr->can_identifier = 0;
for(_i=0;_i<4;_i++)
{
lmo_ptr->mo_ptr->can_identifier = (lmo_ptr->mo_ptr->can_identifier << 8) + MsgPtr->Array[_i];
}
// 在線修改lmo配置
CAN_NODE_MO_Init(lmo_ptr);
}
/*從MsgPtr加載到CAN自帶的結構體中*/
void J1939_CAN_Transmit(J1939_MESSAGE *MsgPtr)
{
CAN_NODE_LMO_t *lmo_ptr = CAN_NODE3_DEBUG.lmobj_ptr[1];
/*加載29位ID*/
ChangeGroupIDofLMO((const CAN_NODE_LMO_t * const)(CAN_NODE3_DEBUG.lmobj_ptr[1]),MsgPtr);
/*加載數據長度*/
lmo_ptr->mo_ptr->can_data_length = MsgPtr->Mxe.DataLength;
CAN_NODE_MO_Init(lmo_ptr);
/*加載數據*/
lmo_ptr->mo_ptr->can_data_byte[0] = MsgPtr->Mxe.Data[0];
lmo_ptr->mo_ptr->can_data_byte[1] = MsgPtr->Mxe.Data[1];
lmo_ptr->mo_ptr->can_data_byte[2] = MsgPtr->Mxe.Data[2];
lmo_ptr->mo_ptr->can_data_byte[3] = MsgPtr->Mxe.Data[3];
lmo_ptr->mo_ptr->can_data_byte[4] = MsgPtr->Mxe.Data[4];
lmo_ptr->mo_ptr->can_data_byte[5] = MsgPtr->Mxe.Data[5];
lmo_ptr->mo_ptr->can_data_byte[6] = MsgPtr->Mxe.Data[6];
lmo_ptr->mo_ptr->can_data_byte[7] = MsgPtr->Mxe.Data[7];
/*加載RTR*/
//你的代碼
//開始發送數據
(CAN_NODE_STATUS_t) CAN_NODE_MO_Transmit(lmo_ptr) ;
}
//將設備CAN中的數據取出,存入J1939_MESSAGE結構體中
int J1939_CAN_Receive(J1939_MESSAGE *MsgPtr)
{
uint32_t receive_status=0;
uint32_t _id=0;
receive_status = CAN_NODE_MO_GetStatus( ((CAN_NODE_t *)&CAN_NODE3_DEBUG)->lmobj_ptr[0]);
if ( receive_status & XMC_CAN_MO_STATUS_RX_PENDING) //XMC_CAN_MO_STATUS_NEW_DATA
{
// 清除接受標識位
CAN_NODE_MO_ClearStatus(((CAN_NODE_t *)&CAN_NODE3_DEBUG)->lmobj_ptr[0],XMC_CAN_MO_RESET_STATUS_RX_PENDING);
// 讀取數據
CAN_NODE_MO_Receive( ((CAN_NODE_t *)&CAN_NODE3_DEBUG)->lmobj_ptr[0]);
//將29位標誌位(can_identifier)寫入J1939的結構中
_id = ((CAN_NODE_t *)&CAN_NODE3_DEBUG)->lmobj_ptr[0]->mo_ptr->can_identifier;
MsgPtr->Array[0] = _id>>(8*3);
MsgPtr->Array[1] = _id>>(8*2);
MsgPtr->Array[2] = _id>>(8*1);
MsgPtr->Array[3] = _id>>(8*0);
//讀取數據長度
MsgPtr->Mxe.DataLength = ((CAN_NODE_t *)&CAN_NODE3_DEBUG)->lmobj_ptr[0]->mo_ptr->can_data_length;
if (MsgPtr->Mxe.DataLength > 8)
MsgPtr->Mxe.DataLength = 8;
//讀取數據
MsgPtr->Mxe.Data[0] = ((CAN_NODE_t *)&CAN_NODE3_DEBUG)->lmobj_ptr[0]->mo_ptr->can_data_byte[0];
MsgPtr->Mxe.Data[1] = ((CAN_NODE_t *)&CAN_NODE3_DEBUG)->lmobj_ptr[0]->mo_ptr->can_data_byte[1];
MsgPtr->Mxe.Data[2] = ((CAN_NODE_t *)&CAN_NODE3_DEBUG)->lmobj_ptr[0]->mo_ptr->can_data_byte[2];
MsgPtr->Mxe.Data[3] = ((CAN_NODE_t *)&CAN_NODE3_DEBUG)->lmobj_ptr[0]->mo_ptr->can_data_byte[3];
MsgPtr->Mxe.Data[4] = ((CAN_NODE_t *)&CAN_NODE3_DEBUG)->lmobj_ptr[0]->mo_ptr->can_data_byte[4];
MsgPtr->Mxe.Data[5] = ((CAN_NODE_t *)&CAN_NODE3_DEBUG)->lmobj_ptr[0]->mo_ptr->can_data_byte[5];
MsgPtr->Mxe.Data[6] = ((CAN_NODE_t *)&CAN_NODE3_DEBUG)->lmobj_ptr[0]->mo_ptr->can_data_byte[6];
MsgPtr->Mxe.Data[7] = ((CAN_NODE_t *)&CAN_NODE3_DEBUG)->lmobj_ptr[0]->mo_ptr->can_data_byte[7];
return 1;
}else
{
return 0;//沒有消息
}
}
void J1939_RXinterruptEnable()
{
INTERRUPT_Enable(&CAN_RInterrupt_DEBUG);
}
void J1939_RXinterruptDisable()
{
INTERRUPT_Disable(&CAN_RInterrupt_DEBUG);
}
void J1939_TXinterruptEnable()
{
;
}
void J1939_TXinterruptDisable()
{
;
}
#endif
備註
J1939與CAN2.0B驅動接口函數在後面,將逐一的分析。