Ampersant & =bitwise AND?

Hello,

Short question. I'v looked it up and this; the & before a identifier; should be a bitwise AND.
But i want to play with a UART ultrasonic distance sensor A02YYUW. I'v ordered the wrong one but i was dissecting the code a bit.
On this webpage that person states that the checksum = the sum fo the first 3 incomming bytes in the data buffer.

/*
  JSN-SR04T-V3.0 Ultrasonic Sensor - Mode 1 Demo
  srt04-mode1.ino
  Uses JSN-SR04T-V3.0 Ultrasonic Sensor
  Displays on Serial Monitor

  Mode 1 is set by bridging "M1" pads on board

  Also works with A02YYUW Ultrasonic Sensor

  DroneBot Workshop 2021
  https://dronebotworkshop.com
*/

// Include the Software Serial library
#include <SoftwareSerial.h>

// Define connections to sensor
int pinRX = 10;
int pinTX = 11;

// Array to store incoming serial data
unsigned char data_buffer[4] = {0};

// Integer to store distance
int distance = 0;

// Variable to hold checksum
unsigned char CS;

// Object to represent software serial port
SoftwareSerial mySerial(pinRX, pinTX);

void setup() {
  // Set up serial monitor
  Serial.begin(115200);
  // Set up software serial port
  mySerial.begin(9600);
}

void loop() {

  // Run if data available
  if (mySerial.available() > 0) {

    delay(4);

    // Check for packet header character 0xff
    if (mySerial.read() == 0xff) {
      // Insert header into array
      data_buffer[0] = 0xff;
      // Read remaining 3 characters of data and insert into array
      for (int i = 1; i < 4; i++) {
        data_buffer[i] = mySerial.read();
      }

      //Compute checksum
      CS = data_buffer[0] + data_buffer[1] + data_buffer[2];
      // If checksum is valid compose distance from data
      if (data_buffer[3] == CS) {
        distance = (data_buffer[1] << 8) + data_buffer[2];
        // Print to serial monitor
        Serial.print("distance: ");
        Serial.print(distance);
        Serial.println(" mm");
      }
    }
  }
}

But in a other example found in the forum the first three bytes are added (sum) and that result is undergoing a bitwise AND with 0x00FF.

/*
  *@File  : DFRobot_Distance_A02.ino 
  *@Brief : This example use A02YYUW ultrasonic sensor to measure distance
  *         With initialization completed, We can get distance value 
  *@Copyright [DFRobot](https://www.dfrobot.com),2016         
  *           GUN Lesser General Pulic License
  *@version V1.0           
  *@data  2019-8-28
*/

#include <SoftwareSerial.h>

SoftwareSerial mySerial(11,10); // RX, TX
unsigned char data[4]={};
float distance;

void setup()
{
 Serial.begin(57600);
 mySerial.begin(9600); 
}

void loop()
{
    do{
     for(int i=0;i<4;i++)
     {
       data[i]=mySerial.read();
     }
  }while(mySerial.read()==0xff);

  mySerial.flush();

  if(data[0]==0xff)
    {
      int sum;
      sum=(data[0]+data[1]+data[2])&0x00FF;
      if(sum==data[3])
      {
        distance=(data[1]<<8)+data[2];
        if(distance>30)
          {
           Serial.print("distance=");
           Serial.print(distance/10);
           Serial.println("cm");
          }else 
             {
               Serial.println("Below the lower limit");
             }
      }else Serial.println("ERROR");
     }
     delay(100);
}

Why would there be needed a bitwise AND?

      sum=(data[0]+data[1]+data[2])&0x00FF;
      if(sum==data[3])

Is this adding a empty 'byte' of the sum to get a int?

if(sum==data[3])

..because sum is a int?
..does that mean that in the first sketch the sum of the first three unsigned char's in the data_buffer[] is 'overflowing'? So the most significant bits are automatically dumped to get unsigned char CS in 8 bits?

thx!

to limit the value to just the lower 8 bits

The checksum is a single byte.

The first code achieves this by assigning the result of the data total to a single byte variable.

The second code achieves it by using bitwise and to mask off all but the required byte.

The ampersand (&0x00FF) masks (makes zero) the high byte of the int.

In the first example this is not needed because CS is an unsigned char (byte) and anything bigger than 0xFF is thrown away, in the second example it's sum is an int.

1 Like

I've just adjusted my final questions but you beated me to the finish!
Thanks you everybody for confirming my questions/supposals!

Does it?..in some cases it can 'overflow' if the sum is 'larger' than 8 bits

i believe the value will be limited to the size of the variable being set.

It's not a buffer[] overflow. I hope that below demonstrates what happens.

void setup()
{
  Serial.begin(115200);
  while (!Serial) {}

  uint8_t b1 = 0xFF, b2 = 0x10, bsum;
  int16_t i1 = 0xFF, i2 = 0x10, isum;

  bsum = b1 + b2;
  isum = i1 + i2;

  if(bsum < 0x10) Serial.print("0");
  Serial.println(bsum, HEX);
  if(isum < 0x10) Serial.print("0");
  Serial.println(isum, HEX);
  isum &=0xFF;
  if(isum < 0x10) Serial.print("0");
  Serial.println(isum, HEX);
}

void loop()
{
}

yes i see it now.

void setup()
{
  Serial.begin(115200);
  while (!Serial) {}

  uint8_t b1 = 0xFF, b2 = 0x10, b3 = 0x2E, bsum, bbsum;
  uint16_t i1 = 0xFF, i2 = 0x10, i3 = 0x2E, isum, iisum;

  bsum = b1 + b2;
  Serial.println("bsum=");
  Serial.println(bsum, HEX);
  Serial.println(bsum, BIN);
  isum = i1 + i2;
  Serial.println("isum=");
  Serial.println(isum, HEX);
  Serial.println(isum, BIN);


  bbsum = b1 + b2 + b3;
  Serial.println("bbsum=");
  Serial.println(bbsum, HEX);
  Serial.println(bbsum, BIN);
  iisum = i1 + i2 + i3;
  Serial.println("iisum=");
  Serial.println(iisum, HEX);
  Serial.println(iisum, BIN);

  if(bbsum < 0x10) Serial.print("0");
  Serial.println(bbsum, HEX);
  if(iisum < 0x10) Serial.print("0");
  Serial.println(iisum, HEX);
  isum &=0xFF;
  if(iisum < 0x10) Serial.print("0");
  Serial.println(iisum, HEX);
}

void loop()
{
}

unint8 's are just added like normal but the 'adding' gets 'cut off' at 8 bits. I called it a overflow but it is just a stop in length and that's why the least significant bits stay the same as in the unint16 's.
thx

Actually in C++ the norm states that If a, b, and c are uint8_t, then when you do c = a + b;, both a and b are promoted to int, the addition is performed as a signed int, and the result is then implicitly converted back to uint8_t, which wraps around modulo 256.

➜ There is no way in standard C++ to force the addition a + b to be performed directly as uint8_t (i.e. as an 8-bit operation without promotion), because the language automatically promotes operands smaller than int before arithmetic.

This implicit type promotion is to be kept in mind when you do maths with bytes on a 16 bits MCU, esp if you multiply and overflow the positive int and intend to use the result as a parameter to a function that supports int as a type:

Try

uint8_t a = 200;
uint8_t b = 200;
uint8_t c = a * b;

Serial.println(a*b); //  -25536 as print sees an int 
Serial.println(c);  // as expected 64

So don’t forget to store as a byte or mask the value to get rid of the higher bits and get the expected result, in the example above

Serial.println((a*b) & 0xFF); // as expected 64

Print still sees an int but you extracted the least significant byte.

it's actually called "wraparound". adding 1 2 to an 8-bit variable having a value of 255 doesn't remain at it's max of value of 255 or 0xff, it now becomes 1 which is the value of the lower 8 bits of the sum.

the same is also true when subtracting a larger unsigned value from a smaller unsigned value with the same # of bits. subtracting 250 from 1 results in 7.

 a   1 0x01
 b 250 0xfa
 c   7 0x07

It becomes 0

(Now good with +2 instead of +1)

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.