Getting the Encoder working with Interrupts

9 Mar

IThis is working nicely now, but it was a bit tricky.

When he designed the uBITx, Farhan decided not to use the Arduino pins dedicated for devices that can externally interrupt the micro controller (D2 & D3). Instead, he used inputs A0 and A1, which are general purpose analog/digital pins and then he polled the inputs in software to determine the encoder state. This works well enough for the primitive low-resolution encoder supplied with the uBITx, but it can’t keep up with higher resolution encoders that have more than 10x as many pulses per revolution of the shaft. This is compounded by the fact that the TFT color display I’m using ‘steals’ a lot of processor throughput every time it updates, causing missed states when the encoder is turned.



Fortunately, Farhan chose to use analog-capable pins, and with a little trickery, these can generate interrupts by using the Arduino’s built-in analog comparator, which can generate interrupts to detect state changes. To accomplish this, you have to set up the comparator to generate an interrupt on a specified edge of one of the encoder inputs and then immediately poll the other encoder input to compare state combinations. This is now working pretty well with no missed states or ‘stuttering’, no matter how fast you spin the encoder shaft.

This weekend, I’ll hopefully connect the new display and encoder to the uBITx, connect an antenna, and give it a whirl.


UPDATE: I had a lot of problems with the comparator bouncing on encoder transitions because it has no hysterisis. I rewired the Raduino bard to use the D2 and D3 lines for the encoder and A0 & A1 replacing what D2 and D3 were doing. This works much better.

5 Responses to “Getting the Encoder working with Interrupts”

  1. Bob August 13, 2018 at 4:43 pm #

    Hi Joe,

    Imagine you have probably by now sorted your 400pulse optical encoder issue.

    I have used several of these encoders in various projects, most recently on the VU2SPF Mega2650 uBitx Controller and, out of interest here is how I divided the pulse count in the interrupt routine to give 50 pulses per revolution. The division ratio can easily be changed to give other pulse counts.

    static volatile int PulseCounter;
    unsigned char result = r.process();
    if (result && !txstatus) // lock freq during transmit
    if (result == DIR_CW) {PulseCounter++;}
    if (result == DIR_CCW) {PulseCounter–;}
    if (PulseCounter > 7) {vfo += radix;PulseCounter = 0; changed_f = 1;}
    if (PulseCounter < -7) {vfo -= radix; PulseCounter = 0; changed_f = 1;}

    (radix is the step size in the VU2SPF sketch)

    My original efforts were tweaked slightly following input from Jack W8TEE.

    Bob GM4CID

    • w3jdr August 13, 2018 at 5:08 pm #

      Hi Rob!

      I’m using the encoder in the 400ppr mode with either 1hz steps or 10 hz steps in an interrupt driven system. This gives a nice smooth, almost analog feel when slow tuning.. I use proportional software acceleration when the knob is turned faster to be able to get across the band faster if I want to. For me, it’s the best of all worlds and feels like my TS-450, but you need a fast processor to keep up with the rapid interrupt rate of the 400ppr encoder while simultaneously servicing a 10khz audio sampling S-meter/AGC, reloading the Si5351 and upating the display. That’s one of the reasons I’m moving to the Blue Pill.

      Thanks for commenting


      • Bob August 14, 2018 at 5:52 am #

        Hi Joe,

        From your blogs I had imagined that you had moved on. is it the STM32F103C8T6 that you are using?
        Also interested that you have working software acceleration, none of my efforts were successful.

        73 Bob

  2. w3jdr August 15, 2018 at 5:18 am #


    This is still very much on my list of active projects, but my time is limited with nice-weather activities and job responsibilities.

    Yes, I’m using the Blue Pill xxx103 board. The encoder outputs drive interrupts. In the ISR, the time since the last interrupt (based on “micros` if I recall) is measured and the result drives a lookup table (actually a SWITCH selection) to determine a multiplier for the step size. Works pretty smoothly, but the speed at which the Nano can measure, tune and update the display is the limiting factor. I had to move to a faster ILI9341 library. All this was done months ago, so my memory is a bit fuzzy.

    • Bob McClements August 16, 2018 at 8:36 am #


      Thank you, will explore this technique when time permits.

      73 Bob

Leave a Reply to Bob Cancel reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: