SAE J1939 协议源代码分析(三)-程序应用分析

来源:互联网 发布:少年ma的奇幻 知乎 编辑:程序博客网 时间:2024/06/05 20:49

预备知识

1.熟悉CAN2.0B协议,及相关硬件驱动开发
2.熟悉SAE J1939协议http://blog.csdn.net/xietongxueflyme/article/details/74276702/

J1939协议栈的功能

1.消息发送
2.消息广播
3.消息请求
4.消息确认,响应
5.群功能
6.专用传输A
7.专用传输B
8.地址声明竞争
9.远程地址配置
10.自动重新分配地址
11.多帧传输协议TP

接口函数简介

函数名 函数描述 J1939_Initialization (BOOL); 初始化一些全局变量,向总线声明地址(默认地址) J1939_DequeueMessage (J1939_MESSAGE *MsgPtr) 从接受列队中复制接收消息到传入的内存中(*MsgPtr) J1939_EnqueueMessage (J1939_MESSAGE *MsgPtr) 将传入的消息(*MsgPtr),复制到发送列队中 J1939_Poll (unsigned long ElapsedTime) 检查列队(轮询模式),提供小的延时,检查地址竞争 J1939_ISR (void) CAN中断(发送和接受,can错误)函数入口 J1939_TP_TX_Message(unsigned int PGN,unsigned char SA,char *data,unsigned short data_num) 当我们需要发送字节数大于8字节的数据,调用这个函数启用TP协议将数据发送出去 J1939_TP_RX_Message(char *data,unsigned short data_num) 接收网络中TP协议的数据,并将数据存入data缓存

协议接口demo

API –> J1939_Initialization (BOOL);【初始化一些全局变量,向总线声明地址(默认地址)】

int main(){    //初始化can驱动    init_can();    //初始化J1939协议栈    J1939_Initialization( TRUE );    //等待地址超时    while (J1939_Flags.WaitingForAddressClaimContention)        J1939_Poll(5);    //运行到这里,说明地址已经声明好在系统总线上(设备已挂载到总线上)    while(1)    {        ;    }}

API –> J1939_EnqueueMessage (J1939_MESSAGE *MsgPtr);【将传入的消息(*MsgPtr),复制到发送列队中】

void main( void ){    J1939_MESSAGE Msg;    /*在CAN驱动初始化中,请配置好滤波,说明参考移植函数(滤波函数)*/    /* can_init(); */    J1939_Initialization( TRUE );    //等待地址超时    while (J1939_Flags.WaitingForAddressClaimContention)        J1939_Poll(5);    //运行到这里,说明地址已经声明好(设备已挂载到总线上)    while (1)    {    /********发送数据(参考J1939的ID组成填充下面)***********/        Msg.Mxe.DataPage = 0;        Msg.Mxe.Priority = J1939_CONTROL_PRIORITY;        Msg.Mxe.DestinationAddress = 0x0f;        Msg.Mxe.DataLength = 8;        Msg.Mxe.PDUFormat = 0xfe;        Msg.Mxe.Data[0] = 1;        Msg.Mxe.Data[1] = 2;        Msg.Mxe.Data[2] = 3;        Msg.Mxe.Data[3] = 4;        Msg.Mxe.Data[4] = 5;        Msg.Mxe.Data[5] = 6;        Msg.Mxe.Data[6] = 7;        Msg.Mxe.Data[7] = 8;        while (J1939_EnqueueMessage( &Msg ) != RC_SUCCESS)            J1939_Poll(5);        J1939_Poll(20);    }}

API –> J1939_DequeueMessage (J1939_MESSAGE *MsgPtr);【从接受列队中复制接收消息到传入的内存中(*MsgPtr)】

int main(){    J1939_MESSAGE Msg;    /*在CAN驱动初始化中,请配置好滤波,说明参考移植函数(滤波函数)*/    /* can_init(); */    J1939_Initialization( TRUE );    //等待地址超时    while (J1939_Flags.WaitingForAddressClaimContention)        J1939_Poll(5);    //运行到这里,说明地址已经声明好(设备已挂载到总线上)    while(1)    {       /***********************处理接受数据*************************/        while (RXQueueCount > 0)        {            J1939_DequeueMessage( &Msg );            if (Msg.PDUFormat == 0x01)                //你的功能码;            else if (Msg.PDUFormat == 0x02)                //你的功能码;        }        J1939_Poll(20);        /********************j1939心跳函数*************************/        J1939_Poll(20);    }}

API –>J1939_TP_TX_Message(unsigned int PGN,unsigned char SA,char *data,unsigned short data_num)【当我们需要发送字节数大于8字节的数据,调用这个函数启用TP协议将数据发送出去】

void main( void ){    char data[100] = {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7};    /*在CAN驱动初始化中,请配置好滤波,说明参考移植函数(滤波函数)*/    /* can_init(); */    J1939_Initialization( TRUE );    // 等待地址声明超时    while (J1939_Flags.WaitingForAddressClaimContention)          J1939_Poll(5);    //地址已经声明好(设备已挂载到总线上)    while(1)    {        /*发送一个长帧 data*/        while(J1939_TP_TX_Message(65259,0XF1,data,sizeof(data))==RC_SUCCESS)              J1939_Poll(5);        osDelay(10);         J1939_Poll(20);    }}

API –>J1939_TP_RX_Message(char *data,unsigned short data_num)【接收网络中TP协议的数据,并将数据存入data缓存】

void main( void ){    //建议初始化缓存大小用  J1939_TP_MAX_MESSAGE_LENGTH    char data[J1939_TP_MAX_MESSAGE_LENGTH] = {0};    /*在CAN驱动初始化中,请配置好滤波,说明参考移植函数(滤波函数)*/    /* can_init(); */    J1939_Initialization( TRUE );    // 等待地址声明超时    while (J1939_Flags.WaitingForAddressClaimContention)        J1939_Poll(5);    //地址已经声明好(设备已挂载到总线上)    //最简单的示例    while(1)    {        /*读取TP接受数据*/        while(J1939_TP_RX_Message( data,sizeof(data))==RC_SUCCESS)            J1939_Poll(5);        osDelay(1); //基本单位为10ms * 1;        J1939_Poll(20);    }    //完整的接受逻辑示例    while(1)    {        /*判断有没有接受的TP到来*/        if(TP_RX_MSG.tp_rx_msg.byte_count >0)        {            /*判断数据是否是我们想要的PGN*/            if(TP_RX_MSG.tp_rx_msg.PGN == 我们想要的PGN)            {                while(J1939_TP_RX_Message( data,sizeof(data))==RC_SUCCESS)                J1939_Poll(5);            }        }        osDelay(1); //基本单位为10ms * 1;        J1939_Poll(20);    }}

示例1—轮询模式

备注:接受处理,不是标准的接受处理。这里只是测试接受

void main( void ){    J1939_MESSAGE Msg;    can_init();    J1939_Initialization( TRUE );    //等待地址超时    while (J1939_Flags.WaitingForAddressClaimContention)        J1939_Poll(5);    //设备确认总线上没有,竞争地址的设备存在    while (1)    {    /***********************发送数据***************************/        Msg.Mxe.DataPage                = 0;        Msg.Mxe.Priority                = J1939_CONTROL_PRIORITY;        Msg.Mxe.DestinationAddress      = OTHER_NODE;        Msg.Mxe.DataLength              = 8;        Msg.Mxe.PDUFormat               = 0xfe;        Msg.Mxe.Data[0]         = 0xFF;        Msg.Mxe.Data[1]         = 0xFF;        Msg.Mxe.Data[2]         = 0xFF;        Msg.Mxe.Data[3]         = 0xFF;        Msg.Mxe.Data[4]         = 0xFF;        Msg.Mxe.Data[5]         = 0xFF;        Msg.Mxe.Data[6]         = 0xFF;        Msg.Mxe.Data[7]         = 0xFF;         while (J1939_EnqueueMessage( &Msg ) != RC_SUCCESS)            J1939_Poll(5);     /***********************处理接受数据*************************/        while (RXQueueCount > 0)        {            J1939_DequeueMessage( &Msg );            if (Msg.Mxe.PDUFormat == 0x01)                //你的功能码;            else if (Msg.Mxe.PDUFormat == 0x02)                //你的功能码;        }        J1939_Poll(20);    }}

示例2—中断模式

void main(){    can_init();    J1939_Initialization( TRUE );    //等待地址超时    while (J1939_Flags.WaitingForAddressClaimContention)        J1939_Poll(5);    //设备确认总线上没有,竞争地址的设备存在    while (1)    {        //判断接受列队中,存在多少个接受消息(RXQueueCountwhile (RXQueueCount > 0)        {            //读取接受列队中的数据到Msg (出队)            J1939_DequeueMessage( &Msg );            /*判断是否是数据请求帧*/            if (Msg.Mxe.PDUFormat == J1939_PF_REQUEST)            {                //判断参数群是否被本设备支持                if ((Msg.Mxe.Data[0] == J1939_PGN0_REQ_ENGINE_SPEED) &&                     (Msg.Mxe.Data[1] == J1939_PGN1_REQ_ENGINE_SPEED) &&                     (Msg.Mxe.Data[2] == J1939_PGN2_REQ_ENGINE_SPEED))                {                    if (某种原因不能响应)                    {                        /*********发送不能响应(参考J1939-21)*************/                        Msg.Mxe.Priority            = J1939_ACK_PRIORITY;                        Msg.Mxe.DataPage            = 0;                        Msg.Mxe.PDUFormat           = J1939_PF_ACKNOWLEDGMENT;                        Msg.Mxe.DestinationAddress  = Msg.SourceAddress;                        Msg.Mxe.DataLength          = 8;                        Msg.Mxe.Data[0]         = J1939_NACK_CONTROL_BYTE;                        Msg.Mxe.Data[1]         = 0xFF;                        Msg.Mxe.Data[2]         = 0xFF;                        Msg.Mxe.Data[3]         = 0xFF;                        Msg.Mxe.Data[4]         = 0xFF;                        Msg.Mxe.Data[5]         = J1939_PGN0_REQ_ENGINE_SPEED;                        Msg.Mxe.Data[6]         = J1939_PGN1_REQ_ENGINE_SPEED;                        Msg.Mxe.Data[7]         = J1939_PGN2_REQ_ENGINE_SPEED;                    }                    else                    {                    /*******************上传相关的参数群*****************/                        Msg.Mxe.Priority    = J1939_INFO_PRIORITY;                        Msg.Mxe.DataPage    = J1939_PGN2_REQ_ENGINE_SPEED & 0x01;                        Msg.Mxe.PDUFormat   = J1939_PGN1_REQ_ENGINE_SPEED;                        Msg.Mxe.GroupExtension = J1939_PGN0_REQ_ENGINE_SPEED;                        Msg.Mxe.DataLength  = 1;                        Msg.Mxe.Data[0]     = EngineSpeed;                    }                    while (J1939_EnqueueMessage( &Msg ) != RC_SUCCESS);                }            }        }    }}
原创粉丝点击