Serial Wombat
a general-purpose digital interface device for hobbyists, engineers and students

 


Home
Overview
Protocol
Documentation
Channel Modes
Direct Control
Controlled Pin
Raw A/D
A/D Averaging
A/D 1st Order Filtering
Matrix Keypad
Servo Control
Analog Direct
Analog Follow
Rotary Encoder
Debouncing
Counter
Hysteresis
Morse Code
Pulse
Unipolar Stepper
LCD Driver 1
LCD Driver 2
HW Pulse Meas.
2D Lookup
SPI Master
HD44780 Generic
Remote Control
DataLogger
Min-Max
Public Data
Timed IO
Getting Started
Connectivity
Pin Mode SDK Beta
Sample Projects
Downloads
Contact Us
Purchase
Forum

Did you know...

 

Rotary_Encoder

The rotary encoder mode is used to measure positive or negative rotation of a shaft. A rotary encoder is a special type of switch capbable of connecting either, both, or neither of two pins to a third pin. By alternating connections on the pins the encoder can show rotation speed and rotation direction of the shaft. Rotary encoders are useful for applications which require measuring a shaft's rotation, but not its absolute angular position. The most common use of rotary encoders is to add knobs to digitally controlled equipment such as car radios.


Typically, two pins are connected to a microcontroller's digital inputs, and are pulled up to Vcc using two pullup resistors:


           Vcc               _________
                            |         |
         |    |             |         |
         /    /             |    @    |
         \    \  10k        |         |
         /    /             |_________|
         \    \               |  |  |
          |   `---+-----------'  |  |
          |       |              |  |
          `-------(-------+------' GND
                  |       |
                INPUT   INPUT
                  1       2
        



When the encoder is rotated one "click" one of the two pins will toggle. By comparing the new value with the previous one it is possible to determine which direction the encoder shaft was turned.

   Clockwise Rotation:

               __________        __________       
 input 1:  ____|        |________|        |_______

                   __________        __________   
 input 2: _________|        |________|        |___

               |   |    |   |    |   |    |   |   
               C   C    C   C    C   C    C   C   
               L   L    L   L    L   L    L   L   
               I   I    I   I    I   I    I   I   
               C   C    C   C    C   C    C   C   
               K   K    K   K    K   K    K   K   

   Counterclockwise rotation:
                   __________        __________   
 input 1: _________|        |________|        |___

               __________        __________       
 input 2:  ____|        |________|        |_______


               |   |    |   |    |   |    |   |   
               C   C    C   C    C   C    C   C   
               L   L    L   L    L   L    L   L   
               I   I    I   I    I   I    I   I   
               C   C    C   C    C   C    C   C   
               K   K    K   K    K   K    K   K   
        

The Serial Wombat is an easy way to interface a rotary encoder to a PC or other RS232 based host.
The rotary encoder mode outputs the net numberof clicks which have occurred since the last initialization or query. The initialization of the rotary encoder mode requires two packets to be sent:

Data Sent to the Wombat: 200 Pin # 11 Second Pin # Min MSB Min LSB Max MSB Max LSB
Meaning: Configure Pin First message Pin Number to be set to Rotary Encoder Rotary Encoder Mode A rotary encoder requries two input pins. The minimum value the rotary encoder can provide. The maximum value the rotary encoder can provide
This message is echoed back by the Wombat.

 

Data Sent to the Wombat: 201 Pin # 11 Pin to Modify Increment MSB Increment LSB Initial Value MSB Initial Value LSB
Meaning: Configure Pin Second message Pin Number to be set to Rotary Encoder Rotary Encoder Mode The pin whose public data should be incremented or decremented The amount to increment or decrement the modified Pin's public data per click. The initial value of the Public Data Buffer for Modified Pin
 
Data Received by the Host 201 Pin # 11 Pin to Modify Increment MSB Increment LSB Previous Value MSB Previous Value LSB
Meaning: Configure Pin Second message Pin Number to be set to Rotary Encoder Rotary Encoder Mode The pin whose public data should be incremented or decremented The amount to increment or decrement the modified Pin's public data per click. The value of the Public Data Buffer for Modified pin before being changed to commanded value

 

 

Pin Mode Source Code

The following code is what creates the pin mode for this function inside of the Wombat. You don't need to know this to use the pin mode, but some people find it interesting. See the SDK for some insight into how pin modes work. Hold your mouse over various words and variables for definitions. #ifndef COMPILING_FIRMWARE
#include <stdio.h>
#endif
#include "types.h"
#include "utilities.h"
#include "global_data.h"
#pragma code APPLICATION
#pragma romdata APPLICATION_DATA



void init_rotary_enc ()
{
        if (rxbuffer[0] == CONFIGURE_CHANNEL_MODE_0)
        {
                     tp.rotary_enc.min = RXBUFFER16(4);
                     tp.rotary_enc.max = RXBUFFER16(6);
                     tp.rotary_enc.increment = 0;
                     vpin_input();
                     tp.rotary_enc.second_vpin = map_pin(rxbuffer[3]);
                     pin_input(tp.rotary_enc.second_vpin);
                     local_i = read_pin(tp.rotary_enc.second_vpin);
                     local_i <<=1;
                     local_i += vpin_read();
                     tp.rotary_enc.last_value= local_i;
                     tp2.rotary_enc.pintomodify =  255;
                     put_tp2((tp.rotary_enc.second_vpin);
        }
        else if (rxbuffer[0] == CONFIGURE_CHANNEL_MODE_1)
        {

                     get_tp2((tp.rotary_enc.second_vpin);
                     txbuffer[6] = HIGH_BYTE_16(tp.generic.buffer);
                     txbuffer[7] = LOW_BYTE_16(tp.generic.buffer);
                     tp.rotary_enc.increment = RXBUFFER16(4);
                     tp.generic.buffer = RXBUFFER16(6);
                     tp2.rotary_enc.pintomodify =  map_pin(rxbuffer[3]);
                     tp2.generic.mode = PIN_MODE_CONTROLLED;
                     put_tp2((tp.rotary_enc.second_vpin);
        }

}

void update_rotary_enc(void)
{
        // Sequence 00 02 03 01
        #define INCREMENT 0
        #define DECREMENT 0XFF
        #define NOACTION  2
        get_tp2((tp.rotary_enc.second_vpin);
        tp2.rotary_enc.action = NOACTION;
             local_i = read_pin(tp.rotary_enc.second_vpin);
             local_i <<= 1;
             local_i += vpin_read();
        if ( local_i == tp.rotary_enc.last_value)
        {
                return;
        }
        executive_settings.buffer_dirty = 1;
      switch (tp.rotary_enc.last_value)
         {
             case 0x00:
                   if (local_i == 0x01)
                   {
                           tp2.rotary_enc.action = DECREMENT;
                   }
                   else if (local_i == 0x02)
                   {
                           tp2.rotary_enc.action = INCREMENT;
                   }
             break;
              case 0x01:
                   if (local_i == 0x03)
                   {
                           tp2.rotary_enc.action = DECREMENT;
                   }
                   else if (local_i == 0x00)
                   {
                           tp2.rotary_enc.action = INCREMENT;
                   }
              break;
              case 0x02:
                   if (local_i == 0x00)
                   {
                           tp2.rotary_enc.action = DECREMENT;
                   }
                   else if (local_i == 0x03)
                   {
                           tp2.rotary_enc.action = INCREMENT;
                   }
              break;
              case 0x03:
                   if (local_i == 0x02)
                   {
                           tp2.rotary_enc.action = DECREMENT;
                   }
                   else if (local_i == 0x01)
                   {
                           tp2.rotary_enc.action = INCREMENT;
                   }
              break;
              default:
              break;
         }
         tp.rotary_enc.last_value = local_i;
         if (tp2.rotary_enc.action == NOACTION)
        {
            return;
        }
         if ( tp2.rotary_enc.pintomodify != virtual_pin)
         {
            tp2.rotary_enc.old_value = get_buffer(tp2.rotary_enc.pintomodify);
         }
         else 
         {
                 tp2.rotary_enc.old_value = tp.generic.buffer;
         }
         tp2.rotary_enc.final_value = tp2.rotary_enc.new_value = tp2.rotary_enc.old_value;
         if (tp2.rotary_enc.action == INCREMENT)
         {
                tp2.rotary_enc.new_value += tp.rotary_enc.increment;
                if (tp2.rotary_enc.new_value > tp2.rotary_enc.old_value && tp2.rotary_enc.new_value <= tp.rotary_enc.max)
                {
                        tp2.rotary_enc.final_value = tp2.rotary_enc.new_value;
                }
                else
                {
                        tp2.rotary_enc.final_value = tp.rotary_enc.max;
                }
        }
        else  // Must be DECREMENT
        {
                tp2.rotary_enc.new_value -= tp.rotary_enc.increment;
                if (tp2.rotary_enc.new_value < tp2.rotary_enc.old_value && tp2.rotary_enc.new_value >= tp.rotary_enc.min)
                {
                        tp2.rotary_enc.final_value =tp2.rotary_enc.new_value;
                }
                else
                {
                        tp2.rotary_enc.final_value =tp.rotary_enc.min;
                }
        }
        
         if (tp2.rotary_enc.pintomodify != virtual_pin)
         {
             set_buffer(tp2.rotary_enc.pintomodify, tp2.rotary_enc.final_value);
         }
         else 
         {
                 tp.generic.buffer = tp2.rotary_enc.final_value;
         }
         put_tp2((tp.rotary_enc.second_vpin);
}

#ifndef COMPILING_FIRMWARE

#ifdef TEST_ROTARY_ENC
void cw(void);
void ccw(void);
void flip(void);
int pin1 = 20;
int pin2 = 21;
int modify_pin = 20;
int expectedvalue = 0x8000;
int test = 0;
uint16 increment = 1;
int main(void)
{
        int test_result = 0;
        uint16 min = 0 ;
        uint16 max = 65535;
        int i;
     printf ("Testing rotary encoder\n");
     system_init();

     pin_low(pin1);
     pin_low(pin2);

     rxbuffer[0] = CONFIGURE_CHANNEL_MODE_0;  
     rxbuffer[1] = pin1;
     rxbuffer[2] = PIN_MODE_ROTARY_ENC;
     rxbuffer[3] = pin2;
     rxbuffer[4] = min / 256;
     rxbuffer[5] = min % 256;
     rxbuffer[6] = max / 256;
     rxbuffer[7] = max % 256;
     process_rxbuffer();

     expectedvalue = 0x8000;

     rxbuffer[0] = CONFIGURE_CHANNEL_MODE_1;  
     rxbuffer[1] = pin1;
     rxbuffer[2] = PIN_MODE_ROTARY_ENC;
     rxbuffer[3] = modify_pin;
     rxbuffer[4] = increment / 256 ;
     rxbuffer[5] = increment % 256; //  increment by 1
     rxbuffer[6] =  expectedvalue / 256;
     rxbuffer[7] =  expectedvalue % 256;
     process_rxbuffer();


     process_pins();
     for (i = 0; i < 1000; ++i)
     {
             switch (random() & 3)
             {
                 case 0:
                     cw();
                     expectedvalue += increment;
                     if (expectedvalue > max)
                     {
                             expectedvalue = max;
                     }
                     break;
                 case 1:
                     ccw();
                     expectedvalue -= increment;
                     if (expectedvalue < min)
                     {
                             expectedvalue = min;
                     }
                     break;
                 case 2:
                     flip();
                     break;
                 default:
                     break;
             }
             process_pins();
             if (get_buffer(map_pin(pin1)) != expectedvalue)
             {
                     printf ("FAILED Test %d expected result was %d, got %d\n", test,
                                     expectedvalue, get_buffer(map_pin(pin1)));
                     test_result = 1;
             }
     }


     // Next test.  Verify that counter doesn't roll over maximum or under minimum
     ++test;
     rxbuffer[0] = CONFIGURE_CHANNEL_MODE_0;  
     rxbuffer[1] = pin1;
     rxbuffer[2] = PIN_MODE_ROTARY_ENC;
     rxbuffer[3] = pin2;
     rxbuffer[4] = min / 256;
     rxbuffer[5] = min % 256;
     rxbuffer[6] = max / 256;
     rxbuffer[7] = max % 256;
     process_rxbuffer();

     expectedvalue = 0x8000;

     rxbuffer[0] = CONFIGURE_CHANNEL_MODE_1;  
     rxbuffer[1] = pin1;
     rxbuffer[2] = PIN_MODE_ROTARY_ENC;
     rxbuffer[3] = modify_pin;
     rxbuffer[4] = increment / 256 ;
     rxbuffer[5] = increment % 256; //  increment by 1
     rxbuffer[6] =  expectedvalue / 256;
     rxbuffer[7] =  expectedvalue % 256;
     process_rxbuffer();


     process_pins();
     for (i = 0; i < 70000; ++i)
     {
             cw();
             process_pins();
     }
     if (get_buffer(map_pin(modify_pin)) != max)
     {
             printf ("Failed.  Maximum was equal to %d, not %d\n", get_buffer(map_pin(modify_pin)),max);
             test_result = 1;
     }

     process_pins();
     for (i = 0; i < 70000; ++i)
     {
             ccw();
             process_pins();
     }
     if (get_buffer(map_pin(modify_pin)) != min)
     {
             printf ("Failed.  Minimum was equal to %d, not %d\n", get_buffer(map_pin(modify_pin)),min);
             test_result = 1;
     }

     if (test_result == 0)
     {
             printf ("Rotary Encoder Test passed!\n");
     }

     return(test_result);

}
void cw(void)
{
        if (read_pin(map_pin(pin2)))
        {
                if (read_pin(map_pin(pin1)))
                {   //1,1
                        pin_low(map_pin(pin2));
                }
                else
                {  // 1,0
                        pin_high(map_pin(pin1));
                }

        }
        else
        {
                if (read_pin(map_pin(pin1)))
                {   //0,1
                        pin_low(map_pin(pin1));
                }
                else
                {  // 0,0

                        pin_high(map_pin(pin2));
                }
        }
}

void ccw()
{
        cw();
        cw();
        cw();
}

void flip()
{
        cw();
        cw();
}
#endif
#endif



 

Copyright Wombat Interface Products, 2005-2008. All Rights Reserved.