Skip to content

Interrupt Driven 8-Digit Rotary Encoder Counter

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

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.