Did you know...
|
|
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
|
|