Search code examples
cmicrocontrollerpicmplabxc8

MPLAB XC8 Compiler PIC18F452 Multiplexed Seven Segment Display Code working properly


I am currently working on a code involving the MPLAB XC8 Compiler, PIC18F452 with a Multiplexed Seven Segment Display. I want to use two pushbuttons connected to pins RB2 and RB3 of PORTB of the PIC18F452 to increment and decrement a variable "count" and display this number from 0 to 99 on this display. Schematic and code is show below.

This code relatively functions as it is, and I do not believe the schematic is to blame for the issues I am seeing, nor is the byte array not correct as I am able to see each number when using the array with a 1 segment display.

The issue arrises when trying to use this multiplexing scheme shown in the below figure. I can successfully display two numbers on the seven segment displays, but there are strange anomalies present when executing this code. For one, I seem to not be able to display the number 1, 4 and occasionally 7 on either display, but when this digit does not show the display is blank, and when the button is again pushed the next number is shown as expected.

for example:

The display shows the numbers as follows for number sequences: 9... 10... 11... 12 13... 14... ect...

or

34.... 35... 36... 37....

Not sure where the issues lies, and debugging is not going well... any help would be appreciated.

Schematic for Multiplexed 7 Segment Display

#define _XTAL_FREQ 10000000
#include <xc.h>
#include <stdlib.h>
#define Digit1 PORTBbits.RB1 //variable to sink current to PNP base
#define Digit2 PORTBbits.RB2 //variable to sink current to PNP base
#define Switch1 PORTBbits.RB4 //switch decrement variable
#define Switch2 PORTBbits.RB3 //switch increment variable
#define Pressed1 1 //pressed is high
#define Pressed2 1 //pressed is high
void initialize();
void segment1 (void);
void segment2 (void);
void buttonPress(void);
void delay_ms(unsigned int);
void sendPattern1(unsigned char pattern);
void sendPattern2(unsigned char pattern3);
unsigned char rotateLeft(unsigned char pattern, int no);
unsigned char MSD, LSD, count=0;

Main code

void main(void){
  initialize();
  Digit1 = 0;
  Digit2 = 0;
  while(1){
  buttonPress();
  MSD = count/10 ;  
  segment1();
  Digit2 = 1;
  delay_ms(10); // Delay for 10 ms
  Digit2 = 0;
  LSD = count%10; 
  segment2();
  Digit1 = 1;
  delay_ms(10); // Delay for 10 ms
  Digit1 = 0;
   }
    return;
}

Functions to index Most Significant Digit and Least Significant Digit from array to be sent to the ports to sink current low for common annode display.

void segment1(void){
unsigned char segArrayC[]={0b11000000,0b11111001,0b00100100, 
0b00110000,0b00011001,0b00010010, 
0b00000010,0b11111000,0b00000000,0b00011000};
 unsigned char pattern;
    pattern = segArrayC[MSD];
    sendPattern1(pattern);
    return;
}
void segment2(void){
unsigned char segArrayD[]= {0b11000000,0b11111001,0b00100100,
0b00110000,0b00011001,0b00010010,0b00000010,
0b11111000,0b00000000,0b00011000};
unsigned char pattern3;
     pattern3 = segArrayD[LSD];
     sendPattern2(pattern3);
     return;
}

Button Press Code

void buttonPress(void){
  if (Switch1 == Pressed1) {
        ++count;
        delay_ms(100);
    }
 if (Switch2 == Pressed2) {
        --count;
        delay_ms(100);
    }

 if(count>=99||count<0)
 {
     count=0; 
     delay_ms(100);
 }
  return;
}

Function to rotate bytes in array two places to left to be displayed on PORTs

/** Rotate pattern to the left 'no' number of bits
 */
unsigned char rotateLeft(unsigned char pattern, int no) {
    return (((pattern << no) & 0xFF) | (pattern >> (8-no)));
}

Functions to output indexed array char to PORTC and PORTB pins

void sendPattern1(unsigned char pattern) {
    // Send pattern to appropriate port pins
    unsigned char pattern2;
    PORTC = pattern;
    pattern2=rotateLeft(pattern, 2);
    PORTB = pattern2;
    return;
}
void sendPattern2(unsigned char pattern3) {
    unsigned char pattern4;
    PORTC = pattern3;
    pattern4=rotateLeft(pattern3, 2);
    PORTB = pattern4;
    return;
}

Delay Function

    void delay_ms(unsigned int n){
    while (--n) _delay(2500);
}

Initialize pins to be used (0 output, 1 input)

void initialize() {
     TRISC = 0;
     TRISBbits.TRISB0 = 0;
     TRISBbits.TRISB1 = 0;
     TRISBbits.TRISB2 = 0;
     TRISBbits.TRISB4 = 1;
     TRISBbits.TRISB3 = 1;
     PORTC = 0x00;
     PORTB = 0x00;
}

Solution

  • In sendPattern() you write a rotated bit pattern to PORTB. This interferes with the setting the common anode control. So you see both digits only, if both right hand segments are turned on. According your schematic you should write a 0 to turn on the common anode. Try this:

    void main()
    {
         static const unsigned char segArray[]= 
         { 0b11000000, 0b11111001, 0b00100100, 0b00110000, 0b00011001,
           0b00010010, 0b00000010, 0b11111000, 0b00000000, 0b00011000
         };
         TRISC = 0; //PortC all OUTPUT
         PORTC = 0xFF; //PortC all HIGH = IDLE = LED_OFF
    
         TRISBbits.TRISB0 = 0; //Output unused
         TRISBbits.TRISB1 = 0; //Output Digit1
         TRISBbits.TRISB2 = 0; //Output Digit2
         TRISBbits.TRISB4 = 1; //Input: Switch PLUS
         TRISBbits.TRISB3 = 1; //Input: Switch MINUS 
    
         PORTB = 0x00;
         unsigned char count=0;
         for(;;)
         {
            //Handle buttons
            if (Switch1 && count<99) 
            {
               ++count;
               delay_ms(100);
            }
            if (Switch2 && count > 0) 
            {
               --count;
               delay_ms(100);
            }
    
            //Write high digit
            PORTC = segArray[count/10];  
            Digit2 = 0;
            delay_ms(10); // Delay for 10 ms
            Digit2 = 1;
    
            //Write low digit
            PORTC = segArray[count%10];  
            Digit1 = 0;
            delay_ms(10); // Delay for 10 ms
            Digit1 = 1;
       }
    }