Supported platforms: CODESYS 3.5

 

Sending J1939 Message with Fixed Interval

Description

This section describes how to define J1939 messages to be send with a fixed interval.

The CAN-message sending is independent of the application cycle (see also limitations below).

 

This example uses MultiTool Creator generated PGNs, but it is also possible to define PGNs manually.

 

Some engines require a certain message interval for TSC1 message. In some cases the software cycle time affects so that the TSC1 message is not sent in the correct time frame. In this case, the engine may not respond to the RPM (rounds per minute) request. In this case, use the interrupt functionality described here. The interrupt functionality sends the TSC1 message in the correct time frame regardless of the software cycle time.

 

 

Required:

 

 

Limitations:

  • Maximum number of the send messages is 10

  • Accuracy of the time is +-2 ms

  • Minimum time interval for sending is 2 ms, but it is recommended to use intervals > 10 ms

  • Used CAN channel must be initalized before initializating the time triggered messages.

  • Function block instance must be called at least every 100 ms, otherwise message sending is stopped

 

 

Example uses MultiTool Creator and code template so CAN channel is automatically initialized.

 

Creating 5050 project with PGN

1. Open MultiTool Creator, create 5050 C3.5 control unit and add Transmit PGN. This example uses TSC1 which is sent to engine in address 0.

 

   

 

 

2. Create CODESYS 3.5 project

 

Changing J1939 sending to use time triggered CAN sending

 

Definitions:

 

bInit: BOOL := TRUE;

tsc1CanApiHandler: EPEC_5050INT.CanApiTimeTriggeredMsg;

usedCobId: DWORD;

 

 

Code:

 

IF bInit THEN

bInit := FALSE;

(* Set TSC1 PGN *)

(* Time triggered CAN message supports only data length <= 8 *)

IF J1939_CAN2.Out.Engine.PGN_TSC1.DataLength <= 8 THEN

(* Set cycle time to 0ms to prevent message sending by J1939 server *)

J1939_CAN2.Out.Engine.PGN_TSC1.CycleTime := 0;

(* Set data length *)

tsc1CanApiHandler.i_Dlc := WORD_TO_BYTE(J1939_CAN2.Out.Engine.PGN_TSC1.DataLength);

 

(* Set init data for message *)

EPEC_J1939.J1939_BuildPGN(

i_pBasePGN := ADR(J1939_CAN2.Out.Engine.PGN_TSC1),

i_pDataBuffer := ADR(tsc1CanApiHandler.i_Data)

);

 

(* Init cobid for time triggered message *)

(* build used cobid from PGN *)

usedCobId:=BYTE_TO_DWORD(J1939_CAN2.Out.Engine.PGN_TSC1.Priority);

usedCobId:=SHL(usedCobId,1) OR 0;

usedCobId:=SHL(usedCobId,1) OR BYTE_TO_DWORD(J1939_CAN2.Out.Engine.PGN_TSC1.DataPage);

usedCobId:=SHL(usedCobId,8) OR WORD_TO_DWORD(SHR(J1939_CAN2.Out.Engine.PGN_TSC1.PGN_Number,8) AND 16#FF);

 

IF 16#F000 > J1939_CAN2.Out.Engine.PGN_TSC1.PGN_Number THEN

usedCobId:=SHL(usedCobId,8) OR BYTE_TO_DWORD(J1939_CAN2.Out.Engine.PGN_TSC1.Destination);

ELSE

usedCobId:=SHL(usedCobId,8) OR WORD_TO_DWORD(J1939_CAN2.Out.Engine.PGN_TSC1.PGN_Number AND 16#FF);

END_IF

 

usedCobId := SHL(usedCobId,8) OR BYTE_TO_DWORD(J1939_CAN2.Out.Engine.PGN_TSC1.SourceAddress);

usedCobId := usedCobId OR EPEC_CANVXD.MASK_29BIT; (* Set bit on which defines message as 29bit *)

 

(* Init time triggered message *)

tsc1CanApiHandler.InitCobId(

i_CanChannel := 1, (*CAN2*)

i_CobId := usedCobId,

i_TimeInterval := T#10MS

);

 

tsc1CanApiHandler.i_Enable := TRUE;

END_IF

ELSE

(* J1939 variables are accessed normally through J1939 structure*)

J1939_CAN2.Out.Engine.TSC1_EngRqedSpeed_SpeedLimit := WORD#1000 * 8; (*1000 rpm to raw value*)

 

(* Update PGN data to Api handler input*)

EPEC_J1939.J1939_BuildPGN(

i_pBasePGN := ADR(J1939_CAN2.Out.Engine.PGN_TSC1),

i_pDataBuffer := ADR(tsc1CanApiHandler.i_Data)

);

 

(* Function block instance must be called at least with 100ms interval *)

tsc1CanApiHandler();

END_IF

 

 

See also

 

 

Source file topic000985.htm

Last updated 21-Feb-2025