|
|
View previous topic :: View next topic |
Author |
Message |
Sergeant82d
Joined: 01 Nov 2009 Posts: 55 Location: Central Oklahoma
|
Worlds' Best Rotary Encoder Routine? |
Posted: Thu Dec 31, 2009 11:48 am |
|
|
I take no credit for this superb rotary encoder routine, that goes to Oleg at CircuitsAtHome ( http://www.circuitsathome.com/mcu/programming/reading-rotary-encoder-on-arduino ). All I did was port it to CCS C, but it should work with any C compiler now, I think.
The key to the routine is the enc_states array, which prevents the need for debouncing the encoder and only allows valid states to be read. Absolute wizardry! Then he saves the old value by shifting it up two bits, reads the new value, and finally writes the new value to memory.
Of course, you could strip this down and call it from a timer interrupt rather than an endless While loop in main, also.
Code: |
#include <18F4620.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,BROWNOUT,PUT,NOPBADEN,DEBUG
#use delay(clock=20M) //Inex NX-877 Plus II Development Board
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#include<Flex_LCD_2x20.c>
/////////////////////////////Encoder Vars//////////////////////////////////////
signed char enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
int16 enc_position = 0;
signed int16 enc_value = 0;
int16 old_enc_value = 0;
/////////////////////////////Working Vars//////////////////////////////////////
int16 my_enc_val = 0;
/////////////////////////////Encoder Function - Repeat as required/////////////
void encoder0Loop(void)
{
enc_position <<= 2; //remember previous state by // shifting the lower bits up 2
enc_position |= ( input_b() & 0x03 ); // AND the lower 2 bits of //port b, then OR them with var //old_AB to set new value
enc_value += enc_states[( enc_position & 0x0f )]; // the lower 4 bits of old_AB & 16 are then
// the index for enc_states
if ( enc_value == old_enc_value ) {
return;
}
if( enc_value <= 0 ) {
enc_value = 0;
}
if( enc_value >= 400 ) { // Arbitrary max value for testing purposes
enc_value = 400;
}
my_enc_val = enc_value/4; // This is the value you will pass to
//whatever needs the encoder data - change as required
printf("Encoder 0 = %4ld\n\rValue = %3ld%%\n\n\r",enc_value,my_enc_val);
printf(lcd_putc,"\fEncoder 0 = %ld\nValue = %3ld%%\n",enc_value,my_enc_val);
old_enc_value = enc_value;
} // End of encoder0Loop
////////////////////////////////////////////////////////////////////////////////////////////
#int_TIMER0
void timer0_isr()
{
output_toggle(PIN_A2); // let me know it's alive...
// T0_flag_1 = 1; // Set a flag
// T0_flag_2++; // Increment a counter
}
////////////////////////////////////////////////////////////////////////////////////////////
void main(void)
{
port_b_pullups(true);
setup_adc_ports(NO_ANALOGS);
ENABLE_INTERRUPTS(global);
ENABLE_INTERRUPTS(INT_TIMER0);
SETUP_TIMER_0(RTCC_INTERNAL | RTCC_DIV_32);
printf("\n\n\rRotary Encoder Test 2\n\n\r");
printf(lcd_putc,"\fRotary Encoder\nTest 2");
while (true)
{
encoder0Loop();
} // end of while loop
} // end of main
|
Brad
Last edited by Sergeant82d on Wed Aug 11, 2010 6:15 pm; edited 2 times in total |
|
|
mutthunaveen
Joined: 08 Apr 2009 Posts: 100 Location: Chennai, India
|
i dont get any result |
Posted: Tue Feb 02, 2010 9:07 am |
|
|
Hi, I modified according to my IC and my code is here but I can see nothing varying on my LCD.
Code: |
#include <16F877a.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=12000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#include <flex_lcd.c>
/////////////////////////////Encoder Vars//////////////////////////////////////
signed char enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
int16 enc_position = 0;
signed int16 enc_value = 0;
int16 old_enc_value = 0;
/////////////////////////////Working Vars//////////////////////////////////////
int16 my_enc_val = 0;
/////////////////////////////Encoder Function - Repeat as required/////////////
void encoder0Loop(void)
{
enc_position <<= 2; //remember previous state by shifting the lower bits up 2
enc_position |= ( input_b() & 0x03 ); // AND the lower 2 bits of port b, then OR them with var old_AB to set new value
enc_value += enc_states[( enc_position & 0x0f )]; // the lower 4 bits of old_AB & 16 are then the index for enc_states
if ( enc_value == old_enc_value ) {
return;
}
if( enc_value <= 0 ) {
enc_value = 0;
}
if( enc_value >= 400 ) { // Arbitrary max value for testing purposes
enc_value = 400;
}
my_enc_val = enc_value/4; // This is the value you will pass to whatever needs the encoder data - change as required
printf("Encoder 0 = %4ld\n\rValue = %3ld%%\n\n\r",enc_value,my_enc_val);
printf(lcd_putc,"\fEncoder 0 = %ld\nValue = %3ld%%\n",enc_value,my_enc_val);
old_enc_value = enc_value;
} // End of encoder0Loop
////////////////////////////////////////////////////////////////////////////////////////////
#int_TIMER0
void timer0_isr()
{
output_toggle(PIN_A2); // let me know it's alive...
// T0_flag_1 = 1; // Set a flag
// T0_flag_2++; // Increment a counter
}
////////////////////////////////////////////////////////////////////////////////////////////
void main(void)
{
lcd_init();
port_b_pullups(true);
setup_adc_ports(NO_ANALOGS);
ENABLE_INTERRUPTS(global);
ENABLE_INTERRUPTS(INT_TIMER0);
SETUP_TIMER_0(RTCC_INTERNAL | RTCC_DIV_32);
printf("\n\n\rRotary Encoder Test 2\n\n\r");
printf(lcd_putc,"\fRotary Encoder\nTest 2");
while (true)
{
encoder0Loop();
} // end of while loop
} // end of main
|
In my 16x2 LCD it is showing as timer 0 = 0.
When I make RB0 to 1 then the LCD is displaying timer 0 = 1.
When I connect an astable 555 timer, then no counting is happening. Please suggest me. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|