Generare valori esadecimali per inviarli a un modulo GPS.

Ciao a tutti
Avevo bisogno di qualche frequenza campione e ho pensato al GPS.
Ho acquistato un NEO-7N, che sull’uscita PPS può dare frequenze da frazioni di Hertz a circa 16MHz e ho trovato un programmino su cui ho lavorato un po’. Quando tutto sembrava funzionare, però, mi sono reso conto che sui kHz ci sono problemi, in quanto la frequenza in uscita non corrisponde a quella desiderata. I MHz e gli Hz sembrano funzionare perfettamente. Andando a rivedere la parte del codice che calcola e invia i dati, sembra che ci sia un errore concettuale nella conversione in esadecimale (“Converte la frequenza in HEX”), ma non riesco a farlo funzionare. In particolare, sembra non funzionare la conversione del block2.

Ecco la parte del codice che si occupa della conversione e dell’invio dei dati per via seriale:

void invia_freq( )
  {
  freq_HX = freq,HEX;       // Converte la frequenza in Hex
  freq_block1 = freq_HX%0x100;  // Calcola il byte a destra, Lo-byte
  freq_HX /= 0x100;        
  freq_block2 = freq_HX%0x100;     // Calcola il byte n.2, Md-byte
  freq_HX /= 0x100;       
  freq_block3 = freq_HX%0x100;    // Calcola il byte a sinistra, Hi-byte
                                   // In realtà esiste anche un quarto byte sia per le frequenze che per il duty cycle.
  /*
  freq_block1=freq%256;
  freq_block2=(freq%65536)/256;
  freq_block3=freq/65536;
  */
  // Serial.print("   Calculated Hex Freq Bytes  BK3:"); Serial.print(freq_block3,HEX);
  // Serial.print("  BK2:"); Serial.print(freq_block2,HEX); 
  // Serial.print("  BK1:"); Serial.print(freq_block1,HEX);
  // Serial.print("   F:"); Serial.print(freq); Serial.println(" Hz"); 
  
//            0     1     2     3     4     5     6     7     8     9     10    11    12    13
//           Chr1  Chr2  CFG   TP5   L E N G TH  TPsel Rvd0  Rvd1a Rvd1b dlya  dlyb  Rdlya Rdlyb
  byte Hz[]={0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x07, 0x00, 0x20, 0x32, 0x00, 0x00, 0x00,

//            14    15    16    17    18    19    20    21    22    23    24    25    26    27    28    29
//            Lo  Freq/Per FREE Hi     Lo  Freq/Per LOCK Hi     Lo Lgth/DC. FREE Hi    Lo  Lgth/DC. LOCK Hi
             0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 
//            1Hz                     2Hz                                       50%                     50%
           
//            30    31    32    33    34    35    36    37    38    39
//           
             0x00, 0x00, 0x00, 0x00, 0xEB, 0x00, 0x00, 0x00, 0xA9, 0x60};  
//           --User config. delay--    EF: cambia frequenza in LOCK - EB: non cambia frequenza.
       
    Hz[14]=freq_block1; Hz[15]= freq_block2; Hz[16]=freq_block3;   // for unlocked freq generation
 // Hz[18]=freq_block1; Hz[19]= freq_block2; Hz[20]=freq_block3;   // for GPS locked freq generation
 //  for(int i=0; i<43; i++) {Serial.print(Hz[i],HEX); Serial.print(" ");} Serial.println();

  calcChecksum(&Hz[2],sizeof(Hz)-4);  // makes the checksum
  sendUBX(Hz,sizeof(Hz));             // Send the HEX
  // byte gpsSetSuccess = 0;
  // gpsSetSuccess += getUBX_ACK(&Hz[2]) ;
  } // end of void write_freq
   

void calcChecksum(byte *checksumPayload, byte payloadSize)
  {
  byte CK_A=0;
  byte CK_B=0;
  for(int i=0; i<payloadSize; i++)
    {
    CK_A = CK_A+*checksumPayload;
    CK_B = CK_B+CK_A;
    checksumPayload++;
    }
  *checksumPayload = CK_A;
  checksumPayload++;
  *checksumPayload = CK_B;
  }// end of void calcChecksum


void sendUBX(byte *UBXmsg, byte msgLength)
  {
  for(int i=0; i<msgLength; i++)
    {
    ss.write(UBXmsg[i]);
    ss.flush();
    }
  ss.println();
  ss.flush();
  } // end of void sendUBX

Il principio è questo: inizialmente viene costruito un array di valori esadecimali di tutti i parametri del segnale PPS; poi i valori che riguardano la frequenza da generare vengono sostituiti con quelli calcolati di volta in volta, dopodiché tutto l’array viene inviato sulla seriale (NeoSWSerial ss).

Credo che la frequenza, ad esempio 1.234.000Hz, debba essere convertita in tre byte esadecimali:12D450 >> 12, D4, 50 che poi devono essere inviati al GPS. Mi sembra che il problema stia nel calcolare correttamente il D4.

Mi potete aiutare?

Grazie
Gianluca

Intanto comincia con lo spiegare cosa pensi possa fare questa riga ...

freq_HX = freq,HEX;       // Converte la frequenza in Hex

... dato che non credo faccia quello che tu pensi e scrivi nel commento ::slight_smile:

HEX è solo un numero definito nel "core" nel file "Print.h" e vale 16:

#define DEC 10
#define HEX 16
#define OCT 8
#ifdef BIN // Prevent warnings if BIN is previously defined in "iotnx4.h" or similar
#undef BIN
#endif
#define BIN 2

e, scrivere quello che hai scritto tu, significa solo assegnare freq alla variabile freq_HX dato che, l'operatore binario ',' (comma) scritto in quel modo non ha alcun effetto (viene semplicemente scartato il valore 16).

Guglielmo

gpb01:
Intanto comincia con lo spiegare cosa pensi possa fare questa riga …

freq_HX = freq,HEX;       // Converte la frequenza in Hex

… dato che non credo faccia quello che tu pensi e scrivi nel commento :slight_smile:

Proprio quello è l’errore concettuale a cui mi riferisco! Quella riga stava nel programma che ho preso come base, in gran parte funzionante sebbene sia chiaro, vedendolo prima del mio lavoro, che viene già da un altro, modificato da una persona non pienamente cosciente di ciò che faceva! :slight_smile: Il produttore del chip dice che, a richiesta, fornisce un programma in C: probabilmente qualcuno lo ha avuto e lo ha modificato, ottenendo quello che ho trovato io!

Quella riga è del TUTTO inutile e NON fa quello che credi e chi l’ha scritta ha scritto una frescaccia (… per non cadere nel volgare :wink:)!

Per ottenere i vari bytes la cosa più semplice che puoi fare è AND e SHIFT …

void setup() {
  // put your setup code here, to run once:
  uint32_t valore;
  uint8_t  b0, b1, b2, b3;
  delay(500);
  Serial.begin(115200);
  valore = 1234000;
  Serial.print("Valore: ");
  Serial.println(valore,HEX);
  b0 = (valore & 0x000000FF);
  b1 = (valore & 0x0000FF00) >> 8;
  b2 = (valore & 0x00FF0000) >> 16;
  b3 = (valore & 0xFF000000) >> 24;
  Serial.print("b0: ");
  Serial.print(b0,HEX);
  Serial.print(" - b1: ");
  Serial.print(b1,HEX);
  Serial.print(" - b2: ");
  Serial.print(b2,HEX);
  Serial.print(" - b3: ");
  Serial.println(b3,HEX);
}

void loop() {
  // put your main code here, to run repeatedly:

}

… una banalità unica :smiley:

Guglielmo

È ovvio!!! :slight_smile:
Grazie!

Spero che funzioni... Sulla carta, i calcoli fatto col modulo e la divisione sembrano funzionare, sia quelli originali (che ho messo come commento, quelli con 0x100) che quelli che ho scritto io (con 256 e 65536, dopo aver provato con gli esadecimali, forse in questo caso più leggibili).

Datman:
Spero che funzioni...

... quello che ti ho scritto funziona di sicuro :smiley:

Quello che sarebbe da capire se vuole i valori così in binario o li vuole veramente convertiti in HEX in formato ASCII ...
... mi spiego, è da capire se, ad esempio, vuole un singolo byte che contiene il valore 0x12 o vuole DUE byte che contengono 0x31 (1 in ASCII) e 0x32 (2 in ASCII) ... ma questo lo vedi facilmente dallo spazio che hai nel record :wink:

Guglielmo

Così è più elegante ma, purtroppo, il risultato è lo stesso! Il problema è altrove… :frowning:

Mah ... di sicuro su Arduino c'è un problema con la Serial.print() ... ho idea che, oltre a voler trasmettere i caratteri in ASCII, appena incontra 0x00 considera il valore come terminatore di stringa e chiude la trasmissione ::slight_smile:

Dovresti provare con la Serial.write() nella sua forma: Serial.write(buf, len); che dovrebbe trasmettere in binario :wink:

Guglielmo

Alla fine vedi
ss.write(UBXmsg*);*
quindi converte in caratteri... Ma non sono i valori esadecimali...
Ad esempio, anziché 80kHz escono 14465Hz.
La cosa strana è che in parte funziona!

Datman:
Alla fine vedi
ss.write(UBXmsg*);*

Quello è il formato che nel reference è descritto come: Serial.write(str) = a string to send as a series of bytes. Non vorrei che anche li, se incontra 0x00 si blocchi.

Prova con il formato che ti ho detto, definendo il buffer come un array di uint8_t ed usando la forma: Serial.write(buf, len) = buf: an array to send as a series of bytes; len: the number of bytes to be sent from the array.

Guglielmo

Uhmm... 14465Hz è 3881, mentre 80000Hz è 013880... Uhmm...

gpb01:
Quello è il formato che nel reference è descritto come: Serial.write(str) = a string to send as a series of bytes. Non vorrei che anche li, se incontra 0x00 si blocchi.

... pensandoci ... è sicuro che si blocca al primo 0x00, altrimenti NON saprebbe dove terminare la trasmissione seriale!

Devi usare l'altra forma ... Serial.write(buf, len).

E si, 14465 è 0x3881 e 80000 è 0x013880 ... cosa non ti torna ? ? ?

Guglielmo

Non noti una certa ciclicità?...
Trasmette 38 81 anziché 01 38 80
No: con 100kHz i valori esadecimali sono completamente diversi

Datman:
Non noti una certa ciclicità?...

De che ? ? ? :o :o :o oh ... i valori in binario di un numero non è che te li inventi eh :smiley: :smiley: :smiley:

Guglielmo

Ma 0x00 c'è già al sesto byte, ben prima dell'invio della frequenza! Non dovrebbe mandare nulla...

Funziona bene fino a 32999Hz; con 33000 salta a 10082739! Sarà mica bacato il gps cinese?... >:( A 1MHz e a 10MHz, però, funziona!

Vuoi la dimostrazione pratica ... eccotela:

void setup() {
  // put your setup code here, to run once:
  char dati[] = {65, 66, 67, 00, 68, 69, 70};
  delay(500);
  Serial.begin(115200);
  Serial.print("Prima forma: ");
  Serial.write(dati);
  Serial.println();
  Serial.print("Seconda forma: ");
  Serial.write(dati,7);
  Serial.println();
}

void loop() {
  // put your main code here, to run repeatedly:

}

... fai girare e vedi quello che stampa !

Ah ... la Serial.write(str) NON accetta uint8_t, ma vuole char !

Guglielmo

L’array è di tipo byte: non è che è stato scelto byte proprio per evitare il problema del null, che così non viene riconosciuto?
Ciò che mi fa pensare è che fino a 32999Hz e per frequenze con diversi zeri finali funziona…
Potrebbe essere un problema intrinseco del modulo gps?

Ma le prove con Arduino non te le sai fare da solo ? ? ? :smiley: :smiley: :smiley:

… comunque, se provassi prendendo il codice di cui al post precedente, vedresti che la Serial.write(str) di un byte array da errore:

Arduino: 1.8.9 (Mac OS X), Board: "Arduino/Genuino Uno"
/var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/arduino_modified_sketch_263773/sketch_jun04b.ino: In function 'void setup()':
sketch_jun04b:7:20: error: no matching function for call to 'write(byte [7])'
   Serial.write(dati);
                    ^
In file included from /Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/Arduino.h:232:0,
                 from /var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/arduino_build_988045/sketch/sketch_jun04b.ino.cpp:1:
/Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/HardwareSerial.h:129:20: note: candidate: virtual size_t HardwareSerial::write(uint8_t) <near match>
     virtual size_t write(uint8_t);
                    ^
/Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/HardwareSerial.h:129:20: note:   conversion of argument 1 would be ill-formed:
/var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/arduino_modified_sketch_263773/sketch_jun04b.ino:7:20: warning: invalid conversion from 'byte* {aka unsigned char*}' to 'uint8_t {aka unsigned char}' [-fpermissive]
   Serial.write(dati);
                    ^
In file included from /Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/Arduino.h:232:0,
                 from /var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/arduino_build_988045/sketch/sketch_jun04b.ino.cpp:1:
/Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/HardwareSerial.h:130:19: note: candidate: size_t HardwareSerial::write(long unsigned int) <near match>
     inline size_t write(unsigned long n) { return write((uint8_t)n); }
                   ^
/Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/HardwareSerial.h:130:19: note:   conversion of argument 1 would be ill-formed:
/var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/arduino_modified_sketch_263773/sketch_jun04b.ino:7:20: warning: invalid conversion from 'byte* {aka unsigned char*}' to 'long unsigned int' [-fpermissive]
   Serial.write(dati);
                    ^
In file included from /Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/Arduino.h:232:0,
                 from /var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/arduino_build_988045/sketch/sketch_jun04b.ino.cpp:1:
/Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/HardwareSerial.h:131:19: note: candidate: size_t HardwareSerial::write(long int) <near match>
     inline size_t write(long n) { return write((uint8_t)n); }
                   ^
/Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/HardwareSerial.h:131:19: note:   conversion of argument 1 would be ill-formed:
/var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/arduino_modified_sketch_263773/sketch_jun04b.ino:7:20: warning: invalid conversion from 'byte* {aka unsigned char*}' to 'long int' [-fpermissive]
   Serial.write(dati);
                    ^
In file included from /Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/Arduino.h:232:0,
                 from /var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/arduino_build_988045/sketch/sketch_jun04b.ino.cpp:1:
/Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/HardwareSerial.h:132:19: note: candidate: size_t HardwareSerial::write(unsigned int) <near match>
     inline size_t write(unsigned int n) { return write((uint8_t)n); }
                   ^
/Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/HardwareSerial.h:132:19: note:   conversion of argument 1 would be ill-formed:
/var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/arduino_modified_sketch_263773/sketch_jun04b.ino:7:20: warning: invalid conversion from 'byte* {aka unsigned char*}' to 'unsigned int' [-fpermissive]
   Serial.write(dati);
                    ^
In file included from /Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/Arduino.h:232:0,
                 from /var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/arduino_build_988045/sketch/sketch_jun04b.ino.cpp:1:
/Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/HardwareSerial.h:133:19: note: candidate: size_t HardwareSerial::write(int) <near match>
     inline size_t write(int n) { return write((uint8_t)n); }
                   ^
/Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/HardwareSerial.h:133:19: note:   conversion of argument 1 would be ill-formed:
/var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/arduino_modified_sketch_263773/sketch_jun04b.ino:7:20: warning: invalid conversion from 'byte* {aka unsigned char*}' to 'int' [-fpermissive]
   Serial.write(dati);
                    ^
In file included from /Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/Stream.h:26:0,
                 from /Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/HardwareSerial.h:29,
                 from /Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/Arduino.h:232,
                 from /var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/arduino_build_988045/sketch/sketch_jun04b.ino.cpp:1:
/Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/Print.h:52:12: note: candidate: size_t Print::write(const char*) <near match>
     size_t write(const char *str) {
            ^
/Applications/Arduino/Arduino 1.8.9 Portable.app/Contents/Java/hardware/arduino/avr/cores/arduino/Print.h:52:12: note:   conversion of argument 1 would be ill-formed:
/var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/arduino_modified_sketch_263773/sketch_jun04b.ino:7:20: warning: invalid conversion from 'byte* {aka unsigned char*}' to 'const char*' [-fpermissive]
   Serial.write(dati);
                    ^
exit status 1
no matching function for call to 'write(byte [7])'

… come vedi il tipo “byte array” NON è tra quelli supportati, quindi, da qualche parte, avviene qualche altra conversione in altro tipo supportato o neanche ti compilerebbe.

Guglielmo

Ti è sfuggito che sto usando NeoSWSerial, come ho scritto nel mio primo messaggio! :slight_smile: