Seeking help with arrays and data manipulation please.

Hi

I'm not a frequent poster as I find this forum helps resolve most queries, but I'm seeking a little help if possible please.
I may be approaching my solution from the wrong angle entirely but this is where I'm at.

I am trying to read a digital signal on a data pin and record the state of the pin at set intervals. There will be 16 samples.
I would like to end up with two seperate bytes of data which I can then use in other functions.

My code functions but the result is not as expected.

I know it's my conversion of the array to the uint8_t which is wrong. First issue is the result is backwards, it also misses 0's and in some cases I get what I will call an overflow (correct term?)

Here are a few examples of array vs converted which will hopefully explain better:-

*Example 1 - Missing 0's and backwards

11111110,00101011 // Data printed to the serial from the array
1111111,11010100 // Data printed to serial following conversion to uint8_t

*Example 2 - missing 0's, backwards and overflow

11111111,00000000 // Data printed to serial from array
11111111,0 // Data printed to serial following conversion
11111111,11111111 // Overflow?
11111111,11111111 // Overflow?

*Example 3 - Ok but both bytes are backwards

00000001,11110001 // Data printed to serial from array
10000000,10001111 // Data printed to serial following conversion

I have tried quite a few things to resolve - Changing array data type, using atoi, changing array length.
I know the conversion is the main issue but if someone could offer some help I'd appreciate it.
I obviously have an issue with the main capture into the array as the 'overflow' is present here as well, I have tried using delimiter '\0' but this doesnt seem to help.

Originally I captured all of the 16 bits into an array with a view to splitting it afterward, but I had the same issue with conversion.

Thanks

int pinstate;
int pin = 4;                               // Input on pin 4                                
uint8_t arrLength = 8;                     // 8no samples
uint8_t LStoredData[9];                    // Lo byte storage set to 9 to include delimeter? 
uint8_t HStoredData[9];                    // Hi byte storage set to 9 to include delimeter? 



void setup(void) {
  pinMode(pin, INPUT);                   // Set pin to input
  Serial.begin(9600);
  delay(15);                             // Settle time for serial init
  Serial.println("Ready to Sample");     // Send text just to check it's alive
}

void loop(void) {
  
pinstate = digitalRead(pin);              // Read and monitor input for change. Input is normally High
        // Read and store High byte

if (pinstate ==LOW) {                    // If input goes low, begin capture   
for (int i = 0; i < arrLength ; i++) {   // Loop 8 times to capture High Byte
delayMicroseconds(830);                  // Sample every x Microseconds               
LStoredData[i] = digitalRead(pin);       // Read current pin level and move to array
Serial.print (LStoredData[i]);           // Print to serial 
}

Serial.print (",");                      // Make it easier to read the two bytes on serial 

        // Read and store Low Byte

for (int i = 0; i < arrLength ; i++) {       // Loop 8 times to capture High Byte
delayMicroseconds(830);                  // Sample every x Microseconds
HStoredData[i] = digitalRead(pin);       // Read current pin level and move to array
Serial.print (HStoredData[i]);           // Print to serial
}

Serial.println ();                       // New line on serial monitor


        // Convert data in arrays to a useable real number
      //Convert Low Byte
      
uint8_t LB = 0;                          // create variable for Low Byte 
  for (int i = 0; i <8; i++)             // setup loop to shift 8 bits of data from array
  {
    LB |= LStoredData[i] << i;           // Shift the data from the Low byte array into a uint8_t variable
  }
Serial.print(LB, BIN);                   // Print result to serial
  
Serial.print (",");                      // Make it easier to read the two bytes on serial

    //Convert High Byte
    
uint8_t HB = 0;                          // create variable for High Byte
  for (int i = 0; i <8; i++)             // setup loop to shift 8 bits of data from array
  {
    HB |= HStoredData[i] << i;           // Shift the data from the Low byte array into a uint8_t variable
  }
Serial.println(HB, BIN);                 // Print result to serial

  }                                      // end 
 }                                       // end loop
uint8_t LStoredData[9];                    // Lo byte storage set to 9 to include delimeter?
uint8_t HStoredData[9];                    // Hi byte storage set to 9 to include delimeter?

You do not need two 9 element (or even 8 element) arrays to store 16 bits. An unsigned int, and bitSet(), would do. Then, there is no possibility of getting the bits in the wrong order.

delayMicroseconds(830);                  // Sample every x Microseconds

That comment is a bunch of happy horsesh*t. The Serial.print() statement in the for loop will affect timing.

  for (int i = 0; i <8; i++)             // setup loop to shift 8 bits of data from array
  {
    LB |= LStoredData[i] << i;           // Shift the data from the Low byte array into a uint8_t variable
  }

Using an int to iterate from 0 to 7 is a waste.

Do you KNOW the precedence of the operators you are using? I don't, so I would be using parentheses to force the statement to be evaluated the way I want.

Actually, I wouldn't, because saving 16 bits of data in two arrays, and then combining them is silly. Just bitSet() the bit in an unsigned int, and there is not need to "combine" the arrays.

@OP

You are sampling the states of DPin-4 for 16 times at 830 us interval, and you are collecting 16 separate bits. Let us assume that the very first sampled bit is the MS-bit. May we proceed in this way:

1. Declare a 16-bit unsigned variable x.

unsigned int x = 0; //x15 x14 x13, ..., x1, x0

2. Read the state of DPin-4 and save it at position x15 of x.

bitWrite(x, 15, digitalRead(4));

3. Extend the instruction of Step-2 for all the bits of x using for() loop.

for (left for you)
{
   //left for you
}

4. Now, split the value of x into bytes:

byte lowerByte = lowByte(x);
byte upperByte = highByte(x);

Thank you both, very interesting and I'm extremely grateful for the help.
I've experimented with both your solutions but I'm still having a few troubles.

@PaulS

I know using delayMicroseconds is wrong and I plan to implement a timing loop instead, this just seemed a good way to quickly test the bit storage.

I have implemented your suggestion but might be using bitSet() incorrectly?
I've setup an unsigned int called data, When I try to serialprint 'data' after the sample loop is complete it only prints one value.
I am assuming therfore I am not filling 'data' correctly?

  • Result

1111111100000101 // Serial printed result by printing each bit during the loop
1 // Serial printed result by printing 'data'

int pinstate;
int pin = 4;                               // Input on pin 4                                
uint8_t arrLength = 16;                     // 8no samples
unsigned int data =0;


void setup(void) {
  pinMode(pin, INPUT);                   // Set pin to input
  Serial.begin(9600);
  delay(15);                             // Settle time for serial init
  Serial.println("Ready to Sample");     // Send text just to check it's alive
}

void loop(void) {
  
pinstate = digitalRead(pin);              // Read and monitor input for change. Input is normally High

if (pinstate ==LOW) {                     // If input goes low, begin capture 
  data =0;  
for (int i = 0; i < arrLength ; i++) {   // Loop 8 times to capture High Byte
delayMicroseconds(830);                  // Sample every x Microseconds   
bitSet(data, i)= digitalRead(pin);        
Serial.print (data);                   // Print to serial as we step through the loop
}
Serial.println();                      // Print to serial
Serial.println (data);               // Print to serial
delay(50);                            // Added delay to allow settling time, eliminates 'overflow'
     
  }                                      // end 
 }                                       // end loop

@GolamMustafa

Equally as interesting thank you.

For some reason the output is reversed and looses 0's from the end.

  • Result

1111111100000110 // Actual data
110000011111111 // Serial printed data - flipped and missing MSB 0

int pinstate;
int pin = 4;                               // Input on pin 4                                
uint8_t arrLength = 16;                     // 8no samples
unsigned int data =0;


void setup(void) {
  pinMode(pin, INPUT);                   // Set pin to input
  Serial.begin(9600);
  delay(15);                             // Settle time for serial init
  Serial.println("Ready to Sample");     // Send text just to check it's alive
}

void loop(void) {
  
pinstate = digitalRead(pin);              // Read and monitor input for change. Input is normally High

if (pinstate ==LOW) {                      // If input goes low, begin capture 
  data =0;  
for (int i = 0; i < arrLength ; i++) {   // Loop 8 times to capture High Byte
delayMicroseconds(830);                  // Sample every x Microseconds   
bitWrite(data, i, digitalRead(pin)); 
}
Serial.println();                       // Print to serial
Serial.println (data, BIN);           // Print to serial
delay(80);
     
  }                                      // end 
 }                                       // end loop
bitSet(data, i)= digitalRead(pin);

Does that even compile?

You want to read the state of the pin. If it is high, you want to call bitSet(), to set the ith bit of data.

You seem to be expecting leading 0s to be printed. By default, they are not. If you want to print every bit, use bitRead() and print the returned value.

lazerjules:
@GolamMustafa

Equally as interesting thank you.

For some reason the output is reversed and looses 0's from the end.

  • Result

1111111100000110 // Actual data
110000011111111 // Serial printed data - flipped and missing MSB 0

data =0;  

for (int i = 0; i < arrLength ; i++) {

You are filling up 'bit-0 of variable data' first, and then you are printing that bit first. Change the argument of for() loop so that you fill up 'bit-15 of variable data' first. Everything will be alright.

@PaulS

Ah, ok. yes you're right I was expecting to see leading 0's.

Thinking about my longer term application i.e. what I'm going to do with this data, I could just as easily use a HEX value instead of binary.

If I use bitSet() as suggested to set the high bits, 'data' should then print as a HEX value right?

@GolamMustafa

That works, thanks for your help. Very much appreciated.

If I use bitSet() as suggested to set the high bits, 'data' should then print as a HEX value right?

Or you can print it in binary, or decimal, or base 5, or base 127. Whatever floats your boat. The data is not changed by printing it is some specific base.

Good point, yes. Silly question really.

I’ll play around with bitSet() a little more.

Thanks again for your help.
Really has pushed me on a bit.

lazerjules:
I’ll play around with bitSet() a little more.

Hints:

unsigned int data = 0;

for (int i=0; i<16; i++)
{
   bool n = digitalRead(4);
   if(n != LOW)
   {
       bitSet(//left for you//);
   }
}

Excellent thanks. I have bitWrite() working but of course want to understand the other as well.

What is the reason behind writing if(n != LOW) instead of if (n = HIGH)?

lazerjules:
Excellent thanks. I have bitWrite() working but of course want to understand the other as well.

What is the reason behind writing if(n != LOW) instead of if (n != HIGH)?

unsigned int data = 0b1111111111111111;

for (int i=0; i<16; i++)
{
   bool n = digitalRead(4);
   if(n != HIGH)
   {
       bitClear(//left for you//);
   }
}