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@micro.wellassa.org
*/
/*
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