[TriEmbed] C Code Question Ralated to Rotary Encoder

Jon Wolfe jonjwolfe at anibit.com
Tue Feb 23 18:51:30 CST 2016


I'm very glad it helped Fyi, I misswrote, it is shifting to the left. My entire life, I have lacked whatever neural pathway it is that lets people tell left from right without having to think about it. I mix them up all the time!


-------- Original message --------
From: Dwight Morgan <dwight.w.morgan at gmail.com> 
Date: 2/23/2016  6:46 PM  (GMT-05:00) 
To: 'Rodney Radford' <ncgadgetry at gmail.com>, 'Jon Wolfe' <jonjwolfe at anibit.com> 
Cc: 'Triangle Embedded Computing Discussion' <triembed at triembed.org> 
Subject: RE: [TriEmbed] C Code Question Ralated to Rotary Encoder 

Thanks everyone! I think one thing that was confusing me, among several, was the bit shift in the function. I thought it was shifting it left.  Jon cleared that up – it is shifting right. I have a short tutorial now on bit shifting and hopefully that will help too. I’m putting all these notes in my project file related to the rotary encoder. It is surely helpful and I can’t thank you enough! I would like to hear it if we have a discussion sometime about this. I do think it is important, not just for encoders, but in general with all the applications possible with Arduino.  Dwight From: Rodney Radford [mailto:ncgadgetry at gmail.com] 
Sent: Tuesday, February 23, 2016 4:46 PM
To: Jon Wolfe
Cc: Dwight Morgan; Triangle Embedded Computing Discussion
Subject: Re: [TriEmbed] C Code Question Ralated to Rotary Encoder I think Jon and Pete's descriptions were very helpful - the youtube video was very informative, but his constant use of 10 (to mean 2) and 11 (to mean 3), were confusing.  I thought the issue that was throwing you off was that in addition to using 10 and 11 (without stating they are binary or adding the 0b prefix to them) was the debug statements also showed only the numbers in binary as 10 or 11 (instead of in decimal as 2 or 3). Hopefully this will help, but computers work in binary as every signal is either an on (1) or off (0), and it is this combination of 1s and 0s that are used to represent everything - all numbers (whether integer or floating point), characters, strings, and even instructions. When he was saying 10, he was using the binary representation where 10 really means 1x2 + 0x1, as opposed to decimal where 10 means 1x10 + 0x1. It is a good video, but unfortunately not the best implementation of a quadrature decoder.  For what he is using it for, a hand controlled encoder, it works great - but if that was tied to a motor with high precision encoders, there is a chance of error.  It is hard to explain in an email, but quadrature encoders is something that would make a great discussion at a future TriEmbed meeting (and is already on the plan for a robotics meeting), so perhaps we can discuss it there.  For those curious, imagine what happens if the encoder stops directly at the edge of the two signals and rocks back and forth - it will cause the count to keep increasing (or decreasing depending on which edge).  The solution to this is to use a 4-bit state variable instead of just 2 - 2 to indicate the current state and 2 to indicate the previous state.  He also has another error where a race condition can occur between reading the first and second signal from the quadrature, yielding bizarre results.  Sorry if this is confusing, but hopefully useful to others who may see this.   On Tue, Feb 23, 2016 at 3:53 PM, <jonjwolfe at anibit.com> wrote:I think you're overthinking it a bit. There is (almost) no such thing as a "decimal" value at runtime. The integer variables in C++ are *always* in binary, especially on Arduino.

a "byte" in C++ is nothing more than an integer type that is unsigned, and semantically constrained to be 8 bits. That is it, period, there's nothing else that distinguishes a "byte" type from a regular "int" type.

The "byte" moniker on that type is nothing more than a convenience, and as a mnemonic indicator that the variable logically represents some byte, (as opposed to say, a loop index) There is a standard C++ type "uint8_t" that is identical in every way to a byte type, you could use that type everywhere and your program would behave identically.

In that context, the state variable is manipulated bit-wise, so that it's value ranges between 0-3. Any integer can be manipulated bitwise in C/C++. You can even manipulate floating point bit-wise, but the representation is such that there is seldom reason to do so.

the statement:

state <<= 1;

is moving all the bits of that variable to the right, so if the variable had a value of 1 before the statement, it would then have a value of 2.

The "byte" type used in Arduino is not a standard C++ type, it is defined in terms of one of two standard C++ types: "uint8_t", so they are, in-fact, equivalent.

On desktops, on 32 or 64 bit cpus, it is impossible to have only a 8 bit value, so the compiler actually has to do extra work to ensure that the code behaves identically to if it were only 8 bits. For example, adding 1 to a uint8_t variable would yield 256, but the compiler adds instructions to mask out the high bits to make sure the answer you get is 0. That's not needed on Arduino, because the "native" data size is already 8 bits.






On 2016-02-23 13:15, Dwight Morgan via TriEmbed wrote:Thanks Rodney and Mike for the responses. In Mr. Churchward’s code
he declares the byte variable “state” and uses the function
“knobTurned()” as follows – code snippets:

byte state = 0;           // will store TWO BITS for pins A & B on the
encoder which we will get from the pins above

void knobTurned(){

  /* AH HA! the knob was turned */

  state = 0;    // reset this value each time

  state = state + digitalRead(pinA);   // add the state of Pin A

  state <<= 1;  // shift the bit over one spot

  state = state + digitalRead(pinB);   // add the state of Pin B

  /* now we have a two bit binary number that holds the state of both
pins

     00 - something is wrong we must have got here with a key bounce

     01 - sames as above - first bit should never be 0

     10 - knob was turned backwards

     11 - knob was turned forwards

     */

  /* We can pull a value out of our truth table and add it to the
current level */

  level = level + bump[state];

  /* Let's see what happened */

  Serial.print(bits[state] + "    ");  // show us the two bits

  Serial.print(bump[state],DEC);       // show us the direction of the
turn

  Serial.print("    ");

  Serial.println(level);               // show us the new value

}

I’ve never used bytes much in code and never really  thought about
it much and I always saw calls to specific array elements with a
decimal value in the square brackets like this: X = myarray[2]; for
instance to get the 3rd element value.

It looks like when a byte is used as the index the value is a binary
number – using ones and zeros – and it can simply because it is a
byte!

If you look at the knobTurned() function it is building a two place
binary index stored in the byte variable named “state”. When the
code sees the binary index as a byte it knows that 10 means read the
third element value and when it sees 11 it knows to read the fourth
element value.

This seems like a very handy thing to know for new learners like me
with Arduino and RPi.

That’s my now understanding of it. Please shim up any parts as
needed!

Thanks again!

DwightFROM: Rodney Radford [mailto:ncgadgetry at gmail.com]
SENT: Monday, February 22, 2016 11:22 PM
TO: Dwight Morgan
CC: Triangle Embedded Computing Discussion
SUBJECT: Re: [TriEmbed] C Code Question Ralated to Rotary Encoder

I had to search for the video you watched to see what was being done
and then find the code. For those following along, the video is part
of a 3 part video of using a quadrature rotary encoder as an input for
a morse code sending device. The one necessary for this discussion is
the part 2 which can be found at
https://www.youtube.com/watch?v=FGxLXqzPe3Q [1]

In the video, as the knob is turned to the left or right, a line is
printed with three values on it, like this:

11 1 70
11 1 71
10 -1 70
10 -1 69

The first column represents the two bits of the quadrature, the second
column indicates whether we are counting up (+1) or down (-1) and the
third column represents the current value.

The question is how can the compiler know that the 11 represents a
binary number whose value is 3, and how does it know that 10
represents a binary number whose value is 2.

The answer is that it doesn't have to... the internal variable is
called state and it either has a 0, 1, 2, or 3.

When printing, the author decided to show the value of the number in
binary, instead of decimal, so he printed the first value like this:

 /* For demo purposes we will create an array of these binary digits
*/
 String bits[] = {"00","01","10","11"};

 /* Let's see what happened */
 Serial.print(bits[state] + " "); // show us the two bits

So as you see, the number is the index into a character string array
and it prints out either the string "00", "01", "10", or "11". This is
just to make it easier for you to visualize that the number is really
a two bit number representing the two outputs of the quadrature knob.

The second value in the line is printed with this line (this is the
one you showed). This prints out only the

 int bump[] = {0,0,-1,1};
 Serial.print(bump[state],DEC); // show us the direction of the turn

Here we see the same 0..3 state variable indexing into a numerical
array and printing out either 0, 0, -1 or +1 as a DECimal number.

And then the third value is printed with these lines:

 Serial.print(" ");
 Serial.println(level); // show us the new value

Here we just print out the integer level variable that has already
been incremented or decremented.

On Mon, Feb 22, 2016 at 10:10 PM, Dwight Morgan via TriEmbed
<triembed at triembed.org> wrote:

I’m trying to understand and use a rotary encoder on an Arduino
project and I have a simple demo circuit working with the encoder and
output to the serial monitor. I see how the code is working but I
can’t find documentation that confirms what I’m seeing.

The C code builds a two digit binary number that is used as a pointer
to values in an array that is used to output either a 1 or -1 to
indicate if the encoder is rotating clockwise or counterclockwise –
all well and fine.

The variable used as a pointer is a type byte initially set to zero
(byte state = 0) with a function called by an interrupt to build the
two digit pointer. I looked it up and a byte can either hold 8 bits or
a decimal value from 0 to 255.

The pointer works fine and prints out either a 1 or -1 on the serial
monitor.

My question is, how does the code know that a binary 10 is not the
number ten as the pointer or binary 11 is not the number eleven as the
pointer instead of knowing it is the number 2 or 3 to be used as the
pointer to pick out values in the following array?

int bump[] = {0,0,-1,1};

The output is like this: Serial.print(bump[state]),DEC); //state being
the built pointer of either binary 10 or 11 for a value of either
decimal 2 or 3, respectively.

Thanks to C code by Budd Churchward on YouTube.

Input appreciated. Thanks!

Dwight

_______________________________________________
Triangle, NC Embedded Computing mailing list
TriEmbed at triembed.orghttp://mail.triembed.org/mailman/listinfo/triembed_triembed.org [2]
TriEmbed web site: http://TriEmbed.org [3]



Links:
------
[1] https://www.youtube.com/watch?v=FGxLXqzPe3Q
[2] http://mail.triembed.org/mailman/listinfo/triembed_triembed.org
[3] http://TriEmbed.org

_______________________________________________
Triangle, NC Embedded Computing mailing list
TriEmbed at triembed.org
http://mail.triembed.org/mailman/listinfo/triembed_triembed.org
TriEmbed web site: http://TriEmbed.org  
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.triembed.org/pipermail/triembed_triembed.org/attachments/20160223/885bac18/attachment.htm>


More information about the TriEmbed mailing list