This example C code can be used to implement a completely interrupt driven rotary encoder counter (incremental type) using PIC16FXXX microcontrollers built-in timers and counters. This code was written in 2005 for a simple factory automation project I did. The code is written for HI-TECH PIC16 compilers. The microcontroller used was PIC16F877A. Note: This program supports only uni-directional counting. The encoder output should is connected to TMR1 module’s input pin (PORTC1).
/* Simple 8-digit SSD counter for PIC16 microcontrollers To be compiled with HI-TECH PIC16 Compilers Freely distributable in this original form. (c) 2006 Pasan Hettiarachchi (c) Microsolutions Any questions or comments? admin@microsolutions.info */ /* counting and displaying is completely interrupt driven. Timer1 is used as the rotary encorder counter, and Timer0 is used to scan the SSD display */ #include <pic.h> __CONFIG (HS & WDTDIS & LVPDIS & PROTECT); //following four lines defines pins used for seven digit SSD dispaly. #define segments PORTB //segments pins are connected (common anode SSD) to PORTB #define segmentsDataDir TRISB //segments pins data direction (should be outputs) #define digitSelect PORTD //digit selection transistors (PNP for common anode) are connected to PORTD #define digiSelectDir TRISD //digit select pins data direction (should be outputs) unsigned long count; //variable to hold the rotary encoder count //segment data to display 0-9 unsigned char SSD[]={0xC0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90}; unsigned char digits[8]; /*Only one digit selection pin is 0 at a given time (for common anode type displays) i.e. only one digit is displayed at a given time */ unsigned char digipattern[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; void interrupt myISR(); //the variable tmr1Rest together with 16bit Timer1 module makes a 32bit count possible volatile unsigned int tmr1Rest; //Declared volatile because used in an interrupt handler void decodeDigits(); void main(){ tmr1Rest=0; //intializing counter variables count=0; //intializing counter variables while(GIE==1) GIE=0; //Turn all interrupts off TMR1ON=0; //Turn off timer1 TRISC0=1; //Rotary encoder input OPTION=0b11000100; //timer0 internal clock //prescaler assigned to timer 0 TMR1CS=1; //External input to counter(Counter mode) T1SYNC=0; //Synchronous timer T1OSCEN=0; //external Oscillator is disbled tmr1Rest=0; //Initialise Counter to 0 TMR1L=0; //Initialise Counter TMR1H=0; //Initialise Counter PEIE=1; //Peripheral interrupts are enabled TMR1IE=1; //Timer1 interrupt is enabled(will be triggered when counter overflows) T0IE=1; //Timer0 interrupt is enabled(will be triggered when counter overflows) segmentsDataDir=0x00; //making port pins connected to SSD segments as outputs digiSelectDir=0x00; //making port pins connected to digit select transistors as outputs segments=0; //segments are turned off digitSelect=0xff; //digits are turned off GIE=1; //Turn on interrupts TMR1ON=1; //Turn on Timer1 counter while(1){ //count is the 32bit long integer holding the rotary encoder count *(((unsigned char *)&count))=TMR1L; //pointer arithmatic to access Word and bytes of a long integer *(((unsigned char *)&count)+1)=TMR1H; *(((unsigned int *)&count)+1)=tmr1Rest; decodeDigits(); } } void decodeDigits(){ unsigned long temp3; unsigned int temp; unsigned char temp2; digits[7]=count/10000000; // 10 millionth digit temp3=count%10000000; digits[6]=temp3/1000000; // millionth digit temp3=temp3%1000000; digits[5]=temp3/100000; // 100 thousand's digit temp3=temp3%100000; digits[4]=temp3/10000; // ten thousand's digit temp3=temp3%10000; digits[3]=temp3/1000; // thousand's digit temp=count%1000; digits[2]=temp/100; // hundred's digit temp2=(temp%100); digits[1]=temp2/10; // 10's digit digits[0]=temp2%10; // 1's digit } void interrupt myISR(){ unsigned char digit; if (TMR1IF){ TMR1IF=0; tmr1Rest++; } if (T0IF){ T0IF=0; if (digit==8) digit=0; digitSelect=0xff; //turn off all digits to prevent ghosting segments=SSD[digits[digit]]; digitSelect=digipattern[digit]; digit++; } }
Download the source code: 8-digit counter