SysSerialPort, manage serial port

List

Questa pagina fa parte del Manuale Programmazione IEC 61131-3. Vai all indice.

Questo blocco funzione gestisce la comunicazione su porta seriale, occorre definire in COM la porta da gestire fornendo tutti i parametri di configurazione. Se non sono definiti parametri la porta verrà impostata di default a 19200, e, 8, 1, DTR_AUTO_WO_TIMES.

Attivando il comando Open la porta viene aperta se non ci sono problemi viene attivato Opened e sull’uscita File viene ritornato lo stream da utilizzarsi per lo scambio dati sulla porta. Se ci sono errori nei parametri o con la porta definita viene generato Fault.

Per aggiungere porte seriali ai nostri moduli CPU è possibile utilizzare convertitori USB/Seriale sui moduli basati su Linux e convertitori Ethernet/Seriale sui moduli ARM e Cortex, vedi articolo.

LogicLab (Ptp116, ST_SerialDataReceive) Semplice protocollo seriale

Riportiamo un programma che gestisce un semplice protocollo seriale, viene ricevuta una stringa con 2 valori REAL. I valori ricevuti sono decodificati e ritornati in risposta.

PROGRAM ST_SerialDataReceive
VAR
    i : UDINT; (* Auxiliary variable *)
    Ch : USINT; (* Rx character *)
    ErrorNr : USINT; (* Error number *)
    CaseNr : USINT; (* Program case *)
    RxCtr : USINT; (* Rx data counter *)
    Ptr : PVOID; (* Auxiliary buffer *)
    Value : ARRAY[0..1] OF REAL; (* Value array *)
    TimeBf : ARRAY[0..1] OF UDINT; (* Time buffer (mS) *)
    SpyBuffer : STRING[ 64 ]; (* Spy buffer *)
    RxTxBuf : STRING[ 128 ]; (* Rx/Tx data buffer *)
    Sp : SysSerialPort; (* Serial port management *)
END_VAR

// *****************************************************************************
// PROGRAM "ST_SerialDataReceive"
// *****************************************************************************
// Receives data from serial port and manage them.
// -----------------------------------------------------------------------------

    // -------------------------------------------------------------------------
    // INITIALIZATION
    // -------------------------------------------------------------------------
    // Configure serial port.

    IF (SysFirstLoop) THEN
        Sp.COM:=ADR('COM0'); //COM port definition
//      Sp.COM:=ADR('/dev/ttyAMA0'); //COM port definition
//      Sp.COM:=ADR('/dev/ttyUSB0'); //COM port definition
        Sp.Baudrate:=19200; //Baudrate
        Sp.Parity:='E'; //Parity
        Sp.DataBits:=8; //Data bits
        Sp.StopBits:=1; //Stop bits
        Sp.DTRManagement:=DTR_AUTO_WO_TIMES; //DTR management
        Sp.DTRComplement:=FALSE; //DTR complement
        Sp.EchoFlush:=FALSE; //Received echo flush
        Sp.DTROnTime:=0; //DTR On time delay (mS)
        Sp.DTROffTime:=0; //DTR Off time delay (mS)
        Sp.FlushTm:=0; //Flush time (mS)
        Sp.RxSize:=0; //Rx buffer size
        Sp.TxSize:=0; //Tx buffer size
    END_IF;

    // -------------------------------------------------------------------------
    // MANAGE THE SERIAL PORT
    // -------------------------------------------------------------------------
    // Manage the serial port.

    Sp(Open:=TRUE); //Serial port management
    IF NOT(Sp.Opened) THEN CaseNr:=0; RETURN; END_IF;

    // -------------------------------------------------------------------------
    // EXECUTION ERROR REPORT
    // -------------------------------------------------------------------------
    // On execution error the reception loop is ended and the error number is
    // reported on spy console

    IF (ErrorNr <> 0) THEN
        i:=SysVsnprintf(ADR(SpyBuffer), SIZEOF(SpyBuffer), ADR('Error:%d'), USINT_TYPE, ADR(ErrorNr));
        i:=SysCVsnprintf(ADR(SpyBuffer), SIZEOF(SpyBuffer), ADR(', On case:%d'), USINT_TYPE, ADR(CaseNr));
        i:=SysWrSpyData(SPY_ASCII, 0, 16#10000000, ADR('SerialDataReceive:Er'), ADR(SpyBuffer));
        ErrorNr:=0; //Error number
        CaseNr:=0; //Program case
    END_IF;

    // -------------------------------------------------------------------------
    // CASE LOOP
    // -------------------------------------------------------------------------
    // If reception starts it must be ended in a defined time.

    IF (CaseNr = 0) THEN TimeBf[0]:=SysTimeGetMs(); END_IF;
    IF ((SysTimeGetMs()-TimeBf[0]) > TO_UDINT(T#1s)) THEN
        ErrorNr:=10; //Error number
        RETURN;
    END_IF;

    // -------------------------------------------------------------------------
    // CASE MANAGEMENRT
    // -------------------------------------------------------------------------
    // Program cases.

    CASE (CaseNr) OF

        // ---------------------------------------------------------------------
        // WAITS RECEPTION START
        // ---------------------------------------------------------------------
        // Waits until a first character is been received.

        0:
        IF NOT(TO_BOOL(SysFGetIChars(Sp.File))) THEN RETURN; END_IF;
        i:=Sysmemset(ADR(RxTxBuf), 0, SIZEOF(RxTxBuf)); //Clear data buffer
        Ch:=TO_USINT(Sysfgetc(Sp.File)); //Rx character

        // In the example is received a plain string is managed, but if the
        // string starts with a defined character, it must be waited here.

        // IF (Ch <> 16#02) THEN RETURN; END_IF;

        // Initialize the reception.

        i:=eSetBYTE(ADR(RxTxBuf), Ch); //Store character in buffer
        RxCtr:=1; //Rx data counter
        CaseNr:=CaseNr+1; //Program case

        // ---------------------------------------------------------------------
        // In some cases reception ends when no characters has been received for
        // a defined time.

        1:
        IF NOT TO_BOOL(SysFGetIChars(Sp.File)) THEN RETURN; END_IF;
        // IF ((SysTimeGetMs()-TimeBf[1]) > TO_UDINT(T#100ms)) THEN CaseNr:=10; RETURN; END_IF;

        // Here the string is received.
        
        WHILE TO_BOOL(SysFGetIChars(Sp.File)) DO
            TimeBf[1]:=SysTimeGetMs(); //Time buffer (mS)

            Ch:=TO_USINT(Sysfgetc(Sp.File)); //Rx character
            i:=eSetBYTE(ADR(RxTxBuf)+RxCtr, Ch); //Store character in buffer
            RxCtr:=RxCtr+1; //Rx data counter

            // If the string end with a defined character, it must be verified.
            // Plain string usually terminates with a .

            IF (Ch = 16#0D) THEN CaseNr:=10; RETURN; END_IF;

            // If a defined number of character is expected, when has been
            // received reception ends 

            // IF (RxTxCtr = 15) THEN CaseNr:=10; RETURN; END_IF;

            // Check if string is longer than defined buffer.             

            IF (RxCtr >= SIZEOF(RxTxBuf)) THEN
                ErrorNr:=20; //Error number
                RETURN;
            END_IF;
        END_WHILE;

        // -----------------------------------------------------------------
        // Here the string has been received, it's sent to spy console.

        10:
        i:=SysWrSpyData(SPY_ASCHEX, 0, 16#00000001, ADR('SerialDataReceive:Rx'), ADR(RxTxBuf));

        // Assuming string as an array of numbers here they are decoded.
        // "Value:10.23, Value:456.56..."

        Ptr:=SysStrFind(ADR(RxTxBuf), ADR('Value:'), FIND_GET_END);
        IF (Ptr = eNULL) THEN ErrorNr:=20; RETURN; END_IF;
        IF NOT(SysVsscanf(Ptr, ADR('%f'), REAL_TYPE, ADR(Value[0]))) THEN ErrorNr:=21; RETURN; END_IF;

        Ptr:=SysStrFind(Ptr, ADR('Value:'), FIND_GET_END);
        IF (Ptr = eNULL) THEN ErrorNr:=30; RETURN; END_IF;
        IF NOT(SysVsscanf(Ptr, ADR('%f'), REAL_TYPE, ADR(Value[1]))) THEN ErrorNr:=31; RETURN; END_IF;
        CaseNr:=CaseNr+1; //Program case

        // -----------------------------------------------------------------
        // Waits for space on tx buffer

        11:
        IF (TO_UDINT(SysFGetOSpace(Sp.File)) <> SysFGetOBfSize(Sp.File)) THEN RETURN; END_IF;

        // Printout the received values.

        i:=SysVsnprintf(ADR(RxTxBuf), SIZEOF(RxTxBuf), ADR('Values [0]:%5.2f'), REAL_TYPE, ADR(Value[0]));
        i:=SysCVsnprintf(ADR(RxTxBuf), SIZEOF(RxTxBuf), ADR(', [1]:%6.2f$r$n'), REAL_TYPE, ADR(Value[1]));
        i:=Sysfwrite(ADR(RxTxBuf), TO_INT(Sysstrlen(ADR(RxTxBuf))), 1, Sp.File);
        CaseNr:=0; //Program case
    END_CASE;

// [End of file]
Information Circle

Blocco funzione

CODESYS: eCDSXUnified12Lib

LogicLab: eLLabXUnified12Lib

Descrizione

Open (BOOL) Comando apertura porta seriale.
COM (@STRING) Definizione della porta COM da utilizzare (Su CODESYS diventa pCOM).
Baudrate (UDINT) Valore di baud rate porta seriale (da 300 a 115200 baud).
Parity (STRING[1]) Tipo di parità, valori possibili “E” pari, “O” dispari, “N” nessuna.
DataBits (USINT) Numero di bit frame dato, valori possibili 7, 8.
StopBits (USINT)) Numero di bit di stop, valori possibili 1, 2.
DTRManagement (DTR_MODE) Modo di gestione del segnale DTR sulla porta seriale (Definizione).
DTRComplement (BOOL) FALSE: DTR normale, TRUE: DTR complementato.
EchoFlush (BOOL) FALSE: I dati trasmessi sono ritornati in ricezione. TRUE: I dati trasmessi sono ignorati. Questa impostazione è utile nelle comunicazione RS485 per non ricevere in echo i dati trasmessi.
DTROnTime (UINT) Tempo di attesa dopo attivazione segnale DTR prima di trasmissione caratteri (mS).
DTROffTime (UINT) Tempo di attesa dopo trasmissione ultimo dato prima e disattivazione segnale DTR (mS).
FlushTm (UINT) Tempo di flush dati, se non sono caricati dati sullo stream dopo il tempo definito i dati presenti vengono automaticamente inviati (mS) (Impostare 0).
RxSize (UINT) Dimensione buffer ricezione dati.
TxSize (UINT) Dimensione buffer trasmissione dati.
Opened (BOOL) Attivo se porta porta seriale aperta.
Fault (BOOL) Attivo se errore gestione.
File (FILEP) Stream di I/O. Viene valorizzato su apertura porta seriale.

Immagine FB SysSerialPort
LogicLab, definizione porta COM

La porta da utilizzare và definita nel parametro COM, il valore cambia in funzione del sistema che si stà utilizzando.

SlimLine compact senza ethernetCOM0 (Rs232 su P4), COM2 (Rs485 su P2 se prevista)
SlimLine compact con ethernetCOM0 (Rs232 su P4)
SlimLine Cortex M7COM0 (Rs232 su P4), COM1 (Rs232 su P5), COM2 (Rs485 su P2 se prevista)
Netlog IIICOM0 (Rs232 su Port A), PCOM0.0 (Rs232 su Port B), COM2 (Rs485 su P9 se prevista)
SlimLine Raspberry/dev/ttyAMA0 (Rs485 su P2 se prevista)

Lo SlimLine basato su Raspberry permette di aumentare il numero di porte connettendo al sistema dei convertitori USB/Seriale. Le porte aggiuntive assumeranno un identificativo assegnato automaticamente (Avremo /dev/ttyUSB0, /dev/ttyUSB1, ecc). Connesso il convertitore al modulo, da console SSH con il comando lsusb è possibile vedere se è stato riconosciuto. Ecco il comando eseguito su di un modulo a cui è stato connesso un convertitore.

lsusb
Bus 001 Device 008: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC

Per conoscere il nome assegnato alla porta eseguire un listing della directory /dev, ecco il comando:

ls /dev | grep ttyUSB
ttyUSB0
ttyUSB1

In questo caso al modulo sono stati connessi 2 convertitori USB/Seriale e le porte sono identificate con /dev/ttyUSB0 e /dev/ttyUSB1.

CODESYS, definizione porta pCOM

Porta seriale RS485

Se il dispositivo SlimLine dispone di porta seriale RS485, la porta è conessa alla porta ttyAMA del modulo CPU Raspberry, per poterla utilizzare dall’ambiente CODESYS identificandola come “1”, occorre nel file /etc/CODESYSControl_User.cfg modificare la voce [SysCom] come indicato di seguito. Nota si specifica device ttyAMA anche se il device è ttyAMA0.

[SysCom]
;Linux.Devicefile=/dev/ttyS
Linux.Devicefile=/dev/ttyAMA

Aggiungere porta seriale su USB

Utilizzando moduli USB/Seriale è possibile connettere alla porta USB del modulo porte seriali aggiuntive, nel caso di una porta da utilizzare in alternativa alla ttyAMA identificandola come “1”, occorre modificare la voce [SysCom] come indicato di seguito. Nota si specifica device ttyUSB anche se il device è ttyUSB0.

[SysCom]
;Linux.Devicefile=/dev/ttyS
Linux.Devicefile=/dev/ttyUSB

Esempi

Come utilizzare gli esempi.

Oltre al programma di esempio ST_SerialDataReceive riportato in testa all’articolo rimando al programma ST_WindSonicDriver. Entrambi questi programmi aiutano a capire nel dettaglio come gestire le comunicazioni seriali.Negli esempi seguenti viene aperta una porta di comunicazione seriale e viene eseguito l’echo dei caratteri ricevuti.

LogicLab (Ptp116), FBD_SysSerialPort
PROGRAM FBD_SysSerialPort
VAR
    Sp : SysSerialPort; (* Serial port management *)
END_VAR
Immagine POU FBD_SysSerialPort
LogicLab (Ptp116), ST_SysSerialPort
PROGRAM ST_SysSerialPort
VAR
    Ch : INT; (* Auxiliary variable *)
    Sp: SysSerialPort; (* Serial port management *)
END_VAR

// *****************************************************************************
// PROGRAM "ST_SysSerialPort"
// *****************************************************************************
// This program echoes the characters received by the serial line.
// -----------------------------------------------------------------------------

    // -------------------------------------------------------------------------
    // INITIALIZATION
    // -------------------------------------------------------------------------

    IF (SysFirstLoop) THEN
        Sp.COM:=ADR('COM0'); //COM port definition
//      Sp.COM:=ADR('/dev/ttyAMA0'); //COM port definition
//      Sp.COM:=ADR('/dev/ttyUSB0'); //COM port definition
        Sp.Baudrate:=19200; //Baudrate
        Sp.Parity:='E'; //Parity
        Sp.DataBits:=8; //Data bits
        Sp.StopBits:=1; //Stop bits
        Sp.DTRManagement:=DTR_AUTO_WO_TIMES; //DTR management
        Sp.DTRComplement:=FALSE; //DTR complement
        Sp.EchoFlush:=FALSE; //Received echo flush
        Sp.DTROnTime:=0; //DTR On time delay (mS)
        Sp.DTROffTime:=0; //DTR Off time delay (mS)
        Sp.FlushTm:=0; //Flush time (mS)
        Sp.RxSize:=0; //Rx buffer size
        Sp.TxSize:=0; //Tx buffer size
    END_IF;

    // -------------------------------------------------------------------------
    // ECHOES CHARACTERS
    // -------------------------------------------------------------------------
    // Here the received characters are echoed back.

    Sp(Open:=TRUE); //Serial port management
    IF (Sp.Opened) THEN
        IF ((SysFGetOSpace(Sp.File) > 0) AND (SysFGetIChars(Sp.File) > 0)) THEN
            Ch:=Sysfgetc(Sp.File); //Get input character
            Ch:=Sysfputc(Ch, Sp.File); //Put input character
        END_IF;
    END_IF;

// [End of File]
CODESYS (Ptp161), ST_SysSerialPort
PROGRAM ST_SysSerialPort
VAR
    FirstLoop: BOOL := TRUE; // First execution loop
    Ch : INT; //Auxiliary variable
    Sp: SysSerialPort; //Serial port management
END_VAR

// *****************************************************************************
// PROGRAM "ST_SysSerialPort"
// *****************************************************************************
// This program echoes the characters received by the serial line.
// -----------------------------------------------------------------------------

    // -------------------------------------------------------------------------
    // INITIALIZATION
    // -------------------------------------------------------------------------
    // Initialize the serial port.

    IF (FirstLoop) THEN
        FirstLoop:=FALSE; //First execution loop
        Sp.pCOM:=ADR('1'); //COM port definition
        Sp.Baudrate:=19200; //Baudrate
        Sp.Parity:='E'; //Parity
        Sp.DataBits:=8; //Data bits
        Sp.StopBits:=1; //Stop bits
        Sp.DTRManagement:=DTR_MODE.DTR_AUTO_WO_TIMES; //DTR management
        Sp.DTRComplement:=FALSE; //DTR complement
        Sp.EchoFlush:=FALSE; //Received echo flush
        Sp.DTROnTime:=0; //DTR On time delay (mS)
        Sp.DTROffTime:=0; //DTR Off time delay (mS)
        Sp.FlushTm:=0; //Flush time (mS)
        Sp.RxSize:=0; //Rx buffer size
        Sp.TxSize:=0; //Tx buffer size
    END_IF;

    // -------------------------------------------------------------------------
    // ECHOES CHARACTERS
    // -------------------------------------------------------------------------
    // Here the received characters are echoed back.

    Sp(Open:=TRUE); //Serial port management
    IF (Sp.Opened) THEN
        IF ((SysFGetOSpace(Sp.File) > 0) AND (SysFGetIChars(Sp.File) > 0)) THEN
            Ch:=Sysfgetc(Sp.File); //Get input character
            Ch:=Sysfputc(Ch, Sp.File); //Put input character
        END_IF;
    END_IF;

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