CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Worlds' Best Rotary Encoder Routine?

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
Sergeant82d



Joined: 01 Nov 2009
Posts: 55
Location: Central Oklahoma

View user's profile Send private message

Worlds' Best Rotary Encoder Routine?
PostPosted: Thu Dec 31, 2009 11:48 am     Reply with quote

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

View user's profile Send private message

i dont get any result
PostPosted: Tue Feb 02, 2010 9:07 am     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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