Convertire 16 bit in "qualcosa"

I miei PLC sono connessi al Web tramite il Wifi di Wemos. Per accoppiare il Wemos alla rete Wifi ho sempre usato il pulsante WPS presenti nei nuovi router.
Ma (c'è sempre un MA) non tutti i router ce l'hanno.
Ecco quindi che quelle poche volte dovrei sparare dal Touch screen al PLC dei caratteri ASCII che poi leggerò dal Wemos in modo che lui si "accoppi" con la rete Wifi.
Nessun problema, a quello poi ci penso io.

Però il PLC usa delle word da 16bit.
E il numero che leggo non ha senso, o almeno questo pensavo...

Cioè, se lo converto in BIN il senso ce lo ha:

se scrivo A mi risponde
01000001

se scrivo AA mi risponde
0100000101000001

se scrivo AAA mi risponde
0100000101000001
01000001

(ho messo gli zeri davanti per migliorare la lettura ma l'output non ha il primo ZERO se questo non è un 1).
Tutto chiaro: se inserisco un carattere usa i primi 8 bit, se ne inserisco due usa tutti i 16 bit e se ne inserisco tre passa alla word successiva e questo lo farà per 30 word (cioè 60 caratteri alfanumerici ma posso anche leggerne di meno, vedrò quanto può essere lunga una password di un router...).
Se non scrivo nessun carattere la word da 0.

  • Il primo problema è SPEZZARE la word in due byte (però solo se è maggiore di un byte)
  • il secondo problema è convertire il byte in un carattere ASCII (spero che siano standard...).

Chi è quell'anima pia che puo' darmi un suggerimento?

Grazie in anticipo!

Il codice Ascii per 'A' è 01000001
Non vedo il problema lì...

Che fosse standard ASCII ci speravo, ma non si sa mai ! :grinning_face_with_smiling_eyes:

Scusa 01000001 se lo scrivi come due nibble da 4 bit è 0100 0001 ovvero ... esattamente 0x41 che è la lettera 'A' in ASCII ... già ti sta trasmettendo i caratteri in ASCII, non devi convertire nulla ...

per il resto tu metti i dati in un char array e, se aggiungi uno 0x00 alla fine, ti trovi già una stringa con tutti i caratteri in ASCII :wink:

Guglielmo

Era tutto nato dalla stampa del valore decimale:

  • se scrivo A mi da 65 e va bene
  • se scrivo AA mi da 16705 e la cosa si complica.

Ecco perché ho pensato alla conversione in bytes, la suddivisione in due byte e la conversione.
Sbaglio qualcosa o c'è un modo più rapido e/o sintetico?

... t'ho già detto, bisogna che ricevi byte a byte e metti in un char array, quando la trasmissione è finita metti uno 0x00 e ti trovi già tutto in ASCII nell'array ... dove è la difficoltà ???

Ma la trasmissione è seriale? o che trasmissione è dal PLC ?

Guglielmo

Forse no, lui dice "se inserisco un carattere usa i primi 8 bit, se ne inserisco due usa tutti i 16 bit e se ne inserisco tre passa alla word successiva" e " il PLC usa delle word da 16bit".

In tal caso è più complesso perché riceve sempre word da 16 bit più o meno popolate.

Quindi, per essere certi di questo, cosa risponde il PLC con A AB ABC ABCD, includendo anche tutti gli zeri non significativi fino a 16 bit?

... e capirai che difficoltà ... se trasmette sempre 16 bit si tratta di capire solo se, nel caso gli bastino 8 bit, usa solo la parte più significativa o la parte meno significativa ... in ogni caso cambia poco.

Quello che invece io ancora non ho capito è come vengo trasmessi i dati ... su porta seriale? ... su un I2C? ... in un pacchetto TCP? ... in che cosa e come???

Guglielmo

La trasmissione non è un problema dato che i dati già li sto leggendo sul monitor seriale del Wemos. Comunque, per soddisfare la tua curiosità, ho il PLC in slave quindi lo interrogo da Wemos su RS-485, in qualsiasi momento con

  for (i = 0; i < 30; i++) {
    ret = node.readHoldingRegisters (i + 430, 1); // read da D430 a D459
    delay (del);
    if (ret == node.ku8MBSuccess) {
      nn = node.getResponseBuffer (0); // e' una Word da 16 bit.
Serial.print (nn); Serial.print (" ");Serial.print(nn, BIN);Serial.print (" ");Serial.println (nn, HEX);
    }

e poi nn lo metto dove mi serve.

Certo, nn è a 16 bit quindi se è un solo carattere i primi 8 bit saranno ZERO (quelli a sinistra) e i successivi 8 bit saranno il carattere.
Non ricevo byte a byte (allora non disturbavo), ma ricevo una word da 16 bit, cioè due byte.

Per rispondere a Claudio_FF

A =
65 1000001 41
AB =
16961 100001001000001 4241
ABC =
16961 100001001000001 4241
67 1000011 43
ABCD =
16961 100001001000001 4241
17475 100010001000011 4443

dove il primo numero è un DEC, di seguito il BIN e poi (per non farci mancare nulla) il HEX.

Siccome sarò bravo con PLC, HMI e hardware ma se si tratta di programmazione un po' più "spinta" sono una frana, se mi date un paio di righe le provo e vi faccio sapere.

quindi hai dichiarato nn come uint16_t ?

unsigned int

La uso per le variabili numeriche (praticamente tutte, prima di questo problema wifi)

@steve-cr : ma dai ... impegnati ... fannullone :joy:

Se hai 16 bit come fai a ricavare gli 8 bit meno significativi? (numero_16_bit & 0x00FF) = ammazzi gli 8 bit superiori e ti tieni gli 8 bit inferiori.

E se vuoi ricavare gli 8 bit superiori? (numero_16_bit >> 8) = sposti gli 8 bit alti in quelli bassi ed hai solo quelli.

Ovviamnete il risultato lo puoi tranquillamente mettere in un char così hai il tuo carattere (che, abbiamo visto, è già in ASCII). :wink:

Guglielmo

1 Like

Mille grazie !

  for (i = 0; i < 30; i++) {
    ret = node.readHoldingRegisters (i + 430, 1); // read da D430 a D459
    delay (del);
    if (ret == node.ku8MBSuccess) {
      nn = node.getResponseBuffer (0); // e' una Word da 16 bit.
      char var1 =  (nn >> 8); 
      char var =  (nn & 0x00FF);
Serial.print (var); Serial.print (" ");Serial.print(var1);Serial.print (" ");Serial.println (nn, BIN);
    }
A B 100001001000001
C D 100010001000011
a b 110001001100001
c d 110010001100011
1 2 11001000110001
3 4 11010000110011

Come passo successivo mi manca di farne una stringa da passare al router

  WiFi.mode(WIFI_STA);
  //WiFi.begin(WiFi.SSID().c_str(), WiFi.psk().c_str()); // reading data from EPROM, last saved credentials
  WiFi.begin("nomerete", "password"); // ------------- Se non possibile WPS, password manuale --------

E per i più "pigri" ci sono sempre le funzioni lowByte e highByte spiegate anche nel reference base di Arduino :wink:

... ma proprio per i più "lazzaroni" ... quelli seduti negli ultimi banchi ... :joy: :joy: :joy:

Guglielmo

questo è lo stesso di uint16_t su un UNO o MEGA (architettura a 8 bit) ma sarebbe a 32 bit su un ESP o MKR

getResponseBuffer() restituisce un uint16_t indipendente dall'architettura

1 Like

SI, occhio, che ho visto programmi non andare più se portati su ESP (o su SAMD21) ...
... meglio, in testa al programma, includere sempre:

#include <stdint.h>

e poi definire le variabili con uint8_t, int8_t, uint16_t, int16_t, ecc. ecc., così le lunghezze sono ben chiare e non cambiano da architettura ad architettura.

Guglielmo

  password = "";
  for (i = 0; i < 30; i++) {
    ret = node.readHoldingRegisters (i + 430, 1); // read da D430 a D459
    delay (del);
    if (ret == node.ku8MBSuccess) {
      nn = node.getResponseBuffer (0); // e' una Word da 16 bit.

      char var =  (nn & 0x00FF);
      password += var;
      char var1 =  (nn >> 8);
      password += var1;

      Serial.print (var); Serial.print (" "); Serial.print(var1); Serial.print (" "); Serial.println (password);
    }

Domanda (prima di verificarlo):
La stringa è piena anche di "spazi" se legge tutte le 30 locazioni di cui solo le prime sono occupate da caratteri oppure il valore ZERO non è inteso come carattere e la stringa rimane "pulita"?

Vabbé, dai, ogni tanto mettevano dietro la lavagna anche me.
Un po' lazzarone dell'ultimo banco lo sono, poi è sabato, fuori piove (e già è raro), il mare è grosso e fuori ci sono "solo" 18 gradi...

Allora ho "sintetizzato". E ho usato solo una var :grinning_face_with_smiling_eyes: per risparmiare...

  for (i = 0; i < 30; i++) {
    ret = node.readHoldingRegisters (i + 430, 1); // read da D430 a D459
    delay (del);
    if (ret == node.ku8MBSuccess) {
      nn = node.getResponseBuffer (0); // e' una Word da 16 bit.
      char var =  lowByte (nn);
      password += var;
      var =  highByte (nn);
      password += var;
    }

... e niente, quando uno è un lazzarone, lazzarone rimane ... :smiling_imp:

Ma che ti usi la classe String ... quella è tutta roba che si fa in un attimo con un char array in cui metti i vari caratteri mano mano che li separi!

Guglielmo

1 Like