4 digit up counter for seven segment

jpanhalt

Joined Jan 18, 2008
11,087
Every second????? Do you realize that 9999 seconds is 6 days 56 mins and 37 seconds. ;) That's a long time to wait to see if it is working. How about every 10 to 20 ms? Even 1000 seconds to see whether each digit rolls over to the next is almost 17 hours. 100 ms would be more practical for that purpose.
 

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
Suppose that you have a 4-digit number 1234.
Can you display "1" on the first 7-segment LED display (the one on the left)?
Here is my program that display 1234

C:
#define _XTAL_FREQ 8000000
#include <xc.h>
// PIC18F45K80 Configuration Bit Settings
// 'C' source line config statements
// CONFIG1L
#pragma config RETEN = OFF      // VREG Sleep Enable bit (Ultra low-power regulator is Disabled (Controlled by REGSLP bit))
#pragma config INTOSCSEL = HIGH // LF-INTOSC Low-power Enable bit (LF-INTOSC in High-power mode during Sleep)
#pragma config SOSCSEL = HIGH   // SOSC Power Selection and mode Configuration bits (High Power SOSC circuit selected)
#pragma config XINST = OFF       // Extended Instruction Set (Enabled)
// CONFIG1H
#pragma config FOSC = INTIO2    // Oscillator (Internal RC oscillator)
#pragma config PLLCFG = OFF     // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)
// CONFIG2L
#pragma config PWRTEN = OFF     // Power Up Timer (Disabled)
#pragma config BOREN = SBORDIS  // Brown Out Detect (Enabled in hardware, SBOREN disabled)
#pragma config BORV = 3         // Brown-out Reset Voltage bits (1.8V)
#pragma config BORPWR = ZPBORMV // BORMV Power level (ZPBORMV instead of BORMV is selected)
// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1048576  // Watchdog Postscaler (1:1048576)
// CONFIG3H
#pragma config CANMX = PORTB    // ECAN Mux bit (ECAN TX and RX pins are located on RB2 and RB3, respectively)
#pragma config MSSPMSK = MSK7   // MSSP address masking (7 Bit address masking mode)
#pragma config MCLRE = ON       // Master Clear Enable (MCLR Enabled, RE3 Disabled)
// CONFIG4L
#pragma config STVREN = ON      // Stack Overflow Reset (Enabled)
#pragma config BBSIZ = BB2K     // Boot Block Size (2K word Boot Block size)
// CONFIG5L
#pragma config CP0 = OFF        // Code Protect 00800-01FFF (Disabled)
#pragma config CP1 = OFF        // Code Protect 02000-03FFF (Disabled)
#pragma config CP2 = OFF        // Code Protect 04000-05FFF (Disabled)
#pragma config CP3 = OFF        // Code Protect 06000-07FFF (Disabled)
// CONFIG5H
#pragma config CPB = OFF        // Code Protect Boot (Disabled)
#pragma config CPD = OFF        // Data EE Read Protect (Disabled)
// CONFIG6L
#pragma config WRT0 = OFF       // Table Write Protect 00800-01FFF (Disabled)
#pragma config WRT1 = OFF       // Table Write Protect 02000-03FFF (Disabled)
#pragma config WRT2 = OFF       // Table Write Protect 04000-05FFF (Disabled)
#pragma config WRT3 = OFF       // Table Write Protect 06000-07FFF (Disabled)
// CONFIG6H
#pragma config WRTC = OFF       // Config. Write Protect (Disabled)
#pragma config WRTB = OFF       // Table Write Protect Boot (Disabled)
#pragma config WRTD = OFF       // Data EE Write Protect (Disabled)
// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protect 00800-01FFF (Disabled)
#pragma config EBTR1 = OFF      // Table Read Protect 02000-03FFF (Disabled)
#pragma config EBTR2 = OFF      // Table Read Protect 04000-05FFF (Disabled)
#pragma config EBTR3 = OFF      // Table Read Protect 06000-07FFF (Disabled)
// CONFIG7H
#pragma config EBTRB = OFF      // Table Read Protect Boot (Disabled)

#define S1            LATBbits.LATB0
#define S2            LATBbits.LATB1
#define S3            LATBbits.LATB2
#define S4            LATBbits.LATB3

void Port_pins_Initialized (void); //prototype function

unsigned char Display (unsigned char digit)
  {
    unsigned char pattern;
    unsigned char  SEGMENT[9] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
    pattern =  SEGMENT[digit] ;  //The pattern to return
    return (pattern);
  }

void main(void)  // main program start
{
   unsigned char Digit1, Digit2, Digit3, Digit4;
   int count=1234;
   unsigned char temp1, temp2, temp3;

   Port_pins_Initialized (); //// Initialize the device

   while (1)
   {
       Digit1 = count / 1000;
       temp1 = count % 1000;
       LATD = Display(Digit1);    //Display the Digit 1
       S1 = 1;     
       __delay_ms(10);            //10ms delay
       S1 = 0;


       Digit2 = temp1 / 100;
       temp2 = temp1 % 100;
       LATD = Display(Digit2);    //Display digit 2
       S2 = 1;   
       __delay_ms(10);            //10ms delay
       S2 = 0;     


       Digit3 = temp2 / 10;

       LATD = Display(Digit3);    //Display digit 3
       S3 = 1;     
       __delay_ms(10);            //a 10 ms delay
       S3 = 0;     

       Digit4 = temp2 % 10;
       LATD = Display(Digit4);    //Display digit 4
       S4 = 1;             /
       __delay_ms(10);            //10ms delay
       S4 = 0;     

   }

}

// Initialize the device
void Port_pins_Initialized (void)
{
    LATA = LATB = LATC = LATD = LATE =  0; // set all to 0

    TRISA = 0b0000000;// all are output, Unused
    TRISB = 0b0000000;// control signal S1, S2, S3, S4 (0-3))
    TRISC = 0b0000000;// All are output, Unused
    TRISD = 0b0000000;//  segment board connected
    TRISE = 0b0000000;// All are output, Unused

    ANCON0 = 0; // digital port
    ANCON1 = 0; // digital port
    CM1CON = 0; // Comparator off
    CM2CON = 0; // Comparator off
    ADCON0 = 0; // A/D conversion Disabled
}
Edit I will try to write further code for up counter
 

Attachments

Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
1234! Nice.
Edit I will try to write further code for up counter
Before you do that, fix the compiler warnings:
Djsarakar.c:65:79: warning: excess elements in array initializer
unsigned char SEGMENT[9] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
^~~~
Djsarakar.c:81:23: warning: implicit conversion changes signedness: 'int' to 'unsigned char' [-Wsign-conversion]
Digit1 = count / 1000;
~ ~~~~~~^~~~~~
Djsarakar.c:82:22: warning: implicit conversion loses integer precision: 'int' to 'unsigned char' [-Wconversion]
temp1 = count % 1000;
~ ~~~~~~^~~~~~
3 warnings generated.
If I may offer a critique of your code..
What you wrote has many problems. The biggest problem is that it is written as one big, monolithic block of operations that should be broken apart. I believe you will find that out when you try to incorporate a counter.

Look at it this way: You want to display a counter on your board. By inspection, there are two main functions that the program does.
1) it counts something
2) it displays the count

Your code mashes both functions together in a way that is going to be a challenge to add the counter part. First, separate the display and count functions.

You have demonstrated that you know how to multiplex the display - very good! But it's a mess.

The display multiplexer's task is to output segment patterns to individual digits at some interval that makes the display show all 4 digits individually. That's all it has to do. To do that, I would
Define an array of 4 characters (bytes) that hold the segment patterns for the digits to be displayed.
Write a function that outputs one segment pattern from the segment pattern array to one digit and does the next one each time it is called. Wrap around at the end.
Call the function often enough to have a smooth display. That's it.

The counter function is just that. Define an integer counter and count up and wrap around 9999-0000, That's it.

There is one thing missing. You have an integer counter that has a binary count in it but the display multiplexer wants segments. So.. you need an interface between the integer and the display.
Write a third function that converts the binary integer count to 4 segment patterns for the digits 0-9. Use the DIV and MOD (/ and %) functions to to that and when you get one digit extracted, look up its segment pattern as you did above and write it to the segments array that is the input to the display multiplexer.

Done.

The 3 program layers are therefore:

integer counter
|
converter- integer to segment patterns
|
multiplexer - output segment patterns sequentially to 7 segment displays continuously.

Note that when you break it up this way, ANY integer can be displayed. Just pass the integer to the converter. You can also reuse the code for other things. That's the way I would do it.

A few other things:
Your existing code recomputes things that haven't changed. Each digit is extracted from the input integer each time it is displayed. That burns a lot of computational time.
Your segment array, besides being the wrong size, should be declared outside of that function. When you initialize a variable inside the function the init code runs EVERY time the function is called (I verified that). That also wastes valuable CPU time. It should also be declared 'const char' so that it goes into ROM. Otherwise, it burns valuable RAM and the codespace required to initialize that RAM.

Give it some thought.
Have fun!
 
I basically mentioned that way earlier. Object orientation would mean a display with attributes so it's re-useable.

It's not an integer display. it should be able to display . . . . or abcd or 1000, or " 01" with various intensities and blink etc. or even rotating dots through another function.

Only implement what you need, but leave hooks for a more comprehensive display.

The only reason you should create mumbo-jumbo is if things are time critical or running out of memory or it's a very low cost very high volume device.
 
Top