Trouble Capturing Un-Encoded Bit Stream

My first post, please be gentle! I would appreciate suggestions re any errors in my code or a better way to achieve the desired result.

As part of a system monitor project for my motorhome I need to capture and store 12 bytes of un-encoded data from each of three tank sensors (currently testing with just one). The data is received on digital pin 5 in response to a prompt sent out on digital pin 6. I have confirmed with an oscilliscope that the data is received at pin 5 (pinSLin) but when I print out the array values after capture, all I get with the current code version is zeros, no matter what is being received.

The attached image shows a capture of a few bits at the start of the data stream. There is a high state of around 10 ms before the 12 bytes arrive. The bit frequency is 8.65 kHz with a “1” represented by a short negative pulse (around 13 microseconds) and a “0” by a long negative pulse (around 43 microseconds). I use a mid-point of 25 microseconds as a 1/0 test.

Here is the receiver code snippet:

void loop() {
tankNum = 0; // test tank
// Get 12 bytes
for (byteLoop = 0; byteLoop < 12; byteLoop++) {
    SeeLevels[tankNum][byteLoop] = readByte();   //SeeLevels[3][12] is the storage array

int readByte() {
  result = 0;   // temporary home for each byte (int)
  for (bitLoop = 0; bitLoop < 8; bitLoop++)   // grab 8 bits
    result << 1;   //shift previous bit
    while ((digitalRead(pinSLin) == HIGH)) {}  // wait for high > low transition
    startStep = micros();
    while ((digitalRead(pinSLin) == LOW & (micros() - startStep) < 80)) {} wait for low > high 
    if ((bitTime = micros() - startStep) >= 70) {  //bad data bit?
      noData = true;
    else if (bitTime >= 25) {
      thisBit = 1;
    else {
      thisBit = 0;
    result | thisBit;

If you are getting a stream of 0s where you were expecting a stream of 0s and 1s at least you are getting somewhere.
If you are doing something time critical like reading a serial data stream, you'd probably be better off setting up a pin change interrupt and and handling the the transitions in the interrupt service routine instead of using the loop().
The other thing to consider is that digitalRead() is quite slow and you are measuring timings of around 13 microseconds. You can read a port directly instead of using digitalRead().

Thanks for the response 6v6gt. Yes, it was encouraging that I actually got something. I was mostly looking for comments on any flaws in my logic or use of code. Did you notice any issues?

I have thought about using a pin interrupt to handle this input but avoided it for two reasons:

  1. The routine I posted is only one of the 4 or 5 functions contained in the total project, which so far I have managed to hold together pretty tightly in a polling scheme. Just didn't want to go down the ISR path if I could avoid it.
  2. I am not an particularly skilled programmer (we only learned Fortran as EEs back in the 70's!) so it seemed like a learning curve I might be able to avoid.

The code here is just a stand-alone test program to see if I can capture the bit stream. I figured the data being at approx. 100 microsecond bit rate was only the equivalent of 9600 baud ASCII so assumed it would not present too big a problem for digitalRead() under my polling scheme, especially since I have control over when the data is requested. I would still like to see this version work if possible.

On the other hand, processing the 12 byte sequence will take at least 10 ms which may cause problems with a separate serial text processing routine in my project when I integrate them. I may have to go with an ISR after all.

Just in case it won't work under polling, I will start thinking about how to set up an ISR for this.

Jim G.

Fortran was pretty basic then. No if then else for example.

Without seeing all the relevant definitions, it’s a bit difficult to see all the potential problems.

The only thing that immediately struck me about your code is the construct:

result | thisBit;

I guess you meant result = result | thisBit;

And maybe the same with the left shift: result << 1 should also be made into an assignment.

result | thisBit;

...has no side-effects.

readByte has no return.

It looks like you got some strong confirmation regarding the bitwise | (or).

Found another one:

 while ((digitalRead(pinSLin) == LOW & (micros() - startStep) < 80)) {} wait for low > high

I guess you meant && (logical and).

It looks like you got some strong confirmation regarding the bitwise | (or).

The bitwise-or is irrelevant. Not doing anything with the result of the expression is the problem.

Great feedback, thanks!

I will review my code and implement necessary changes.


Nice catch on the "no return argument", Coding Badly. That would certainly be one explanation for getting all zeros!

I'll run some tests as soon as I can.