Gestire motore con protocollo CAN SAE J1939

La specifica SAE J1939 descrive la comunicazione CAN nei veicoli per lo scambio di informazioni con la centralina elettronica, l’obiettivo è definire un protocollo di comunicazione standard indipendentemente dai fornitori di componenti. Oggi il SAE J1939 è presente in tutti i veicoli, anche l’auto che guidiamo ogni giorno ha al suo interno uno o più bus CAN per lo scambio dati tra i vari sensori/attuatori di bordo, un bus CAN per diagnostica è disponibile sulla presa OBD presente  su ogni automobile.

I nostri sistemi SlimLine grazie alla alimentazione da 10÷30 Vdc ed al range esteso di temperatura trovano impiego in mezzi mobili, in macchine operatrici ed in imbarcazioni, tutte applicazioni in cui è presente un motore endotermico. Nella necessità di doversi interfacciare con il motore per gestire le automazioni, quale modo migliore ed economico del bus CAN, visto che ormai tutti i modermi motori endotermici prevedono una uscita CAN con protocollo SAE J1939.

L’esigenza

Un nostro Cliente su una grossa imbarcazione da diporto ha realizzato tutte le automazioni di bordo con i nostri sistemi SlimLine, l’interconnessione tra i sistemi in rete Ethernet ha ridotto notevolmente l’impiego di cavi a vantaggio del peso e di conseguenza dei consumi. Per comandare i servizi di bordo, verricelli, salpancore, bow thrusters, ecc. viene utilizzata una pompa idraulica comandata da un motore diesel da 100 CV.  La necessità era di conoscere i giri del motore, il carico e di gestirne l’acceleratore per adeguare i giri alle variabili condizioni di carico.

Connessa la porta CAN del modulo CPU all’interfaccia SAE J1939 del motore, grazie a chiamate alle funzioni di gestione del protocollo CAN si è realizzata la lettura di tutti i parametri di funzionamento del motore.

Utilizzo SlimLine su yacht Capricorn

Spionaggio dati bus

Per identificare una determinata grandezza da acquisire si cerca nella lista PGN (Parameter Group Number) la grandezza desiderata. Identificato il numero si inserisce da debug nel parametro SpyTrigger, nella console di spionaggio verrà visualizzato il valore degli 8 bytes del PGN al cui interno si troverà la grandezza desiderata, vedi specifiche SAE.

LogicLab (Ptp170, SAEJ1939Spy)
PROGRAM SAEJ1939Spy
VAR
    i : UDINT; (* Auxiliary variable *)
    k : UDINT; (* Auxiliary variable *)
    j : UDINT; (* Auxiliary variable *)
    Sa : USINT; (* Source address *)
    PGN : UINT; (* Parameter Group Nr *)
    PED : USINT; (* Priority, Extended data page, Data page *)
    SpyTrigger : UINT; (* Spy trigger *)
    SBf : STRING[ 128 ]; (* Auxiliary buffer *)
    CANMsg : SYSCANMESSAGE; (* CAN message *)
END_VAR

// *****************************************************************************
// PROGRAM "SAEJ1939Spy"
// *****************************************************************************
// Spies CAN SAE J1939 datagrams.
// -----------------------------------------------------------------------------

    // -------------------------------------------------------------------------
    // INITIALIZATIONS
    // -------------------------------------------------------------------------
    // At first loop initialize CAN interface. The SAEJ1939 uses a 29-bit ID.

    IF (SysFirstLoop) THEN
        i:=SysCANSetMode(CAN_SPEED#CAN_250KBIT, 16#80000000, 16#00000000); //Accept only 29 bits messages
    END_IF;

    // -------------------------------------------------------------------------
    // SAEJ1939 RECEIVE
    // -------------------------------------------------------------------------
    // Checks if messages are been received. The messages are stored in a buffer
    // so to read all the messages received is executed a loop.

    FOR j:=0 TO 16 DO
        IF NOT(SysIsCANRxTxAv(FALSE)) THEN EXIT; END_IF; //No more messages

        // Read the message and transfer it to "CANMsg".

        IF NOT(SysCANRxMsg(16#00000000, 16#80000000, ADR(CANMsg))) THEN EXIT; END_IF;

        // The 29-bit "MsgID" SAE J1939 datagram have the following meanings.
        //
        // |- [PED]--------------------+-[PGN]------------------+-[SA]---------+ 
        // |           |       |       |                        |              |
        // |  Priority |  EDp  |  Dp   |Parameter Group Nr (PGN)|Source address|
        // |           |       |       |                        |              |
        // +-[3 Bits]--+[1 Bit]+[1 Bit]+-[16 Bits]--------------+-[8 Bits------+

        Sa:=TO_USINT(CANMsg.MsgID AND 16#FF); //Source address
        PGN:=TO_UINT((CANMsg.MsgID/16#100) AND 16#FFFF); //Parameter Group Nr
        PED:=TO_USINT((CANMsg.MsgID/16#1000000) AND 16#FF); //Priority, Extended data page, Data page

        // Message trigger. Setings by debug the value of "SpyTrigger" it's
        // possible to trigger PGN message.

        IF (PGN = SpyTrigger) THEN

            i:=SysVsnprintf(ADR(SBf), SIZEOF(SBf), ADR('PED:%02X'), USINT_TYPE, ADR(PED));
            i:=SysCVsnprintf(ADR(SBf), SIZEOF(SBf), ADR(', PGN:%04X'), UINT_TYPE, ADR(PGN));
            i:=SysCVsnprintf(ADR(SBf), SIZEOF(SBf), ADR(', Sa:%02X'), USINT_TYPE, ADR(Sa));

            FOR k:=0 TO CANMsg.Length-1 DO
                i:=SysCVsnprintf(ADR(SBf), SIZEOF(SBf), ADR(' %02X'), USINT_TYPE, ADR(CANMsg.Data[j]));
            END_FOR;

            // Spy the message data.

            i:=SysWrSpyData(SPY_ASCII, 0, 16#00000001, ADR('Rx'), ADR(SBf));
        END_IF;
    END_FOR;

// [End of file]

Programma Gestione motore

Viene impostata l’interfaccia CAN per ricevere tutti i messaggi, i messaggi ricevuti sono memorizzati in un buffer, la  funzione SysCANRxMsg ad ogni chiamata, se presente, legge un messaggio dal buffer e lo ritorna cancellandolo. In questo modo iterando sulla funzione è possibile acquisire tutti i messaggi nell’ordine con il quale sono stati ricevuti (FIFO). Ogni messaggio può contenere oltre ai 29 bits di intestazione fino a 8 bytes di dati, i dati assumono diverso significato in funzione del valore del campo PGN. Se viene definito da debug il valore di Speed, viene gestito l’invio del comando TSC1 che imposta la velocità di rotazione del motore (Se il motore lo gestisce).

LogicLab (Ptp170, SAEJ1939Mng)
PROGRAM SAEJ1939Mng
VAR
    i : UDINT; (* Auxiliary variable *)
    Sa : USINT; (* Source address *)
    PGN : UINT; (* Parameter Group Nr *)
    PED : USINT; (* Priority, Extended data page, Data page *)
    TimeBf : UDINT; (* Time buffer (uS) *)
    ESpeed : REAL; (* Engine speed (rpm) *)
    Throttle : REAL; (* Throttle position (%) *)
    Speed : REAL; (* Engine speed to set (RPM) *)
    CANMsg : SYSCANMESSAGE; (* CAN message *)
END_VAR

// *****************************************************************************
// PROGRAM "SAEJ1939Mng"
// *****************************************************************************
// Sends TSC1 command and receives CAN SAE J1939 datagrams and decodes them.
// -----------------------------------------------------------------------------

    // -------------------------------------------------------------------------
    // INITIALIZATIONS
    // -------------------------------------------------------------------------
    // At first loop initialize CAN interface. The SAEJ1939 uses a 29-bit ID.

    IF (SysFirstLoop) THEN
        i:=SysCANSetMode(CAN_SPEED#CAN_250KBIT, 16#80000000, 16#00000000); //Accept only 29 bits messages
    END_IF;

    // -------------------------------------------------------------------------
    // SEND TSC1 TORQUE/SPEED CONTROL 1
    // -------------------------------------------------------------------------
    // The TSC1 command allow to command the torque or the speed on the motor.
    // It must be sent every 10mS, in this example it's sent the speed control.

    IF ((Speed > 0.0) AND (SysIsCANRxTxAv(TRUE))) THEN
        IF ((SysGetSysTime(TRUE)-TimeBf) >= 10000) THEN
            TimeBf:=SysGetSysTime(TRUE); //Time buffer (uS)

            // Prepare the TSC1 message and send it.

            CANMsg.MsgID:=16#8C000003; //Message ID 29 Bit
            CANMsg.RmReq:=FALSE; //eFALSE:Data frame, eTRUE:Remote request
            CANMsg.Length:=8; //Data length

            // Calculate the speed value to set, every bit is 0.125 RPM.

            i:=TO_UDINT(Speed*8.0); //Speed to set (Bits)

            // Set message the 8 bits.

            CANMsg.Data[0]:=16#01; //Speed control
            CANMsg.Data[1]:=TO_BYTE(i); //Speed LSB
            CANMsg.Data[2]:=TO_BYTE(i/16#100); //Speed MSB
            CANMsg.Data[3]:=16#FF;
            CANMsg.Data[4]:=16#FF;
            CANMsg.Data[5]:=16#FF;
            CANMsg.Data[6]:=16#FF;
            CANMsg.Data[7]:=16#FF;
            i:=SysCANTxMsg(ADR(CANMsg)); //Send the message
        END_IF;
    END_IF;

    // -------------------------------------------------------------------------
    // SAEJ1939 RECEIVE
    // -------------------------------------------------------------------------
    // Checks if messages are been received. The messages are stored in a buffer
    // so to read all the messages received is executed a loop.

    FOR i:=0 TO 16 DO
        IF NOT(SysIsCANRxTxAv(FALSE)) THEN EXIT; END_IF; //No more messages

        // Read the message and transfer it to "CANMsg".

        IF NOT(SysCANRxMsg(16#00000000, 16#80000000, ADR(CANMsg))) THEN EXIT; END_IF;

        // The 29-bit "MsgID" SAE J1939 datagram have the following meanings.
        //
        // |- [PED]--------------------+-[PGN]------------------+-[SA]---------+ 
        // |  Priority |  EDp  |  Dp   |Parameter Group Nr (PGN)|Source address|
        // |           |       |       |                        |              |
        // +-[3 Bits]--+[1 Bit]+[1 Bit]+-[16 Bits]--------------+-[8 Bits------+

        Sa:=TO_USINT(CANMsg.MsgID AND 16#FF); //Source address
        PGN:=TO_UINT((CANMsg.MsgID/16#100) AND 16#FFFF); //Parameter Group Nr
        PED:=TO_USINT((CANMsg.MsgID/16#1000000) AND 16#FF); //Priority, Extended data page, Data page

        // Message trigger.

        CASE (PGN) OF

            // -----------------------------------------------------------------
            // PGN=6143 Throttle position.

            61443:
            Throttle:=TO_REAL(CANMsg.Data[2-1])*0.4; //Throttle position (%)

            // -----------------------------------------------------------------
            // PGN=6144 engine speed acquisition (0.125rpm/bit).

            61444:
            ESpeed:=TO_REAL(CANMsg.Data[5-1])*256.0;
            ESpeed:=ESpeed+TO_REAL(CANMsg.Data[4-1]);
            ESpeed:=ESpeed*0.125; //Engine speed (rpm)
        END_CASE;
    END_FOR;

// [End of file]
Was this article helpful?