olaffo Inserito: 27 gennaio 2013 Segnala Share Inserito: 27 gennaio 2013 Salve a tutti, devo realizzare un blocco che converta una lettura di un valore codificato in IEEE-754, in formato Real. Ho realizzato già un blocco che faccia tale conversione ma non sembra funzionare bene. Qualcuno ha già realizzato una funzione del genere o può darmi una mano? Inserisco il codice che ho realizzato io per eventuali commenti e correzioni: ByteBasso2 := AND (Lettura[2], 127); Mantissa := (int_to_dint(Lettura[1]) + (65536*int_to_dint(ByteBasso2))); RotazExp := ROR (lettura[2], 7); Esponente := int_to_real(AND (RotazExp, 255 )); 1_Mantissa := 1.0 + (0.108+((10.0**-7) * (dint_to_real(in := mantissa)))); if lettura[2].15 then segno := 1; else segno := 0; end_if; valore := ((-1.0)**segno) * (2.0**(Esponente-127.0)) * 1_mantissa; mantissa_1 := Lettura[1]; mantissa_2 := ByteBasso2; exp := AND (RotazExp, 255 ); segno_o := segno; L'ingresso Lettura[] è un array di 2 byte. grazie Link al commento Condividi su altri siti More sharing options...
batta Inserita: 27 gennaio 2013 Segnala Share Inserita: 27 gennaio 2013 Non capisco cosa vuoi fare. Se hai un numero codificato in IEEE 754 significa che hai un numero in formato REAL. Quindi, io capisco che vorresti convertire un numero da REAL a REAL ??? Poi dici che la variabile "Lettura[]" è un array di due byte. Ma allora non è una variabile REAL. Sinceramente, non ho proprio capito cosa tu voglia convertire. Link al commento Condividi su altri siti More sharing options...
olaffo Inserita: 27 gennaio 2013 Autore Segnala Share Inserita: 27 gennaio 2013 Dal manuale dello strumento (CPT-DIN CarloGavazzi) The variables are represented by 32-bit floating-point numbers in standard IEEE-754... The representation of a 32-bit floating-point number as an integer is: Bits 31 30 … 23 22 … 0 sign Exponent Mantissa The value of the number is: (-1)^sign * 2^(Exponent-127 ) *1.Mantissa La comunicazione è su modbus RS485. Usando "Readvar" estraggo l'informazione del parametro su due word (mw) da queste devo ottenere il valore real. Link al commento Condividi su altri siti More sharing options...
batta Inserita: 28 gennaio 2013 Segnala Share Inserita: 28 gennaio 2013 Ma da quanto si capisce, il valore che leggi è già in formato REAL. Non devi fare nessuna conversione. Devi solo interpretare le due variabili consecutive da 16 bit come una sola variabile da 32 bit che è già in formato REAL. Al massimo, dovrai scambiare tra loro le due variabili o i 4 byte, ma non credo. Link al commento Condividi su altri siti More sharing options...
nibble Inserita: 27 marzo 2013 Segnala Share Inserita: 27 marzo 2013 Il formato con cui Ti viene restituito il valore (real 32 bits) dovrebbe essere disponibile su 2 registri di tipo INT (direttamente dal buffer di ricezione della funzione READ_VAR. Il primo registro INT sarà relativo alla parte bassa e il ssecondo alla parte alta del valore letto come REAL. Dovresti convertire tali registri da tipo INT in WORD, ad esempio: val_basso:=INT_TO_WORD(buffer_ric[0]) val_alto:=INT_TO_WORD(buffer_ric[1]) E in seguito unire i 2 registri di tipo WORD in un registro REAL, ad esempio: val_flottante:=WORD_AS_REAL(val_basso, val_alto). Prova così dovrebbe funzionare. Bye Link al commento Condividi su altri siti More sharing options...
batman1970 Inserita: 8 giugno 2013 Segnala Share Inserita: 8 giugno 2013 si il modbus TCP IP della NOE ti restituisce solamente BOOL INT o DINT devi convertirli sia per la lettura che per la lettura, devi appunto ricavarti il segno poi l'esponente e poi la mantissa dopo di che moltiplichi tutto con (-1)^sign * 2^(Exponent-127 ) *1.Mantissa ed è semplicemente quello che fanno i plc tutte le volte che dichiari un real..attento che riprodurlo con un pc a 64 Bit ti porta a fare errori di arrotondamento per cui devi essere furbo nelle conversioni. Link al commento Condividi su altri siti More sharing options...
batta Inserita: 8 giugno 2013 Segnala Share Inserita: 8 giugno 2013 (modificato) Dovresti convertire tali registri da tipo INT in WORD, ad esempio: val_basso:=INT_TO_WORD(buffer_ric[0]) val_alto:=INT_TO_WORD(buffer_ric[1]) E in seguito unire i 2 registri di tipo WORD in un registro REAL, ad esempio: val_flottante:=WORD_AS_REAL(val_basso, val_alto). si il modbus TCP IP della NOE ti restituisce solamente BOOL INT o DINT devi convertirli sia per la lettura che per la lettura Perché siete tutti così smaniosi di complicarvi la vita inutilmente? Se devo leggere una variabile in formato REAL, a nessuno importa se leggo i 32 bit che la compongono uno alla volta, in due variabili da 16 bit o in una sola variabile da 32 bit. L'unica cosa importante è che devo leggere questi 32 bit da un dispositivo e riportarli pari pari in un altro. Il fatto che si vadano a leggere questi 32 bit spezzandoli in due variabili da 16 bit (e tra INT e WORD non c'è nessuna differenza), serve solo per far sapere al driver di comunicazione che dovrà leggere 16 + 16 bit. Ma il driver di comunicazione è solo un vettore, e non altera la merce che trasporta. Non effettuerà quindi nessuna conversione di formato. Una volta ricomposta la variabile (rispettando l'ordine dei byte), si avrà la stessa identica sequenza di 32 bit che c'era in partenza. Quindi, se il dato di partenza era in formato REAL, non importa a nessuno se ho mentito al driver dicendogli di leggere due word. A destinazione il dato sarà ancora in formato REAL. Se a un corriere affido due cassette di mele e gli dico che sono pere, lui le consegnerà al destinatario come pere. Ma non basta questo per farle diventare veramente pere. Se sono partite delle mele, arriveranno delle mele. Modificato: 8 giugno 2013 da batta Link al commento Condividi su altri siti More sharing options...
Livio Orsini Inserita: 8 giugno 2013 Segnala Share Inserita: 8 giugno 2013 Se devo leggere una variabile in formato REAL, a nessuno importa se leggo i 32 bit che la compongono uno alla volta, in due variabili da 16 bit o in una sola variabile da 32 bit. L'impoortante è che vengano restituiti nel giusto ordine, in altri termini che l'utilizzatore si ritrovi mantissa e caratteristica nell'ordine esatto. Poi come vengano trasferiti non ha nessuna importanza. Quello che è importante è che il formato real di partenza sia compatibile con quello di utilizzo. Link al commento Condividi su altri siti More sharing options...
batman1970 Inserita: 9 giugno 2013 Segnala Share Inserita: 9 giugno 2013 Io ho realizzato la funzione già da tempo, se vuoi cimentarti con vba non ci sono problemi, ti consiglio di fare una Function in un modulo, in ingresso metti il DINT che hai appena letto, te lo converti in stringa così non ti devi fare paturni con segni o non segni e tratti i bit cosi come sono, estrapoli mantissa segno ed esponente in formato bin... fai 2 for e li ottieni in decimale rimetti gli offset e tutto funziona, ed il giochino è fatto.... Link al commento Condividi su altri siti More sharing options...
Henon Inserita: 9 giugno 2013 Segnala Share Inserita: 9 giugno 2013 Dovresti convertire tali registri da tipo INT in WORD, ad esempio:val_basso:=INT_TO_WORD(buffer_ric[0])val_alto:=INT_TO_WORD(buffer_ric[1])E in seguito unire i 2 registri di tipo WORD in un registro REAL, ad esempio:val_flottante:=WORD_AS_REAL(val_basso, val_alto). Penso abbia completamente ragione Nibble Nel tuo Caso buffer_ric[0] corrisponde a Lettura[1] e buffer_ric[1] corrisponde a Lettura[2] Link al commento Condividi su altri siti More sharing options...
batta Inserita: 9 giugno 2013 Segnala Share Inserita: 9 giugno 2013 A volte le cose banali sono così banali che qualcuno deve per forza trovare il modo di farle diventare complicate. Link al commento Condividi su altri siti More sharing options...
batman1970 Inserita: 9 giugno 2013 Segnala Share Inserita: 9 giugno 2013 Scusate ma olaffo non è stato preciso,sarebbe bello capire come e perché,comunque se il plc e il M340 e la comunicazione e il MODBUS non ha la possibilità di leggere i registri in formati Real ma solo i singoli indirizzi per cui la word 400 e la word 401 oppure dalla 400 alla 460 in modo consecutivo. Ovvio che poi deve convertire i dati da DINT o da Int... leggendo 2 indirizzi consecutivi e poi convertire tutto in real... Ora se olaffo ritiene conveniente leggere i 2 interi e poi accodarli per formare il Dint va bene avrà dei motivi,per fare questo basta che fa così...concentratevi e semplice: RawBinData = Strings.Right("00000000000000000000000000000000" & Convert.ToString(InPutData), 32) la funzione Convert.ToString converte in stringa ed in numero binario a questo punto gli sia attaccano a sinistro un certo numero di Zeri ed allo stesso tempo si prendono i primi 32 caratteri partendo da destra in modo di ricreare un numero binario a 32 bit completo... Ora calcoliamo il segno,prendiamo il primo Bit che è quello che esprime il segno.. If Strings.Left(RawBinData, 1) = 1 Then s = -1 End If If Strings.Left(RawBinData, 1) = 0 Then s = 1 End If la funzione left prendera il primo bit partendo da Sinistra Cioè il segno. Ora tocca estrapolare l'esponente,possiamo fare così: Dim Exp As String = "" Dim ExpResult As Single = 0 ExpResult = 0 Dim I As Integer = 0 Exp = Strings.Left(RawBinData, 9) Exp = Strings.Right(Exp, 8) For I = 0 To 7 ExpResult = ((Val(Exp(I))) * 2 ^ (7 - I)) + ExpResult Next ExpTot = ExpResult - 127 con il primo left prevevo i primi 9 Bit partendo da sinistra, e con il successivo right prendo igli 8 bit partendo da destra che rappresentano l'esponente. il ciclo for successivo e semplicemente la conversione da binario a decimale,finita la conversione aggiungo l'offset 127 che rappresenta la propieta dei numeri real nel formato IEEE bla bla bla... veniamo alla mantissa,che non è altro che i 23 bit a destra mancanti per cui: Mantissa = Strings.Right(RawBinData, 23) li prendo come mamma li ha fatti... For I = 0 To 22 MantissaResult = ((Val(Mantissa(I))) * 2 ^ (22 - I)) + MantissaResult Next Dimensione = MantissaResult MantissaTot = (MantissaResult / 8388608) + 1.0 e li converto in deciamle con il classico for e li divido per l'offset 8388608 ma sto giro gli sommo 1,0 perché il risultato sara sempre 0..... a questo punto il mio real sarà.. Real = (s * MantissaTot * (2 ^ ExpTot)) Ok penso proprio di essere stato esaustivo e completo nelle informazioni,poi se il problema deve essere ataccare 2 word o 2 interi si puo fare cosi Dint= Convert.ToString(dato1 & dato2)e poi lo si puo dare in pasto alla mia funzione... Link al commento Condividi su altri siti More sharing options...
batta Inserita: 10 giugno 2013 Segnala Share Inserita: 10 giugno 2013 Ma tu stai facendo l'interpretazione di una variabile a 32 bit in formato IEEE-754, non la conversione. Prendi semplicemente un dato che è già in formato REAL, e visualizzi il valore in numeri decimali e virgola. Ovvero, significa che i 32 bit sono stati riportati pari pari dal dispositivo A al dispositivo B e, successivamente, interpretati. Ma se leggi i 32 bit, fai una conversione da DINT a REAL e poi interpreti il valore con la tua funzione (della quale non metto assolutamente in dubbio la correttezza), ottieni un valore che non è quello di partenza. Facciamo un esempio con i numeri. Partiamo da una variabile in formato REAL che contiene il valore 1234.5. Se visualizzo questa variabile in formato esadecimale, vedo 449A5000 Se la visualizzo i binario vedo 0100_0100_1001_1010_0101_0000_0000_0000 Se la visualizzo in decimale vedo 1150963712 Ma sono solo modi diversi di visualizzare la stessa identica variabile. Se io trasferisco questi 32 bit spezzandoli in due variabili da 16 bit e poi ricompongo la variabile da 32 bit, devo avere ancora 0100_0100_1001_1010_0101_0000_0000_0000 Questi 32 bit se li interpreto come numero in virgola mobile corrispondono a 1234.5. Se invece decido di convertirli da DINT (o DWORD) in REAL, solo perché il driver di comunicazione mi dice che tratta solo valori interi, la sequenza di 32 bit 0100_0100_1001_1010_0101_0000_0000_0000 (449A5000 Hex) mi viene convertita in 0100_1110_1000_1001_0011_0100_1010_0000 (4E8934A0 Hex) Ma se io interpreto 0100_1110_1000_1001_0011_0100_1010_0000 come variabile in formato REAL ottengo 1.150964e+009 Link al commento Condividi su altri siti More sharing options...
max.riservo Inserita: 10 giugno 2013 Segnala Share Inserita: 10 giugno 2013 Partiamo da una variabile in formato REAL che contiene il valore 1234.5. Se visualizzo questa variabile in formato esadecimale, vedo 449A5000 Se la visualizzo i binario vedo 0100_0100_1001_1010_0101_0000_0000_0000 Se la visualizzo in decimale vedo 1150963712 Ma sono solo modi diversi di visualizzare la stessa identica variabile. Se io trasferisco questi 32 bit spezzandoli in due variabili da 16 bit e poi ricompongo la variabile da 32 bit, devo avere ancora 0100_0100_1001_1010_0101_0000_0000_0000 Questi 32 bit se li interpreto come numero in virgola mobile corrispondono a 1234.5. Credo che questa risposta di Batta dovrebbe metter fine a tutti i dubbi ..... Aggiungo per completezza che lo scambio di variabili (dati) tramite Modbus (RTU oppure TCP/IP) avviene utilizzando dei registri (WORD) e quindi la difficoltà di Olaffo probabilmente risiede nel fatto che una variabile REAL non può essere mossa 'direttamente' in una variabile DINT SENZA effettuarne una converasione di tipo (con relativa perdita della parte decimale) con una istruzione del tipo REAL_TO_DINT(Floating_var) ..... Per superare questo problema apparente ti basta allocare 1 variabile Real e 1 variabile DInt e farle puntare alla stessa area di memoria (i.e. %MW100) : con questo semplice accorgimento hai risolto il tuo problema ! Link al commento Condividi su altri siti More sharing options...
batman1970 Inserita: 10 giugno 2013 Segnala Share Inserita: 10 giugno 2013 Ragazzi Olaffo non e chiaro, pero leggete il software che ha scritto, non sono 2 move sono una conversione IEEE 754 da DINT a real infatti "Conversione Ieee754 -> Real" valore := ((-1.0)**segno) * (2.0**(Esponente-127.0)) * 1_mantissa; nel suo software sta cercando di ricavarsi exp mantissa e segno non mi sembra che abbia bisogno di sapere come fare 2 move.... Pero penso che lo abbiamo aiutato abbastanza tante che non si vede... Link al commento Condividi su altri siti More sharing options...
max.riservo Inserita: 10 giugno 2013 Segnala Share Inserita: 10 giugno 2013 Ragazzi Olaffo non e chiaro, pero leggete il software che ha scritto, non sono 2 move sono una conversione IEEE 754 da DINT a real infatti "Conversione Ieee754 -> Real" Batman, il codice di Olaffo è del tutto superfluo. Se non può utilizzare le funzioni di cast NATIVE del M340 (DINT_TO_REAL e REAL_TO_DINT) DEVE utilizzare il suggerimento del mio post precedente (ovvero assegnare alla stessa area di memoria i.e. %MW100 una variabile Real e una variabile DINT). Link al commento Condividi su altri siti More sharing options...
Stefano Sormanni Inserita: 26 giugno 2013 Segnala Share Inserita: 26 giugno 2013 Ho realizzato un blocco che fa proprio questa funzione , se c'è ancora interesse posso bubblicarlo. ciao Link al commento Condividi su altri siti More sharing options...
MarcoBiadene Inserita: 28 maggio 2014 Segnala Share Inserita: 28 maggio 2014 Ciao, puoi mandare il blocco che fa questa funzione??? Ne avrei bisogno il prima possibile GRAZIE!!!! Link al commento Condividi su altri siti More sharing options...
Messaggi consigliati