Spectrotilt 12bit RS232 help needed

One possibility is your machine has always sent 7 bits and no one bothered to fix it.
Paul

That would be a really cruel joke for a beginner. :rofl:

Yes. Serial.print() suppresses leading zeroes. When you print something out in binary and you get fewer digits than the variable will hold, all of the bits to the left are zeroes.

Try this little sketch to see what the timing of the data looks like:

void setup()
{
  Serial.begin(115200);
  Serial1.begin(9600);
}

void loop()
{
  int val = Serial1.read();
  if (val != -1)
  {
    Serial.print(micros());
    Serial.print(' ');
    Serial.println(val, BIN);
  }
}

Note the higher baud rate for Serial Monitor.

A dozen lines from Serial Monitor should tell us everything we need to know. The 7th bit will let us know which byte is the MSB (1) and which byte is the LSB (0). The microsecond timestamp will let us be absolutely sure which order the bytes are sent: "MSB, LSB, gap" or "LSB, MSB, gap".

1 Like

Perhaps printing as HEX instead of Binary would be easier to see what is what.
Paul

1 Like

2068972 1100
2083128 11100001
2084168 1100
2098208 11100001
2099248 1100
2113392 11100001
2114432 1100
2128576 11100001
2129616 1001011
2143656 11100001
2144696 1010
2158840 11100001

55541548 4D
55555584 E1
55556628 C
55570772 E1
55571808 C
55585952 E1
55586996 C
55601136 E1

I uploaded the sketch with the timestamp. It looks like just over 14ms to send the target frame and then and equal time high until the next set. The numbers i'm getting work. The sensor is sitting on my desk roughly vertical which should send 2048. So I have that part.

I can check the value of bit 7 and get my MSB correctly. However, when I pull the next byte out of the buffer, my LSB is just a lot of ones.
int MSB=0;
int LSB=0;
void setup()
{
Serial.begin(115200);
Serial1.begin(9600);
}

void loop()
{
int val = Serial1.read();
if (val != -1)
{
int bittest = bitRead(val,7);
if (bittest=1){
MSB = val;
LSB = Serial1.read();
}
Serial.print("MSB ");
Serial.println(MSB,BIN);
Serial.print("LSB ");
Serial.println(LSB,BIN);

//Serial.println(val,BIN);

}
}

Produces:
11111111111111111
10:22:42.501 -> MSB 1101100
10:22:42.501 -> LSB 11111111111111111111111111111111
10:22:42.501 -> MSB 11111001
10:22:42.501 -> LSB 11111111111111111111111111111111
10:22:42.547 -> MSB 1101100
10:22:42.547 -> LSB 11111111111111111111111111111111
10:22:42.547 -> MSB 11111001
10:22:42.547 -> LSB 11111111111111111111111111111111
10:22:42.547 -> MSB 101011
10:22:42.547 -> LSB 111111111111111

Do I need to test for LSB also or should I just be able to pull the next byte out of the buffer?

Did you wait until the second byte arrived in the buffer, or just read it after reading the first byte?
Can't tell from your current code!
Paul

1 Like

I did not. I just assumed the next byte would be there. Should I add a delay or there a more elegant solution?

If I try something like this, I get a zero for my LSB.
void loop()
{
int val = Serial1.read();
if (val != -1)
{
int bittest = bitRead(val,7);
if (bittest=1){
MSB = val;
int val = Serial1.read();
if (val != -1){
LSB = val;
}
}
image

Why delay? Just check for when the next byte is available!
Paul

1 Like

@jrm850, You didn't check to see if a character is available, using available(). You can call it elegant if you like... but it's the standard approach :slight_smile:

You should always use it, even for a device like this that constantly spews data. That's because you still can't predict when the data will be sent, and completely decoded by the UART.

Also please start using standard indentation, your code is hard to read without it. Auto format in the IDE will do it for you.

1 Like

Autoformat? That is amazing. I didn't even know it was there lol. Thank you.

I'm still getting a 0 for LSB with this snippet. I've tried a couple of different ways and so far the only thing that worked was a 50ms delay.
int MSB = 0;
int LSB = 0;
void setup()
{
Serial.begin(115200);
Serial1.begin(9600);
}

void loop()
{
int val = Serial1.read();
if (val != -1)
{
int bittest = bitRead(val, 7);
if (bittest = 1) {
MSB = val;
}
}
if (Serial.available() > 0)
{
int val = Serial1.read();
if (val != -1)
{
LSB = val;
}

}
Serial.print("MSB ");
Serial.println(MSB, BIN);
Serial.print("LSB ");
Serial.println(LSB, BIN);
}

It's wonderful that you like auto format, but you didn't use it. :neutral_face:

It's useless to check for available after you have already read a byte.. that's what you did

1 Like

:rofl: I had to go back and read the "How to use the forum". Hopefully it worked this time.

I think I have something sorted out, but I'm unsure if this is the best way to concatenate my two values. Since I'm using the lower 6 bits of each byte and I don't have 8 bits in every frame, I couldn't figure out how to get what I needed with bit shift operators. Is there a better way to stack the 6bits + 6bits?

Does checking for data in the buffer by using if (val != -1) have disadvantages over if(serial.available)?

int MSB = 0;
int LSB = 0;
int AngleM = 0;
int AngleL = 0;
int Angle = 0;
void setup()
{
  Serial.begin(115200);
  Serial1.begin(9600);
}

void loop()
{
  int val = Serial1.read();
  if (val != -1)
  {
    int bittest = bitRead(val, 7);
    if (bittest = 1) {
      MSB = val;
    }
  }

  int lval = Serial1.read();
  if (lval != -1)
  {
    LSB = lval;
  }
  for (int i = 5; i >= 0; i--) {
    int angM = bitRead(MSB, i);
    bitWrite(AngleM, i, angM);
  }
  for (int i = 5; i >= 0; i--) {
    int angL = bitRead(LSB, i);
    bitWrite(AngleL, i, angL);
    //Serial.println(angL, BIN);
  }
  Angle = (AngleM << 6) | (AngleL);
  Serial.print("MSB  ");
  Serial.println(MSB, BIN);
  Serial.print("LSB  ");
  Serial.println(LSB, BIN);
  //Serial.println(AngleM, BIN);
  //Serial.println(AngleL, BIN);
  Serial.println(Angle, BIN);
  //delay(100);
  Angle = 0;
}

Yeah, that's pedestrian. Use C/C++ native masking and shift logic:

int result = (LSB & 0x3F) + ( (MSB & 0x3F) << 6 )

The flow is pedestrian too. You should check for a valid character just once. Then sort out whether it is a high or low byte.

void loop()
{
  if (Serial1.available()) {
  int val = Serial1.read();
   if (bitRead(val, 7)
     MSB = val;
   else
     LSB = val;
  }
}

As I mentioned before, you need a "lock" while the second half is not received yet. Suppose you use the values at a time when the variables contain the current high byte and the previous low byte... they don't match, it's an error.

This is a deliberate puzzle from me - I hand you a solution but also a problem to solve yourself. Hint - how would you know when a high byte is received?

available() will tell you how many bytes are in the buffer, a read value of -1 only tells you that there are none. In your case, it makes no difference.

Then you would have:

void loop()
{
  int val = Serial1.read();
  if (val != -1) {
   if (bitRead(val, 7)
     MSB = val;
   else
     LSB = val;
  }
}
1 Like

OK! So MSB first, then LSB. The even parity bit is working (each of the bytes has an even number of 1 bits).

Taking the bottom 5 bits of the two bytes:

2083128 1000 0100 1100 = 0x84C = 2124 or -1972
2098208 1000 0100 1100 = 0x84C = 2124 or -1972
2113392 1000 0100 1100 = 0x84C = 2124 or -1972
2128576 1000 0100 1011 = 0x84B = 2123 or -1973
2143656 1000 0100 1010 = 0x84C = 2124 or -1972
1 Like

Ahhh, I get it now. If I wanted to get 7 bits out of the byte I would mask (LSB & 0x7F).

For the lock... my original plan was to just put it in a sub and run it sequentially, but the rest of my program does bounce around with interrupts so that doesn't seem like a good idea. I could turn off the timers while in the sub or put it in a while loop or both? Maybe a state machine to track the pairs? I will play around with it some.
I really appreciate the help! I'm learning a lot.

Those numbers work and are what I should expect from the sensor. Now I just need to multiply by .03425 and I will have a gravitational tilt angle. I appreciate you helping.

It's the bottom 6 bits of the two bytes. Not 5. For the lock, everything you mentioned is overkill. Just

void loop()
{
  if (Serial1.available()) {
  int val = Serial1.read();
   if (bitRead(val, 7)
     MSB = val;
   else
    {
     LSB = val;
     result = (LSB & 0x3F) + ( (MSB & 0x3F) << 6 );
    }
  }
  // do something with result here
}

It's all about seeing the problem, not the solution. :slight_smile:

1 Like

2083128 1000 0100 1100 = 0x84C = 2124 or -1972
2098208 1000 0100 1100 = 0x84C = 2124 or -1972

So, is the angle 72.747 or -67.541?

It's actually 2.6⁰ clockwise. I forgot to say that 2048 is the vertical value.

Everything is working perfectly and stable.

I really appreciate everyone's help, and by help I mean doing it for me. I did try to figure it out on my own but my methods are so clumsy. My background is mechanical and I only work on a processor project every couple of years. Anyway... I've learned more in a week than I have in 20 years about serial communication and binary manipulation.
Thank you all!