Vai all indice del manuale di programmazione
Presentiamo un programma per la ricezione e decodifica di una stringa seriale, viene ricevuta la stringa “Gill format– Polar, Continuous” che è la stringa di default inviata in modo continuo dall’anemometro ad ultrasuoni WindSonic della Gill Instruments. Si tratta di una stringa ascii del tipo:
<STX>Q,229,002.74,M,00,<ETX>16<CR><LF> Dove: Q: Indirizzo di nodo (Lettera da A...Z) 229: Direzione vento (Intero da 0 a 359 gradi) 002.74: Velocità vento (Float in metri/sec) M: Unità misura (Lettera M per metri) 00: Stato (Intero 2 cifre) 16: Checksum (Intero esadecimale 2 cifre)
La stringa con i dati è compresa tra lo “Start of text” e “End of text” a cui segue il checksum di controllo.

Descrizione programma
- Il programma dopo avere impostato la porta seriale per la ricezione del messaggio nel case “0” si pone in attesa del primo carattere <STX>.
- Nel case “1” viene eseguita la ricezione dell’intero messaggio fino al carattere <CR> di fine.
- Nel case “2” si controlla il messaggio, dopo il <CR> ci deve essere un <LF> in caso contrario errore. Il messaggio ricevuto è ritornato sulla console di spionaggio.
- Si controlla la lunghezza del messaggio che deve essere di 22 caratteri.
- Segue il calcolo e controllo del checksum del messaggio. Il calcolo è facilitato dalla lunghezza fissa del mesaggio per cui è possibile iterare sui caratteri ricevuti all’interno del buffer di ricezione.
- Viene acquisita la direzione del vento (Numero intero a 3 cfre), la velocità (Numero float) e lo stato (Numero intero a 2 cifre).
- Vengono inviati i valori acquisiti alla console di spionaggio.
- Il programma terimna incrementando il numeratore dei messaggi ricevuti.
- In caso di errore la ricezione viene reinizializzata e alla console di spionaggio è inviato il codice di errore.
LogficLab (Ptp116, ST_WindSonicDriver)
PROGRAM ST_WindSonicDriver
VAR
i : UDINT; (* Auxiliary variable *)
Ch : BYTE; (* Rx character *)
ErrorNr : USINT; (* Error number *)
CaseNr : USINT; (* Program case *)
Ptr : PVOID; (* Auxiliary pointer *)
TimeBf : UDINT; (* Time buffer (uS) *)
WDirection : UINT; (* Wind direction *)
WSpeed : REAL; (* Wind speed *)
Status : USINT; (* Status *)
Cks : ARRAY[0..1] OF BYTE; (* Checksum *)
RxChrs : UDINT; (* Rx characters *)
Errors : UDINT; (* Total errors *)
Messages : UDINT; (* Total messages *)
RxBuf : STRING[ 64 ]; (* Rx data buffer *)
SpyBuffer : STRING[ 64 ]; (* Spy buffer *)
Sp : SysSerialPort; (* Serial port management *)
END_VAR
// *****************************************************************************
// PROGRAM "ST_WindSonicDriver"
// *****************************************************************************
// Receives data from WindSonic a Gill Instruments ultrasonic Wind Sensor.
// In the "Gill format Polar, Continuous" (Default) the device continuously
// transmit a message like the following.
//
// Q,,000.37,M,00,xx
// Q,088,000.37,M,00,xx
//
// Where:
// Q:WindSonic node address
// 088: Wind direction, if detected otherwise none
// 000.37: Wind speed
// M: Units
// 00: Status
// xx: Check sum,this is the XOR of the bytes between (and not including) the
// and characters.
// -----------------------------------------------------------------------------
// -------------------------------------------------------------------------
// INITIALIZATION
// -------------------------------------------------------------------------
// Configure serial port.
IF (SysFirstLoop) THEN
Sp.COM:=ADR('COM2'); //COM port definition
Sp.Baudrate:=9600; //Baudrate
Sp.Parity:='N'; //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
eTO_JUNK(SysVsnprintf(ADR(SpyBuffer), SIZEOF(SpyBuffer), ADR('Error:%d'), USINT_TYPE, ADR(ErrorNr)));
eTO_JUNK(SysCVsnprintf(ADR(SpyBuffer), SIZEOF(SpyBuffer), ADR(', On case:%d'), USINT_TYPE, ADR(CaseNr)));
eTO_JUNK(SysWrSpyData(SPY_ASCII, 0, 16#10000000, ADR('WindSonicDriver:Er'), ADR(SpyBuffer)));
Errors:=Errors+1; //Total errors
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:=SysGetSysTime(TRUE); END_IF;
IF ((SysGetSysTime(TRUE)-TimeBf) > 1000000) THEN
ErrorNr:=10; //Error number
RETURN;
END_IF;
// -------------------------------------------------------------------------
// CASE MANAGEMENT
// -------------------------------------------------------------------------
// Program cases.
CASE (CaseNr) OF
// ---------------------------------------------------------------------
// WAITS RECEPTION START
// ---------------------------------------------------------------------
// Waits until is been received.
0:
IF NOT(TO_BOOL(SysFGetIChars(Sp.File))) THEN RETURN; END_IF;
Ch:=TO_BYTE(Sysfgetc(Sp.File)); //Rx character
IF (Ch <> 16#02) THEN RETURN; END_IF;
// Initialize the reception.
RxChrs:=0; //Rx characters
eTO_JUNK(Sysmemset(ADR(RxBuf), 0, SIZEOF(RxBuf))); //Clear data buffer
eTO_JUNK(eSetBYTE(ADR(RxBuf)+RxChrs, Ch)); //Store character in buffer
RxChrs:=RxChrs+1; //Rx characters
CaseNr:=CaseNr+1; //Program case
// ---------------------------------------------------------------------
// Here the string is received.
1:
WHILE TO_BOOL(SysFGetIChars(Sp.File)) DO
Ch:=TO_BYTE(Sysfgetc(Sp.File)); //Rx character
// terminates the string.
IF (Ch = 16#0D) THEN CaseNr:=CaseNr+1; RETURN; END_IF;
eTO_JUNK(eSetBYTE(ADR(RxBuf)+RxChrs, Ch)); //Store character in buffer
RxChrs:=RxChrs+1; //Rx characters
// Check if string is longer than defined buffer.
IF (RxChrs >= SIZEOF(RxBuf)) THEN
ErrorNr:=20; //Error number
RETURN;
END_IF;
END_WHILE;
// -----------------------------------------------------------------
// After the must be received.
2:
IF NOT(TO_BOOL(SysFGetIChars(Sp.File))) THEN RETURN; END_IF;
Ch:=TO_BYTE(Sysfgetc(Sp.File)); //Rx character
IF (Ch <> 16#0A) THEN ErrorNr:=30; RETURN; END_IF;
// Here the string has been received, it's sent to spy console.
eTO_JUNK(SysWrSpyData(SPY_ASCHEX, 0, 16#00000001, ADR('WindSonicDriver:Rx'), ADR(RxBuf)));
// Calculate checksum on characters between and .
Cks[0]:=eGetBYTE(ADR(RxBuf)+1); //Checksum
FOR i:=0 TO RxChrs-1-3 DO Cks[0]:=Cks[0] XOR eGetBYTE(ADR(RxBuf)+1+i); END_FOR;
// Acquire "Checksum".
Ptr:=SysStrFind(ADR(RxBuf), ADR('$03'), FIND_GET_END);
IF (Ptr = eNULL) THEN ErrorNr:=31; RETURN; END_IF;
IF NOT(SysVsscanf(Ptr, ADR('%02X'), BYTE_TYPE, ADR(Cks[1]))) THEN ErrorNr:=32; RETURN; END_IF;
IF (Cks[0] <> Cks[1]) THEN ErrorNr:=33; RETURN; END_IF;
// Acquire "Wind direction".
// If not detected the field is empty.
Ptr:=SysStrFind(ADR(RxBuf), ADR(','), FIND_GET_END);
IF (Ptr = eNULL) THEN ErrorNr:=40; RETURN; END_IF;
IF (TO_UDINT(SysStrFind(Ptr, ADR(','), FIND_GET_END)-Ptr) > 1) THEN
IF NOT(SysVsscanf(Ptr, ADR('%d'), UINT_TYPE, ADR(WDirection))) THEN ErrorNr:=41; RETURN; END_IF;
END_IF;
// Acquire "Wind speed".
Ptr:=SysStrFind(Ptr, ADR(','), FIND_GET_END);
IF (Ptr = eNULL) THEN ErrorNr:=50; RETURN; END_IF;
IF NOT(SysVsscanf(Ptr, ADR('%f'), REAL_TYPE, ADR(WSpeed))) THEN ErrorNr:=51; RETURN; END_IF;
// Acquire "Status". Meter unit has been expected.
Ptr:=SysStrFind(Ptr, ADR(',M,'), FIND_GET_END);
IF (Ptr = eNULL) THEN ErrorNr:=60; RETURN; END_IF;
IF NOT(SysVsscanf(Ptr, ADR('%d'), USINT_TYPE, ADR(Status))) THEN ErrorNr:=61; RETURN; END_IF;
// Report on Spy console the acquired data.
eTO_JUNK(SysVsnprintf(ADR(SpyBuffer), SIZEOF(SpyBuffer), ADR('WDirection:%03d'), UINT_TYPE, ADR(WDirection)));
eTO_JUNK(SysCVsnprintf(ADR(SpyBuffer), SIZEOF(SpyBuffer), ADR(', WSpeed:%06.2f'), REAL_TYPE, ADR(WSpeed)));
eTO_JUNK(SysCVsnprintf(ADR(SpyBuffer), SIZEOF(SpyBuffer), ADR(', Status:%02d'), USINT_TYPE, ADR(Status)));
eTO_JUNK(SysWrSpyData(SPY_ASCII, 0, 16#00000001, ADR('WindSonicDriver:Rx'), ADR(SpyBuffer)));
Messages:=Messages+1; //Total messages
CaseNr:=0; //Program case
END_CASE;
// [End of file]