$MSGTYPE,value,value,value*HHThe output from the program below is:
$XY,10.1,20.0*03The content is all of the characters between the $ and the *. The last two characters are a CRC checksum (cyclic redundancy code) to provide an option for the receiving device to verify the message. It is 8 bits, formatted as two hex digits. A search for the way to generate this will lead to many variations of codes. It was a long search to find a solution that actually generated the correct 8-bit code used in gps NMEA style messages. [Here is a working calculator] The key part of the algorithm is the exclusive-OR of successive bytes:
for (byte x = start_with+1; x<end_with; x++){ // XOR chars between '$' and '*' CRC = CRC ^ buffer[x]; }
I wanted to use this format to send data from several different sensors between two embedded computer boards via serial hardware port. I didn't immediately need CRC coding, but decided to implement it for the sake of robustness that may be required in a future implementation. I converted the code that Elimeléc Lopez* posted into a callable function for Arduino. I used a global character array to hold the result. This code also illustrates the use of character arrays and String variables together in C++ syntax.
Code is executed on a Teensyduino 3.1. Output is printed to the monitor and to UART2, wired to the UART on an O-Droid C1 running linux. Its output is viewed via its comm port directed back to PC and observed in Teraterm.
(Update now maintained on gitHub.)
Usage:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | // Demonstrate the use of a function to generate the NMEA 8-bit CRC
// - A message is built and placed into a buffer string
// - The checksum is computed, and formatted to two chars
// - The full string is printed both to the IDE monitor and to a hardware UART
// EX1: $test* --> 16
// EX2: $GPRMC,023405.00,A,1827.23072,N,06958.07877,W,1.631,33.83,230613,,,A* --> 42
#define SERIALN Serial2 // define which hardware serial port (1 on TD2; 1.2.3 on TD3
const byte buff_len = 90;
char CRCbuffer[buff_len];
// create pre-defined strings to control flexible output formatting
String sp = " ";
String delim = ",";
String splat = "*";
String msg = "";
// --------------------------------------------------
void setup() {
SERIALN.begin(115200, SERIAL_8N1); // configure Teensy HW UART serial port
Serial.begin(115200); // Init and set rate for serial output (value doesn't matter for Teensy 3)
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo & Teensyduino 3
}
// build msg
Serial.println("NMEA CRC Demo");
char strX[8];
char strY[8];
float x = 10.1;
float y = 20;
String cmd = "$XY"; // a command name
dtostrf(x,4,1,strX); // format float value to string XX.X
dtostrf(y,4,1,strY);
msg = cmd + delim + strX + delim + strY + splat;
outputMsg(msg); // print the entire message string, and append the CRC
}
// -----------------------------------------------------------------------
void loop(){
}
// -----------------------------------------------------------------------
void outputMsg(String msg) {
msg.toCharArray(CRCbuffer,sizeof(CRCbuffer)); // put complete string into CRCbuffer
byte crc = convertToCRC(CRCbuffer);
Serial.print(msg); // omit CRC in console msg
|
*Based on: Generate commands and include NMEA-style 1-byte hex CRC. The algorithm in ArduinoWiring is from nmea-checksum-calculator.html by Elimeléc López