4-Digit UP/Down Counter Using Rotary Encoder

Status
Not open for further replies.

Thread Starter

MCU88

Joined Mar 12, 2015
359
4-Digit UP/Down Counter Using Rotary Encoder






mikroC Source Code:
Code:
unsigned short i = 0;
unsigned short j = 0;
unsigned short scan = 0;
unsigned short rLeft = 0;
unsigned short rRight = 0;
unsigned short rotating = 0;
signed short ones = 0;
signed short tens = 0;
signed short hundreds = 0;
signed short thousands = 0;

#define dslpD PORTA.F1
#define dslpC PORTA.F0
#define dslpB PORTA.F3
#define dslpA PORTA.F2

#define segA PORTB.F7
#define segB PORTB.F5
#define segC PORTB.F3
#define segD PORTB.F2
#define segE PORTB.F1
#define segF PORTB.F6
#define segG PORTB.F4

#define rotary02 PORTB.F0
#define rotary01 PORTA.F4
#define rotary03 PORTB.F3

void num0()
{
  segA = 1;
  segB = 1;
  segC = 1;
  segD = 1;
  segE = 1;
  segF = 1;
}

void num1()
{
  segB = 1;
  segC = 1;
}

void num2()
{
  segA = 1;
  segB = 1;
  segG = 1;
  segD = 1;
  segE = 1;
}

void num3()
{
  segA = 1;
  segB = 1;
  segC = 1;
  segD = 1;
  segG = 1;
}

void num4()
{
  segF = 1;
  segG = 1;
  segB = 1;
  segC = 1;
}

void num5()
{
  segA = 1;
  segF = 1;
  segG = 1;
  segC = 1;
  segD = 1;
}

void num6()
{
  segA = 1;
  segC = 1;
  segD = 1;
  segE = 1;
  segF = 1;
  segG = 1;
}

void num7()
{
  segA = 1;
  segB = 1;
  segC = 1;
}

void num8()
{
  segA = 1;
  segB = 1;
  segC = 1;
  segD = 1;
  segE = 1;
  segF = 1;
  segG = 1;
}

void num9()
{
  segA = 1;
  segB = 1;
  segC = 1;
  segF = 1;
  segG = 1;
}

void blankDigit()
{
  segA = 0;
  segB = 0;
  segC = 0;
  segD = 0;
  segE = 0;
  segF = 0;
  segG = 0;
}

void displayOff()
{
   dslpA = 0;
   dslpB = 0;
   dslpC = 0;
   dslpD = 0;
}

void decCount()
{
   if (ones != 0 || tens != 0 || hundreds != 0 || thousands != 0)
   {
      ones--;

      if (ones < 0)
      {
         if (tens > 0)
         {
            ones = 9;
            tens --;
         }
         else if (hundreds > 0)
         {
            if (tens == 0)
            {
               tens = 9;
               ones = 9;
               hundreds --;
            }
         }
         else if (thousands > 0)
         {
            if (hundreds == 0)
            {
               if (tens == 0)
               {
                  tens = 9;
                  ones = 9;
                  hundreds = 9;
                  thousands --;
               }
            }
         }
      }
   }
}

void incCount()
{
   if (ones != 9 || tens != 9 || hundreds != 9 || thousands != 9)
   {
      ones++;

      if (ones > 9)
      {
         ones = 0;
         tens ++;
      }
      if (tens > 9)
      {
         tens = 0;
         hundreds ++;
      }
      if (hundreds > 9)
      {
         hundreds = 0;
         thousands ++;
      }
   }
}

void rstCount()
{
   ones = 0;
   tens = 0;
   hundreds = 0;
   thousands = 0;
}

void pollRotaryEncoder()
{
   TRISB = 0x09;
   
   if (rotary03 == 0)
   {
      rstCount();
   }

   TRISB = 0x01;

   if (rotary01 == 0)
   {
      if (rotary02 == 0)
      {
         rotating = 1;
      }
   }

   if (rotating == 1)
   {
      if (rotary01 == 1)
      {
         rRight = 1;
         rotating = 0;
      }
      if (rotary02 == 1)
      {
         rLeft = 1;
         rotating = 0;
      }
   }

   if (rotary01 == 1)
   {
      if (rotary02 == 1)
      {
         if (rleft == 1)
         {
            incCount();
            rLeft = 0;
         }
           
         if (rRight == 1)
         {
            decCount();
            rRight = 0;
         }
      }
   }
}

void setDigit(signed short digit)
{
   switch (digit)
   {
      case 0:
         num0();
         break;

      case 1:
         num1();
         break;

      case 2:
         num2();
         break;

      case 3:
         num3();
         break;

      case 4:
         num4();
         break;

      case 5:
         num5();
         break;

      case 6:
         num6();
         break;

      case 7:
         num7();
         break;

      case 8:
         num8();
         break;

      case 9:
         num9();
         break;
         
      case 10:
         blankDigit();
         break;

   }
}

void multiplexDisplays()
{
  displayOff();
  blankDigit();
         
   switch (scan)
   {
      case 0:
         setDigit(ones);
         dslpA = 1;
         break;

      case 1:
         setDigit(tens);
         dslpB = 1;
         break;

      case 2:
         setDigit(hundreds);
         dslpC = 1;
         break;

      case 3:
         setDigit(thousands);
         dslpD = 1;
         break;
   }

   scan++;

   if (scan == 4)
   {
      scan = 0;
   }
}

void main()
{
  CMCON = 7;            
  TRISA = 0x10;        
  TRISB = 0x01;         
  PORTA = 0x00;        
  PORTB = 0x00;        

  while(1)
  {
     multiplexDisplays();
     Delay_us(100);
     pollRotaryEncoder();
  }
}[/SIZE]

N.B: See attached for PCB artwork in Adobe Acrobat and hex file for PIC.

 

Attachments

Last edited by a moderator:

Thread Starter

MCU88

Joined Mar 12, 2015
359
Resistors

  • 11 x 470R
  • 4 x 100K
  • 1 x 1K

Capacitors

  • 2 x 22pF Ceramic
  • 1 x 100nF Polyester
  • 1 x 10uF Electrolytic

Semiconductors

  • IC1 Pre-Programmed 16F628a
  • IC2 LM78L05 Voltage Regulator
  • 4-Digit Common Cathode Red LED Display
  • Q1 – Q4 BC547 NPN Transistors
  • D1 SSR 1N4007

Miscellaneous

  • IC1 Socket 18-Pin
  • Battery Connector
  • Wire Links
  • Rotary Encoder with Knob
  • XTAL 4MHz Crystal
 

Wendy

Joined Mar 24, 2008
22,239
There are times a simple counter is handy. Fast is good, then it could be the heart of a freq counter, for example. Or just count turns of a shaft, or whatever is needed.

I have never programmed a pic, though I would like to learn how.
 

WBahn

Joined Mar 31, 2012
26,398
I engineered it to understand and implement rotary encoders. What would you like it to do?
As a cute little project to get introduced to rotary encoders, it is just fine.

Notice that your picture has a huge splash that proclaims "No Buttons". I hate to be the bearer of bad news, but when you press the knob to reset it, guess what? That's a button! Minor point.

The bigger problem is that you don't document your code, which makes in almost impossible to read without a lot of reverse-engineering effort. This is particularly the case for the section where you are polling the rotary encoder. Just a handful of comments indicating what the signals mean and what task each subsection of the code accomplishes would make it very readable. Just put yourself in the place of someone that has never seen the schematic or the PCB and that can't see anything in the code beyond that section of it and then write the comments that you would need in order to understand what is happening.
 

Thread Starter

MCU88

Joined Mar 12, 2015
359
Notice that your picture has a huge splash that proclaims "No Buttons". I hate to be the bearer of bad news, but when you press the knob to reset it, guess what? That's a button! Minor point.
No buttons of the traditional fashion for such an counter. One button to increment the count UP and one button to decrement the count DOWN. I see where you are coming from though. I did sell a few kits on eBay. Satisfied customers in the end. One guy had BIG trouble with soldering the board though. All I could do was to offer to sell him an pre-build one. He bought it and quickly saw the error of his way.

The bigger problem is that you don't document your code, which makes in almost impossible to read without a lot of reverse-engineering effort. This is particularly the case for the section where you are polling the rotary encoder. Just a handful of comments indicating what the signals mean and what task each subsection of the code accomplishes would make it very readable. Just put yourself in the place of someone that has never seen the schematic or the PCB and that can't see anything in the code beyond that section of it and then write the comments that you would need in order to understand what is happening.
Yes I am getting old and lazy. I used to comment code years back. I'll fix it.
 

Thread Starter

MCU88

Joined Mar 12, 2015
359
There are times a simple counter is handy. Fast is good, then it could be the heart of a freq counter, for example. Or just count turns of a shaft, or whatever is needed.

I have never programmed a pic, though I would like to learn how.
Very true Bill. There are spin-offs to this project and the code. I could quickly adapt and make the following:
  • Capacitance Meter
  • Frequency Meter
  • Door Opening Counter
  • Tachometer
  • Digital (n) Readout Display
  • 4-Digit Clock
  • Count Down Timer
The code runs at a good clip. Could get away with it doing many of the aforementioned projects.

Keen to learn C for programming PICs? Then I recommend doing an online Java course at RMIT University in Melbourne Australia. Cost you AUD 600 per unit. I did 3 units of Java. Worth the money!
 

Thread Starter

MCU88

Joined Mar 12, 2015
359
It's really convenience and anyone no need to write any program or install the compiler.
I agree. You just program the hex file to the chip. I have many PIC projects ...

Perhaps someone can start and sell the pre-programmed chips here? $5 plus postage worldwide?
 

Thread Starter

MCU88

Joined Mar 12, 2015
359
I hope all those pin numbers are correct. I designed the PCB on the Monday before drawing the schematic on the Tuesday. Well actually I drew the schematic last night and did the PCB about a year ago. I did an 245 LED moving message display for an forum back in 2007, the circuit was BIG and I got a couple of pin numbers wrong. The thread was an train-wreck with people accusing me of deliberately putting in mistakes. That's insane and makes me look like an idiot...
 

Thread Starter

MCU88

Joined Mar 12, 2015
359
Everybody makes mistakes.
Some times I get it right the first time. But usually... 50 compiles for the C code... 3 goes at the PCB. I did this project presented here in about a day. So say 8-hours labor. 8 x $30 p/hr so... it owes me $240 + parts.
 

MrChips

Joined Oct 2, 2009
22,886
Yes, you made a mistake with the pin numbers in the drawing.
The RESET switch should be connected to RB3 at pin-9, not pin-10.

On the PCB layout, the 100nF capacitor should be placed as close as possible across pins 5 and 14 for it to be any use.
 

Thread Starter

MCU88

Joined Mar 12, 2015
359
Yes, you made a mistake with the pin numbers in the drawing.
The RESET switch should be connected to RB3 at pin-9, not pin-10.

On the PCB layout, the 100nF capacitor should be placed as close as possible across pins 5 and 14 for it to be any use.
Arh yes I see it. Will make amendments and upload schematic to post #1. I agree that the closer the better for the 100nF decoupling cap. The board was manually routed. I could move things around a bit...
 
Status
Not open for further replies.
Top