XBEE and EMG unitFIXME 180105 enklere og flere detalier Today we will look at communication with this EMG unit:
Analog (muscle) signals from the EMG unit looks like:
The EMG device interfaces to the outer world by use of a XBEE wireless serial device.
In your end we will have a XBEE to serial module which you interface by a standard serial port running with baudrate 115200. Communication protocol
It seems that all integers are 16 bit two's complement. with MSB byte first. You PC and Arduino is little endian. Exercise 1:Here is a code snippet - explain what is happening
char msb,lsb; // here you have your msb and lsb byte int intNumber; ... intNumber = (msg << 8) | lsb; lsb = (char) (intNumber & 0xff); msb = (char) ( (intNumber >> 8) & 0xff); Protocol as statemachineThis is a statemachine which in each state read the proper values from serial port or XBEE. The code for a skeleton state machine is here: CODE IS WITHOUT ANY WARRANTY typedef void *(*pF)(void); // for typecast for calling function #define NEXT(x,y,z) return ((void *)x) void *g7E(); void *gLgt(); void *gFrID(); void *gS(); void *gOptB(); void *gChIndM(); void *gAdcV(); void *gChkS(); void *start() { NEXT(g7E,start,n); } void *g7E() { // read bytes from serial port until we get a 0x7e do { while (! Serial.available() ); until ( Serial.read() == 0x7E); // yes we got it NEXT(gLgt,g7E, n); // next state } void *gLgt() { NEXT(gAPI,gLgt, n); } void *gAPI() { NEXT(gSAdr,gAPI,n); } void *gSAdr() { NEXT(gRSI,gSAdr,n); } void *gRSI() { NEXT(gOptB,gRSI,n); } void *gOptB() { NEXT(gChInd,gOptB,n); } void *gChInd() { NEXT(gAdcV,gChInd,n); } void *gAdcV() { NEXT(gChkS,gAdcV,n); } void *gChkS() { NEXT(doStuff,gChkS, n); } void *doStuff() { NEXT(g7E,doStuff,again); } pF statefunc = start, oldfunc = NULL; // whrere to start void main() { while(1) { oldfunc = statefunc; // if you want to see/track the previous state } statefunc = (pF)(*statefunc)(); // next state is called here // here statefunc is last and oldfunc is last last } return ; // should not get here } You might comsider just read a fixed number of bytes after your 0x7e starting character. Two other ways of showing packinformationExercise
For receing Arduino it's recommended to use a MEGA because it has 4 serial ports. In that case you can use Serial1 to connect to simulator or Xbee and Serial (Std port) to debugging messages on the screen An Arduino acting like …// #include <looptime.h> // EMG simulator /* Format for XBEE packets 0 0x7e - start ch 1 0x00 - length msb 2 0x14 - length lsb 3 0x83 - API frame identifier 4 0x56 - senders address 5 0x78 - senders address 6 0x43 - received signal strength - RSI 7 0x00 - option byte 8 0x01 - nu,mber of samples 9 0x3e - channel indicator mask n/a A5 A4 A3 A2 A1 A0 D8 10 0xe0 - channel indicatot mask D7 D6 D5 D4 D3 D2 D1 D0 11 0x00 - digital sample (msb) 12 0x40 - digital sample (lsb) 13 0x?? - Acc Z (msb) 14 0x?? - Acc Z (lsb) 15 0x?? - Acc Y (msb) 16 0x?? - Acc Y (lsb) 17 0x?? - Acc X (msb) 18 0x?? - Acc X (lsb) 19 0x?? - EMG ch1 (msb) 20 0x?? - EMG ch1 (lsb) 21 0x?? - EMG ch2 (msb) 22 0x?? - EMG ch2 (lsb) 23 0x?? - checksum The checksum is all bytes added together excl the first three. The sum including(!) the checksum shall give 0xff Strategy sum all bytes excluding first three. The checksum will be 0xff - sum */ char dataPkg[24] = {0x7e, 0x00, 0x14, 0x83, 0x56, 0x78, 0x43, 0x00, 0x01, 0x3e, 0xe0, 0x00, 0x40, 0x02, 0x9b, 0x02, 0x1a, 0x02, 0x05, 0x00, 0x00, 0x00, 0x05, 0x47 }; // from datasheet char hexTable[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; void setup() { Serial.begin(115200); while (! Serial) // wait until serial port is up and running { } delay(500); // just to be sure } char chksum(char *pk, int lgt) { char s = 0; for (int i = 0; i < lgt; i++) s += *(pk + i); return s; } void dmpPkgASCII(char *d, int lgt) { while (lgt--) { Serial.print("x"); Serial.print(hexTable[0x0f & (*d >> 4) ]); Serial.print(hexTable[*d & 0x0f]); Serial.print(" "); d++; } Serial.println(""); } void dmpPkg(char *d, int lgt) { while (lgt--) { Serial.write(*d); d++; } Serial.println(""); } void mkPkg(char *d) { int v; char msb, lsb; /* analog 0,1,2,3,4,5 to Z, Y, X, ch1, ch2 We can use a loop bq z,y,x,ch1,ch2 is in line in the package */ //for test only goto yy; for (int i = 0; i < 5; i++) { // z,y,x, ch1 ch2 v = analogRead(0 + i); // A0, A1, ... lsb = (char)(v & 0xff); msb = (char)(0xff & (v >> 8)); // Z, Y, X, ch1, ch2 d[i + 13] = msb; // 13 is msb for the first value : Z d[i + 14] = lsb; } // do chksum yy: // calculate chksum for first 23 bytes and subtract from 0xff to get value for chksum. d[23] = 0xff - chksum(d + 3, 23 - 3); // offset 3 bq first 3 bytes is not part of chksum (dont ask why) } void loop() { looptime(1000); //we will loop with 100 msec ~ 10 Hz mkPkg(dataPkg); dmpPkgASCII(dataPkg, 24); //dmpPkg(dataPkg, 24); } |