Show Posts
Pages: [1] 2 3 ... 6
1  Community / Exhibition / Gallery / Re: AdaEncoder: a library for use with simple quadrature encoders on: November 30, 2013, 12:00:53 am
This is actually a feature, not a bug.  smiley-cool  Perhaps it should only have returned a positive or a negative, to indicate any movement since the last query(). But the idea is this:

You have a main routine loop() which takes an arbitrary amount of time to run. Asynchronously, it is interrupted by a rotary encoder going up and down. My thinking is that because of this disconnect, you can't perfectly track the turns of the encoder.

Say I've gone 3 clicks CW and 1 click CCW. Net is 2 clicks CW. Now the main routine does a query(); we discover that we have clicked net CW so we should act on that. Do you want to act on the fact that you've gone 2 clicks CW? Maybe- maybe not. Yes, you have gone CW, so the query() decrements the counter and now indicates 1 click CW. Maybe, while you're processing the first of the two CW clicks, the user actually turns the encoder CCW. Now you are at 0. Do you still want to register the second previous click? I don't know.

If your routine is fast enough, you can query() repeatedly, count the number of query()'s that get you to 0, and move on. But again, based on the disconnected nature of the interrupt and the main loop, I don't want to make any assumptions... that you can act on the current counters fast enough to catch any intermediate moves. If your main routine is slow enough to allow the internal adaencoder counter to accumulate to 3 or 4 clicks, I'm uncomfortable in assuming that it would be able to take the counter and perform 3 or 4 actions. I leave it up to you; drain the counter using repeated query()'s until you get to 0 (should be pretty fast) and then act on that information.
2  Topics / Robotics / Re: Problem: PID speed with wheel encoders and PinChangeInt on: July 07, 2013, 11:02:33 pm
Besides what Aaron wrote, it appears you are using an old version of PinChangeInt. Try upgrading to the latest, which is 2.21beta.
3  Using Arduino / Programming Questions / Re: Errors with AdaEncoder on: July 02, 2013, 08:54:54 pm
Sounds like you got it figured out.

You don't need ByteBuffer to work with AdaEncoder. That's just for me to work with my test code and such. Using it is really an exercise for the programmer; I just include it to be complete. Plus, it's kind of interesting.

You should probably remove the #include from your code, as it's not necessary. (unless you need a ByteBuffer).
4  Community / Exhibition / Gallery / Re: AdaEncoder: a library for use with simple quadrature encoders on: December 22, 2012, 12:35:57 am
Thanks, vasquo. Anyway, your post prompted me to create some test code, and I hope to use this to ensure the integrity of the library in the future... (this works for v. 0.7beta and above only, but the basic algorithm applies to 0.5 as well)

// Version 1.0: OO version

#include <ByteBuffer.h>
#include <digitalWriteFast.h>
#include <ooPinChangeInt.h> // necessary otherwise we get undefined reference errors.
#define DEBUG
#ifdef DEBUG
ByteBuffer printBuffer(200);
#define SWINTR_DEBUG // To debug using software interrupts on your two pins, define this.
                    // Then in your sketch, set your pins as outputs.  Initialize them as you
                    // desire, attach an interrupt, then the interrupt code will be called.
                    // CAUTION: Make sure you do NOT have any switches connected to those outputs,
                    // or you may end up frying your ATmega328!
#include <AdaEncoder.h>

I like to keep this diagram around so I know which Arduino pin
is part of which port.
            PC6  1|    |28  PC5 (AI 5)
      (D 0) PD0  2|    |27  PC4 (AI 4)
      (D 1) PD1  3|    |26  PC3 (AI 3)
      (D 2) PD2  4|    |25  PC2 (AI 2)
 PWM+ (D 3) PD3  5|    |24  PC1 (AI 1)
      (D 4) PD4  6|    |23  PC0 (AI 0)
            VCC  7|    |22  GND
            GND  8|    |21  AREF
            PB6  9|    |20  AVCC
            PB7 10|    |19  PB5 (D 13)
 PWM+ (D 5) PD5 11|    |18  PB4 (D 12)
 PWM+ (D 6) PD6 12|    |17  PB3 (D 11) PWM
      (D 7) PD7 13|    |16  PB2 (D 10) PWM
      (D 8) PB0 14|    |15  PB1 (D 9) PWM
// An encoder for every port
#define ENCD_a 2
#define ENCD_b 3
#define ENCC_a A3
#define ENCC_b A4
#define ENCB_a 9
#define ENCB_b 10

AdaEncoder encoderD = AdaEncoder('d', ENCD_a, ENCD_b);
AdaEncoder encoderC = AdaEncoder('c', ENCC_a, ENCC_b);
AdaEncoder encoderB = AdaEncoder('b', ENCB_a, ENCB_b);

int8_t clicks=0;
char id=0;

void setup()
  Serial.begin(115200); Serial.println("---------------------------------------");
  Serial.println("AdaEncoder test. Assumes detent position is 1,1 (pin a, pin b).");
  Serial.println("Encoder states: 11->01->00->10->11 (== CCW 1 click)");
  volatile uint8_t portmask0=PCMSK0;
  volatile uint8_t portmask1=PCMSK1;
  volatile uint8_t portmask2=PCMSK2;
  PCMSK0=0; PCMSK1=0; PCMSK2=0; // turn off PinChange interrupts for a minnit
  pinMode(ENCB_a, OUTPUT); pinMode(ENCB_b, OUTPUT);
  digitalWriteFast2(ENCB_a, HIGH); digitalWriteFast2(ENCB_b, HIGH);
  pinMode(ENCC_a, OUTPUT); pinMode(ENCC_b, OUTPUT);
  digitalWriteFast2(ENCC_a, HIGH); digitalWriteFast2(ENCC_b, HIGH);
  pinMode(ENCD_a, OUTPUT); pinMode(ENCD_b, OUTPUT);
  digitalWriteFast2(ENCD_a, HIGH); digitalWriteFast2(ENCD_b, HIGH);
  PCMSK0=portmask0; // interrupts back on.

void changeEncoder(uint8_t pin) {
  if (digitalReadFast2(pin)) { digitalWriteFast2(pin, LOW); }
  else digitalWriteFast2(pin, HIGH);

void printEncoderState(uint8_t pina, uint8_t pinb) {
  Serial.print(digitalReadFast2(pina), DEC);
  Serial.println(digitalReadFast2(pinb), DEC);

void loop()
  char inChar, outChar;
  // 00 -> 10 -> 11 -> 01 -> 00
  if(Serial.available()) {
    inChar=(; // get command from serial input
    switch (inChar) {
    case '1':
        Serial.print("B-a "); changeEncoder(ENCB_a); printEncoderState(ENCB_a, ENCB_b);
    case '2':
        Serial.print("B-b "); changeEncoder(ENCB_b); printEncoderState(ENCB_a, ENCB_b);
    case '5':
        Serial.print("C-a "); changeEncoder(ENCC_a); printEncoderState(ENCC_a, ENCC_b);
    case '6':
        Serial.print("C-b "); changeEncoder(ENCC_b); printEncoderState(ENCC_a, ENCC_b);
      case '9':
        Serial.print("D-a "); changeEncoder(ENCD_a); printEncoderState(ENCD_a, ENCD_b);
      case '0':
        Serial.print("D-b "); changeEncoder(ENCD_b); printEncoderState(ENCD_a, ENCD_b);
  while ((outChar=(char)printBuffer.get()) != 0) Serial.print(outChar);
  AdaEncoder *thisEncoder=NULL;
  if (thisEncoder != NULL) {
    Serial.print(thisEncoder->getID()); Serial.print(':');
    if (clicks != 0) { Serial.print("Clicks: "); Serial.print(clicks, DEC); }
    if (clicks > 0) {
      Serial.println(" CW");
    if (clicks < 0) {
       Serial.println(" CCW");

...If I then hit a sequence of numbers in the Monitor screen, I can then demonstrate that the library behaves as expected.

For example, if I hit the following sequence, I simulate switch bounce on the two pins and it registers "CCW" exactly when I expect it:
Number Output
1 B-a 01
1 B-a 11
1 B-a 01
1 B-a 11
1 B-a 01
2 B-b 00
2 B-b 01
2 B-b 00
2 B-b 01
2 B-b 00
1 B-a 10
1 B-a 00
1 B-a 10
1 B-a 00
1 B-a 10
2 B-b 11
  b:Clicks: -1 CCW
5  Community / Exhibition / Gallery / Re: AdaEncoder: a library for use with simple quadrature encoders on: December 22, 2012, 12:08:30 am
Well, I tried using the 0.7beta.  ... But I can't get it to work properly. ... I'm going back to 0.5.

I do have a few questions on the sample MyEncoder in 0.7beta

On Line# 15, we have this code
AdaEncoder encoderA = AdaEncoder('a', ENCA_a, ENCA_b);

but nowhere else in the program is "encoderA" used. What's the purpose of line#15?

Then on line#30, I see this
AdaEncoder *thisEncoder=NULL;

*thisEncoder is used in the loop() program.  But how does Arduino know how *thisEncoder is setup?  We defined encoder pins 2 and 3 for "encoderA", not "thisEncoder".

I'm sorry it didn't work out for you. It is a little more Object-Oriented like, so it's not everyone's cup of tea.

Also I'm sorry I am late in replying. This thread is not intended for support; there is a support link on the page for that. Anyway, I will answer your questions for posterity:

The code is an example that shows you how to set up 2 encoders, A and B. encoderA and encoderB are designed to encapsulate all the important data within, so you can think about "encoders" rather than the pins of your Arduino. It's a conceptual change over version 0.5 of the library, really.

In the old days, then, of version 0.5, the genie() method would fill in the values for "clicks" and "id" for you, so you could then query the variables and ask, "Who turned?  How far?".

Now in version 0.7, the genie() method returns a pointer to an AdaEncoder object. The "thisEncoder" variable is set to NULL on every iteration of loop. Then, if genie() finds a changed encoder, it will send back the pointer to the AdaEncoder object, and now you can do whatever you want with this encoder that you've found. It sends back either encoderA or encoderB- whichever one was turned. "thisEncoder", then, changes its identity to that of either A or B. I have done the simplest thing, which is to have it query itself and return the number of times it was clicked.

By using Object Oriented techniques, you are not bound to if/then statements based on values (like id numbers) of the encoders. Each encoder object intrinsically knows who it is; you can even subclass the encoder and have your subclass do special things simply based on its identity.

On this small of a scale it may be difficult to see any kind of win at all, that I'll grant. But I think it's interesting, and I like the way Object Oriented programming makes me adjust my way of thinking, so I have decided to go that route. Thankfully the AdaEncoder library is simple enough that, in the last year, I haven't moved from the functionality I created in version 0.5. The old one should continue to be useful to people.  Although I do recommend an upgrade of the underlying PinChangeInt library.

6  Community / Exhibition / Gallery / Re: AdaEncoder: a library for use with simple quadrature encoders on: December 21, 2012, 11:46:06 pm
I've encountered a bug with the AdaEncoder (old version).

So you power up, turn the encoder CCW... the counter decrement. All is good.

You stop turning, and then turn one click CW... the counter instead of incrementing as expected, instead decrements! 
Turn it again by another click CW, then the counter increments correctly.
Does this update fix this bug? 

I don't think the update fixes that bug- not directly anyways. The bug actually came from the PinChangeInt library, which was not properly testing the state of the pins when interrupts came in quickly. If you have bouncing switches (yes- if you have a mechanical encoder, then you do have bouncing switches), then quite likely you had some issues.  I recommend you continue to use AdaEncoder 0.5 but update PinChangeInt to 2.19beta or greater.
7  Community / Exhibition / Gallery / Re: AdaEncoder: a library for use with simple quadrature encoders on: December 04, 2012, 10:29:04 pm
Announcing version 0.7beta of the AdaEncoder library. This release incorporates some bugfixes in the ooPinChangeInt library (which it uses).

I have moved the library to using the ooPinChangeInt library because, well, I like OO programming. So using the AdaEncoder library is now a bit different. Check the included "MyEncoder" sketch for an example. Most significantly, instead of calling genie() with reference arguments whose values are filled in, you now call genie() and an AdaEncoder object is returned. Then you query the object for details.

The older AdaEncoder 0.5 will continue to work with the latest PinChangeInt library, which repaired some bugs in the PinChangeInt library itself and makes AdaEncoder more reliable. If you don't like the OO-ness of this release, continue to use 0.5 but make sure to upgrade your PinChangeInt library to 2.19beta or above!
From the Release Notes:
Now works with the latest ooPinChangeInt. Should be much more reliable.

Bugfixes: the clicks variable was supposed to be int8_t, but I had query() and getClicks() returning uint8_t types.

Updated to utilize the ByteBuffer to fill a buffer of text for debug purposes.

turnOffPWM has been moved into its own file, as that code is distributed under the LPGL license. I use the GPL.
8  Community / Exhibition / Gallery / Re: ooPinChangeInt library released: Pin Change Interrupts, object style on: November 30, 2012, 06:07:34 pm
Yeahhh... next version, I guess. We'll see how complicated it gets to do.
9  Community / Exhibition / Gallery / Re: PinChangeInt library- To attach interrupts to multiple Arduino (Uno/Due) pins on: November 29, 2012, 07:14:07 pm
Version 2.19beta has been released. The library now includes Sanguino support. There have been a number of recent bugfixes, so be sure to look at the Release Notes. If you have any library prior to version 2.17beta, it is highly recommended that you upgrade to 2.17beta or later.
10  Community / Exhibition / Gallery / Version 1.03beta is now out. Adds MEGA support; includes significant bug fixes. on: November 29, 2012, 01:05:24 am
Announcing the release of version 1.03 of the ooPinChangeInt library. From the release notes:

Added MEGA support, as per PinChangeInt. This support has not been tested in this library; if you do use it with the MEGA please let me know. See the Google Code site for more information. Thanks.

Modified to not delete() pins that get detachInterrupt()'ed. Now when you detachInterrupt(), the PORT just disables interrupts for that pin; the PCintPin object remains in memory and in the linked list of pins (possibly slowing down your interrupts a couple of micros).  You can reenable a detached interrupt- but you must do it within the PinChangeInt library (would anyone ever enable an interrupt on a pin, then disable it, then have need to reenable it but not using the library?).

Optimized the interrupt handler with code from robtillaart to take out the checks for changed pins from the while() loop that steps through the pins.

Other bugfixes that follow the PinChangeInt-2.17beta release:

1. PCintPort::curr bug. In the interrupt handler PCint(), we loop as long as PCIFR indicates a new interrupt wants to be triggered, provided DISABLE_PCINT_MULTI_SERVICE is not defined (it is not by default).  Fixed so that if a pin causes the PCIFR to change, we reread the port and look at how it is now.
2. attachInterrupt() now returns an int8_t value:  1 on successful attach, 0 on successful attach but using an already-enabled pin, and -1 if the new() operator failed to create a PCintPin object.
3. Created the enable() method.
11  Community / Exhibition / Gallery / Re: PinChangeInt library- To attach interrupts to multiple Arduino (Uno/Due) pins on: November 20, 2012, 12:30:52 pm
                } while (tmp != NULL);
This won't work because tmp will become null, which will exit us from the loop.

I need tmp->next later in the code, therefore I need the last non-null value of tmp.
12  Community / Exhibition / Gallery / Re: PinChangeInt library- To attach interrupts to multiple Arduino (Uno/Due) pins on: November 20, 2012, 08:59:27 am
Thanks for the input. This saved 12 bytes; I haven't measured the speed:
    if (firstPin != NULL) {
        do {
            if (tmp->arduinoPin == arduinoPin) { enable(tmp, userFunc, mode); return(0); }
            if (tmp->next == NULL) break;
        } while (true);

I have also converted the goto to a do/while/break situation. No change to interrupt speed, but I guess it looks better :-).
13  Community / Exhibition / Gallery / Re: PinChangeInt library- To attach interrupts to multiple Arduino (Uno/Due) pins on: November 17, 2012, 02:26:31 am
Version 2.15beta is out now, and I allow for attaching a new user function. I don't know if anyone would really do that, but there should be no nasty surprises in the code, and attachInterrupt() will thus do exactly what you tell it to do in the argument list.

14  Community / Exhibition / Gallery / Re: PinChangeInt library- To attach interrupts to multiple Arduino (Uno/Due) pins on: November 16, 2012, 10:46:09 pm
I already thought of a bug in v. 2.13beta.  If you detach an interrupt and attach it again, and give it a new user function, it will not attach the new user function- it will use the first user function that you attached.

However you are able to change the mode at this point (RISING, FALLING, or CHANGE).
15  Community / Exhibition / Gallery / Re: PinChangeInt library- To attach interrupts to multiple Arduino (Uno/Due) pins on: November 16, 2012, 10:36:14 pm
BTW, I am still testing this release but I wanted it to get out there because I uncovered some nasty bugs. They made my interrupts unreliable! So it's important if you use this code, to realize that the new version should work better.

I realized that about 5-10% of my interrupts were missed due to my switch bounce; some of the bounces happen only 50 microseconds apart or so. And my code was not processing them properly. With this code, I notice that my switches are more reliable.

I also notice that I am not getting the speed bump that I hoped to get, and some of my bugfixes actually introduce a few extra microseconds of processing. This is disappointing and I hope to find them if I can.
Pages: [1] 2 3 ... 6