Ciao a tutti,
vorrei mettere in comunicazione un mio PLC Omron e l'arduino tramite il protocollo Hostlink. (in allegato la descrizione con degli esempi di utilizzo)
Il problema è nella costruzione della stringa, soprattutto quando cerco di creare il checksum.
Vi allego il codice che ho scritto fin ora
Avrai in memoria, c come variabile carattere che può contenere un carattere e occupa 1 byte.
vc è un vettori di 3 caratteri con i valori 'A','B','C'
vs è una stringa (vettore di caratteri terminato da '\0' carattere fine stringa) e il vettore è di 6 caratteri (5+1)
pc non è una cella che può contenere un carattere ma contiene un puntatore ovvero l'indirizzo a qualcosa.
Questo puntatore può puntare vettori o variabili di tipo carattere. Attraverso di lui potrai leggere/scrivere un carattere.
Nell'esempio pc punta al primo elemento di vs (elemento 0).
Scrivere
vs[2]='X';
oppure
*(pc+2)='X';
è uguale.
pc è particolare perchè di un puntatore puoi modificare il contenuto ovvero l'indirizzo , esempio:
ps=ps+1;
Ora ps punta alla cella 1 di vs.
Attraverso ps (usando come sintassi l'asterisco) allora usi l'indirizzo e leggi/scrivi quello a cui il puntatore punta:
ciao,
grazie mille per la spiegazione, sei stato chiarissimo!
Per il calcolo dell'FCS ho trovato questo esempio scritto in c su un forum Omron. Stavo cercando di adattarlo al mio programma ma non ci sono ancora riuscito.
Puoi suggerirmi qualcosa?
/* Calcola la somma di controllo */
CalcFCS(char *stringa)
{
int l,index;
l=strlen(stringa); // l = lunghezza della stringa
FCS='@'; // inizializzo il valore
for(index=1;index < l;index++)
FCS^=*(stringa+index); // eseguo XOR per tutti i caratteri
return 0;
}
Public Function CalcoloFcs(TestoFcs As String) as String
Dim lun As Integer, idx As Integer, somma As Integer, car As integer, ret As String
lun = Len(TestoFcs)
somma = 0
For idx = 1 To lun
car = Asc(Mid$(TestoFcs, idx, 1))
somma = somma Xor car
Next idx
ret = Hex$(somma)
If Len(ret) = 1 Then ret = "0" & ret
CalcoloFcs = ret
End Function
In VB: ? CalcoloFcs("@00WD00001234") -> "57" @00WD0000123457*
Complesso ritornare in C una stringa (è un vettore), meglio ritornare il valore in cifra. Poi il confronto lo farai convertendo anche il secondo valore in cifra.
unsigned char CalcFCS(char *str, int lun)
{ unsigned char sum=0;
for(int i=0;i<lun;i++)
{ sum ^= *(str+i);
}
return sum;
}
...
chiamata:
unsigned char chk=CalcFCS(stringa,sizeof(stringa)); // numero elementi del vettore
oppure
unsigned char chk=CalcFCS(stringa,strlen(stringa)); // solo se stringa ha terminatore '\0' !!!
oppure
unsigned char chk=CalcFCS(stringa,13); // numero fisso, sai tu quanti elementi sono validi, mi sembra nel tuo primo esempio, 13 elementi poi chksum
Quindi la funzione CalcFCS() ti dà il valore decimale (un byte).
Devi a questo punto prendere la parte bassa (prima 4 bit) e la parte alta (secondi 4 bit) e convertirli in una cifra ascii
dove '0' è 48, '1' è 49 etc.
Se i primi 4 bit sono 0100->ovvero 4 sommando 48 ottieni 52 ovvero in ascii -> '4'
Secondi 4 bit sono 0110-> ovvero 6 +48->54->'6'
ed hai i due caratteri da mettere nelle celle 13 e 14 (credo) e poi in 15° cella '*' e in 16° cella il valore 13
nid69ita:
Ho capito ora, il checksum è da aggiungere ad una stringa da spedire, non per controllare in risposta.
...
Il "checksum" serve per controllare che i dati trasmessi arrivino corretti, indipendentemente da chi riceve e da chi trasmette.
Chi trasmette (chiunque sia) prende il blocco dei dati, con una data formula calcola il checksum ed invia al ricevente sia i dati che il checksum. Il ricevente riceve i dati, calcola anche lui il checksum con la stessa formula e lo compara con quello che ha ricevuto. Se è uguale i dati sono arrivati correttamente, se è diverso i dati vengono scartarti perché sono arrivati corrotti.
E' quindi fondamentale il calcolo corretto del cheksum altrimenti i due NON si parlano.
Si, @gpb quel che non avevo capito subito è che @blasted stà per ora implementando la costruzione del msg di invio, mentre io ero già al check del msg d'arrivo
La stessa funzione la potrai usare nel controllare la risposta, confrontando 2 numeri, uno dato dalla CalcFCS() sui primi 13 caratteri e l'altra cifra la devi calcolare prendendo il carattere in cella 13 e 14 e facendo il procedimento inverso.
chk1=CalcFCS(stringa,13);
chk2=(stringa[13]-(stringa[13]>9?55:48))*16 + (stringa[14]-(stringa[14]>9?55:48) );
// * 16 equivale a spostare a sinistra di 4 bit
if(chk1==chk2) // okay
In C, in questo caso, è meglio lavorare con i numeri che con le stringhe alla Basic.
nid69ita:
Si, @gpb quel che non avevo capito subito è che @blasted stà per ora implementando la costruzione del msg di invio, mentre io ero già al check del msg d'arrivo
...
blasted: @nid69ita
poi vorrei sapere perchè in questo esempio metti nella posizione 12 il valore 1?
Copiato dal tuo esempio iniziale dove caricavi ogni elemento a mano.
87 decimale => 57 esadecimale, la versione VB lo dà in esadecimale, quella in C in decimale (usa Serial.println(xx,HEX); per vederlo in esa)
Metti anche una bella una bella Serial.println(chk); per vedere cosa calcola la funzione.
Credo comunque di aver fatto un errore, manca la conversione in esadecimale. Quelle due cifre devono essere in esa, giusto? da 0-9 no problem, 10-15=>A-F
Si bisognerebbe convertire i 2 valori in esadecimale.. Come posso fare?
Mi servirebbe anche perchè ho un'altro vettore da 16 contenente o 1 o 0 e dovrei prima dividerlo in 4 parti e poi convertirlo in esadecimale.
per la divisone penso che non ci siano problemi, mentre per la conversione non saprei come fare.
Ci sono istrzioni che fanno questo?
Guarda che nel mio post precedente ho aggiunto la conversione di quei due valori in esa e anche il post dove ho messo il codice per testata la risposta l'ho aggiornato.
blasted:
Mi servirebbe anche perchè ho un'altro vettore da 16 contenente o 1 o 0 e dovrei prima dividerlo in 4 parti e poi convertirlo in esadecimale.
per la divisone penso che non ci siano problemi, mentre per la conversione non saprei come fare.
Ci sono istrzioni che fanno questo?
nid69ita:
Guarda che nel mio post precedente ho aggiunto la conversione di quei due valori in esa e anche il post dove ho messo il codice per testata la risposta l'ho aggiornato.
Dove? non riesco a trovare il pezzo della conversione
Ora discrimino con un if in linea se il valore supera 9 perchè 0-9=>'0'-'9' ma 10-15=>'A'-'F'
Ti metto il metodo meno leggibile ma più stringato:
stringa[13]=highByte(chk)+(highByte(chk)>9?55:48); // se valore>9 55 else 48
stringa[14]=lowByte(chk) +(lowByte(chk) >9?55:48); // utilizzo if in linea