Go Down

Topic: Who knows how to use bit shift <<? (Read 91 times) previous topic - next topic

laptophead

I am trying to read an encoder from a motor that puts out a string of Hex numbers.

I attached the manufacturer instructions.

The string I get looks like this:
BYTE 0:0 1:92 2:3 3:8 4:DB 5:F6 6:B1 7:0 8:0 9:0 10:0 11:0 12:0 13:A7

and values are changing as I turn the rotor.

In order to compose the encoder reading I tried:

  int64_t  Enc_Read = mybuffer_A[5] + mybuffer_A[6] << 8  + mybuffer_A[7] << 16  + mybuffer_A[8] << 24  + mybuffer_A[9] << 32 
+ mybuffer_A[10] << 40 + mybuffer_A[11] << 48 + mybuffer_A[12] << 56;


   int Enc = Enc_Read;
  Serial.println (Enc);

But all I get are Zeros.   Arduino page is very short on this command.

Please help

Thanks
Mitch

david_2018

#1
Feb 18, 2020, 04:35 am Last Edit: Feb 18, 2020, 04:57 am by david_2018
You will need to cast mybuffer_A to (int64_t) to do the bitshift, otherwise the compiler defaults to a 16-bit integer, which is too small for the shift operation.

Trying to set a 16-bit integer to the value of the 64-bit integer is not going to work either, in your example that would give 0xB1F6, which is a negative number.  You could use a 32-bit integer, but would be better to check the value first to make sure it is within range.

Since the data is coming in as 8 bytes, with the least significant byte first, my preference would be to use a union to redefine the 8 bytes as an int64_t and forget the bitshifting.  

Code: [Select]

union {
  uint8_t Byte[8];
  int64_t LongLong;
} Enc_Read;

byte mybuffer_A[] = {0x00, 0x92, 0x03, 0x08, 0xDB, 0xF6, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA7
                    };

void setup() {
  Serial.begin(115200);
  byte checksum = 0;
  for (byte i = 0; i < 8; i++) {
    Enc_Read.Byte[i] = mybuffer_A[i + 5];
    checksum = checksum + mybuffer_A[i + 5];
  }
  int32_t Enc = Enc_Read.LongLong;
  Serial.print("Enc: ");
  Serial.println(Enc);
  Serial.print("Checksum: ");
  if (checksum < 16) {
    Serial.print('0');
  }
  Serial.print(checksum, HEX);
  Serial.println(' ');
  
  int64_t  Enc_Read_2 = (int64_t)mybuffer_A[5] +
                      ((int64_t)mybuffer_A[6] << 8)  +
                      ((int64_t)mybuffer_A[7] << 16) +
                      ((int64_t)mybuffer_A[8] << 24) +
                      ((int64_t)mybuffer_A[9] << 32) +
                      ((int64_t)mybuffer_A[10] << 40) +
                      ((int64_t)mybuffer_A[11] << 48) +
                      ((int64_t)mybuffer_A[12] << 56);
  int32_t Enc_2 = Enc_Read_2;
  Serial.print("Enc2: ");
  Serial.println(Enc_2);
  while (true) {};
}

void loop() {
}



(edit) When using bitshift to combine the bytes into an int64_t, it is more efficient to use bitwise OR instead of addition.

laptophead

David ,

Thanks a lot, The sketch is running fine on an Ardu Mega
but I am using a teensy 3.6,

 I have to.

I am reading 6 motors and I have to have the UART Ports....etc

The Teensy just freezes and won't serial output anything....

Please help

Thanks

laptophead

#3
Feb 18, 2020, 05:37 am Last Edit: Feb 18, 2020, 05:43 am by laptophead
Actually , I  got it to read on teensy,

I did not declared the union, I just used

void Enc_Calc_A(uint8_t motor_id)
 
{ Show_Inc_String ('A');
  int64_t  Enc_Read_2 = (int64_t)mybuffer_A[5] +
                      ((int64_t)mybuffer_A[6] << 8)  +
                      ((int64_t)mybuffer_A[7] << 16) +
                      ((int64_t)mybuffer_A[8] << 24) +
                      ((int64_t)mybuffer_A[9] << 32) +
                      ((int64_t)mybuffer_A[10] << 40) +
                      ((int64_t)mybuffer_A[11] << 48) +
                      ((int64_t)mybuffer_A[12] << 56);


   long Enc_2 = Enc_Read_2;

 
  Mot_Ang_Read [motor_id] = (360 * Enc_2) / 16383.00;
    Serial.print("Enc2: ");
  Serial.println(Enc_2);
   Serial.print("Mot_Ang_Read deg: ");
  Serial.println(Mot_Ang_Read [motor_id]);
 
}

I got excited when the numbers went up as I turned the shaft and became negative as I went CCW....

Then I applied the conversion to degrees,  one full turn is 16383 pulses.

Then I realized that the numbers are wrong twice as high but not exactly twice.

Here is what I get after and approximate positive one turn of 360


 A: BYTE 0:0 1:92 2:3 3:8 4:DB 5:2B 6:8C 7:0 8:0 9:0 10:0 11:0 12:0 13:B7 14:0 15:0 16:0 17:80 
Enc2: 35883
Mot_Ang_Read deg: 788.49


Here how I process the incoming string:
if (Serial2.available()) {  // for motors 12345
    uint8_t b = Serial2.read();  // always read the next incoming byte
    if (b == 0x3E) {
      num_received_A = 0;  // if begin of message, forget everything previously received
    }

    else {  // we are done with the header
      mybuffer_A[num_received_A + 1] = b; // otherwise, put the byte into the buffer
      num_received_A ++;
      //Serial.println (num_received_A);

      if (num_received_A == (4 + mybuffer_A[3] ))// this  is "message Complete" first four bytes + the Data Lenght
      {
        if  (mybuffer_A[1] == 0x92 )
          Enc_Calc_A(mybuffer_A[2]);

        else if (mybuffer_A[1] == 0x9C)
        { ReadMot_Calc_A(mybuffer_A[2]);
          // Show_Inc_String ('A');
        }

        else if  (mybuffer_A[1] == 0x30 or mybuffer_A[1] == 0x31 or mybuffer_A[1] == 0x32)  // 30 31 and 32 are pertaining to PID
        { Read_PID_Calc('A');
          // Show_Inc_String ('B');
        }

        else
          Show_Inc_String ('A');

      }

    }  // end of "if getting bytes in the array
    // check if the buffer is full (shouldn't happen, right?)
    if (num_received_A >= 20) {
      num_received_A = 0;  // discard everything
      Serial.print(" Overflow A");
      Show_Inc_String ('A');
    } // end of else iteration

  } // end of ser available

The condition
mybuffer_A[1] == 0x92
applies to receiving this multi angle turn data, calling the function above.

What to do?
Thank you  David,

Go Up