unravelling 16 10-bit sensor stream
Hallo all
I have a stable Arduino ->Max environment, based on a patch offered here in recent months by Steven Miller (AFAIK), which reads 16 analog pins in turn then sends them off to Max with an ASCII CR/LF as punctuation. Using a combination of [match nn nn nn .......13 10] in Max and "if(Serial.available()>0" this works seamlessly (props to the original author).
I'm now tweaking it to allow full 10-bit resolution, which requires sending two bytes (high and low bytes) per sensor. My question is do I need a header byte for this new 'pair', or will the above handshaking method ensure byte ordering? And if so, how can I unravel the stream at t'other end?
Experiments continue....
Brendan
Or, stated slightly more clearly, how do I pack/unpack and conduct my highByte/lowByte maths while allowing for the ASCII 13 10 punctuation?
I started responding but then realized I mis-read. You would just send the values clumped together, high/low, high/low, high/low, and have your match be that long.
I'm curious to see your results as it's more finicky than it should be to get 10bit numbers into max.
Yes Rodrigo, I quickly arrived at the same conclusion: the handshaking protocol works fine, no hi/lo header byte needed. However, I'm just a little stumped as to how I should parse the hi/lo pairs and the terminating "13 10". If I use:
[match nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn nn 13 10]
I get each hi/lo pair in order; the attached patch may clarify the issue:
Brendan
This is my solution. My grouping coding is a bit clunky, but I couldn't figure out any other way for it to 'line up' right. And the bitshift stuff is there to merge the bytes back together.
This example shows how to do it with 3 hi-res pairs - lo-byte followed by hi-byte in each pair.
Thanks gents,
Steven's solution appears to be the most immediately transparent - in my sketch do i simply write:
loByte = myVal%4;
hiByte = myVal/4;
. . . . . .
Serial.write(loBye);
Serial.write(hiByte);
. . . . . .
Serial.println();
I suppose it's not important if they arrive hi/lo or lo/hi, as long as the bitshifting is performed on the correct byte?
Cheers
Correct - the order doesn't matter as long as the bit-shifting is appropriately handled at the receiving end.
Here's the corresponding sketch to the patch posted previously.
/*
This sketch reads analog sensors on pins A0, A1 & A2 and sends their values to the serial port for use in Max, Processing, etc.
It expands upon the previous sketch by adding the following:
It preserves the 10-bit resolution of the analog pins by breaking them into lo- and hi-byte values and sending these individually.
You must reconstruct the two-byte values in the receiving software in order to get the 10-bit value.
Steven M. Miller
*/
int SensorPins[3] = {0, 1, 2}; // Array to hold pin numbers of sensors
// fill with first 3 analog pins as default
// **NOTE: Change these numbers if using other pins
int SensorPrevVals[3] = {0, 0, 0}; // Array to hold previous sensor values
// fill with default value of 0
int Val = 0; // Variable for current value read from sensor pin
int NewVal = 0; // Variable for averaged sensor value ((current + previous) / 2)
int i = 0; // Variable for index for for-loop
int inByte = 0; // Variable for incoming serial data
void setup()
{
Serial.begin(9600);
}
void loop()
{
if(Serial.available()>0) // Is there data waiting in the serial port?
{ // If so, proceed with code block, otherwise don't
inByte = Serial.read(); // Read data from serial buffer and store in variable (to get rid of it)
for(i = 0; i < 3; i = i + 1){
Val = analogRead(SensorPins[i]); // Read sensor value and store in Val
NewVal = (Val + SensorPrevVals[i]) / 2; // Average current and previous values for smoothing
SensorPrevVals[i] = Val; // Store current Val as PrevVal for next time
sendBinary(NewVal); // Break NewVal into low & high bytes and send out
}
Serial.println(); // Send CR & LF (ASCII 13 & 10) to mark end of message
}
}
// function to send the given integer value to the serial port as two bytes
void sendBinary(int value)
{
// send the two bytes that comprise an integer
Serial.write(lowByte(value)); // send the low byte
Serial.write(highByte(value)); // send the high byte
}
That seems a lot more elegant than my solution, particularly on the Arduino side.
Have stable/reliable is it? Different things I've tried in the past have either stopped working at some point and/or blowing up the serial buffer on my laptop forcing a hard reboot.
Hi rodrigo
I have found Steven's solution to be rock solid, even with 16 noisy DIY fsrs, a 19200 bps and 5ms qmetro. Hope it continues.
Brendan
That's promising indeed. I'll give it a spin.