Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Repurposing PIC16F877A 7 segment LED PCBs

Not open for further replies.


New Member
I have a few PCBs that have 4 large 7 segment LEDs. They were countdown timers for squash courts. They use an RS422/RS485 feed to send them the value to display, and use a PIC16F877A to drive the LEDs through a ULN2004AN and a 4511 for each LED and 4116R-1 resistor arrays..

The Rx side of the input to the PIC is easy to sort out, although the Tx part is unpopulated. Some of the PCB tracks go under the LEDs so unclear (to me) where they go. I've traced the pinouts from the PIC as best I can, but can't see how the code does the multiplexing - I assume switching the ULN2004 to turn on/off the LEDs in turn.

If anyone can give me a heads up on how it might work I'd be grateful. I've attached front and rear view of the PCB and the pinouts that I've been able to trace.

Grateful for any input/feedback! I can code in C (just about!).
PCB Back small.jpg
I'd try powering it up and see if it displays all zeros - if so then it should be fairly easy to work out how it is multiplexed. If no display then send it some data - something like 1,2,3,4 enter etc. I'm assuming you have a logic analyser - if not the 8 channel ones from Banggood for $5 work well.

Thanks for the reply. No logic analyser, but one on its way.

With the original firmware in the PIC (proprietary so can't get the source, only the hex dump), it displays 0, off, colon, 0, 1 with the dip switches all off or 1 , 2 off and 3, 4 on , so I expect the dip switches are used to allow up to 16 devices to be addressed.

That could mean that the data contains the device number as well as the time value. As the squash system had controllers on each court as well as the timers, there could be more in the string, such as type of device targeted.

I've tried sending 00 to 15 and 0000 as a 6 digit string, with various baud rates but no sign of life. The non-existent Tx from the PIC makes life difficult.
If you have the hex file then Nigel has(had?) the ability to convert it to source code.
Plus, once you have youe logic analyser you should be able to work out the multiplexing and write some test code.
Sounds like an interesting project.

Here's the hex file, in case anyone can decode it.Just knowing the serial parameters and input layout might get me over the line.

Thanks in advance.



  • PIC16F877A.hex
    45.4 KB · Views: 140
The fact that there is one 4511 for each digit would suggest that the display is not multiplexed. A multiplexed display would need only one CD4511.
I agree with BobW (Post #6). I expect that if you trace the connections to pin 5 of each 4511 you will find it goes back to a port pin on the PIC. The 4 data pins (Pins 1,2,6,7) of the 4511 will all go to the same pin on the PIC. The code to write to the display will be very simple. You will set RB0 to 3 to the value yo want to display on one digit position. You will then pulse the pin on the PIC that is connected to pin 5 of the 4511 for that digit low. You then do the same thing for the other three digits. Writing the code from scratch will be MUCH quicker than disassembling the HEX code from the PIC. (I did this once with the hex code from a PIC16F876 as I wanted to modify it to run on a PIC18F2525 which has more program memory. It took me a few months to do all this.) I suspect the the connections from RB4 to 7 drive the decimal points directly via the ULN2004s

You are both correct - the no 4 LED has a HEF4511BCP and the other 3 have a CD4511 each, together with a resistor array. I've now worked out that the 1 & 2 LEDs are driven using PORTD, and the 3 & 4 by PORTB. However, I don't understand why I don't have to send anything to PORTD other than making it output.

The colon is driven by RC0, the decimal points are not driven.

The following code lights up LEDs 1, 2 and 3 correctly, but I can't get LED 4 to show the correct digit.

Also, although I've been a programmer for decades, I've no real time experience. and as it executes each assignment to PORTB, the previous LED turns off. Here's my attempt at the code:

//*****I/O Configuration****//
TRISB=0X00; // Port B is output
PORTB=0X00; // Port B Low

TRISC=0X00; /// Port C is output
PORTC=0X00; // Port C Low
TRISC7=1; // Port C pin 7 input from Max3082

TRISD=0X00; // Port D is output to LEDs 1 & 2
PORTD=0X00; // Port D Low

//***End of I/O configuration**///

PORTB=0X16; // turn on led 1 as digit 6
PORTB=0X25; // turn on led 2 as digit 5
PORTB=0X44; // turn on led 3 as digit 4
PORTB=0X80; // turn on led 4 as digit 0
However, if I add another line to set led 4 as 0X85, it stays displaying 0!
You need to latch the digit into the 4511 by toggling pin 5 (Latch Enable). The sequence of operation would be:
1. Set the 4 data lines to the appropriate digit value.
2. Toggle 4511 pin 5 low then high.

Do this for each digit.
Now I see that pin 5 on each 4511 has a resistor pulling it down to zero, but a track on the other side of the PCB running back under the LEDs, so I need to trace these back to their origins.
I've tracked the latch enable pins: led 1 - RD7, led2 - RD6, led 3 - RD5 and led4 - RC1. Pins 0 - 3 of PortB go to pins 7,1,2,6 on the HEF4511BCP and the other 4511s. Pins 4 - 7 of portB go to the ULN2004 driving power to the leds 1,2,3,4. I just don't know how to code this. Any help gratefully received!
I ran the hex code thru the Oshonsoft emulator. Unknows are the configuration pins, etc. Assumed 4Mhz clock rate. Lots of extraneous 3FFF in the hex file, which I stripped out before loading into emulator, so some code may be a bit messed up. Attached is a PDF of observations of code running, and a crude assembly listing. Seems it uses an interrupt to detect received characters from UART, and stuffs the characters into storage locations.


  • 16f877a.pdf
    137.8 KB · Views: 163
    5 KB · Views: 152
I assume in post #11 that you mean bits 4 to 7 (Not pins 4 to 7) I think you will find that all the pin 1s of the 4511s are connected together. I think you will find that all the pin 2s of the 4511s are connected together. I think you will find that all the pin 6s of the 4511s are connected together. I think you will find that all the pin 17 of the 4511s are connected together. can you confirm this doing resistance measurements with a multimeter. Can you start drawing out a schematic from the information you have found so far. (This will save us having to go back through the posts to check on the use of the various port bits.

If I am correct about how the 4511s are connected then something like this should put 1234 into the displays

MOVLW 0xF1 PORTB ;The F drives the cathodes of all 4 displays. the 1 will be written into the latch for digit 1
BCF PORTD,7 ;Set portD bit 7 low to latch bits 0 to 3 into the 4511
NOP ; small delay
BSF PORTD,7 ; Return but 7 to high

And so on for the other 2 digits.

In the original post only two 4511s are shown. Is this a mistake, there are also two small chips marked as pic16f877s which can't be correct. Can you update it?

There are only two 4511s visible in the photo, but the OP said there was one 4511 for each digit. So, the other two may be the chips that have markings too faint to be legible.
Les's code in C,
    TRISB=0;               //all output
    TRISD=0x1f;            //7,6,5 output
    TRISC=0b11111101;      //RC1 output

It should put 1,2,3,4 on the display.

Hi Mike (Pommie)
My knowledge of "C" programming is almost zero but if I understand your code correctly you seem to be pulsing the the same bit for each digit. If this is so then only the latch for one digit will be written. I think it should go RD7, RD6, RD5, RD4. (I suspect you did a copy and paste and forgot to change the bit.)
Another point. In post #13 I should have said that RD7, RD6, RD5, RD4 need to be set high at the start of the program.

You are of course correct Les. To the OP, change the PORTDbits.RD7 to the relevant bits. Isn't LED 4 bit RC1?
I just posted the C code as many people will struggle with setting the TRIS registers etc.

Thank you for all your helpful replies. The 2 chips at the top of the photo are indeed 4511s, mislabelled as the PIC, due to my copy/ paste excesses!
And of course I referred to bits in PortB as pins.

However, With your advice I have created some code that turns on each LED with the appropriate number and leaves it on.

From the decoding supplied by sagor1, I believe I can create the code I need, albeit in C rather than assembler. Part of my problem is the number of tracks that went underneath the LEDs. Eventually, afer removing all the chips I used a multimeter to trace them. I've updated the PIC pinout accordingly and also the images of the front and back of the PCB.
PCB Front.jpg
PCB Back small.jpg

The process would be:

On power on, illuminate the colon to indicate power.
Set interrupts on
Set a timer interrupt of say 4 seconds (the PC software will send a time msg every 2 seconds.
If the timer runs out, assume no PC and turn off any values displayed on the LEDs
Accept an interrupt from the USART and read the data, storing it locally.
Disable interrupts to allow RB0 to used as output.
Call function to display time on LEDs
Enable interrupts and start timer wait again.

The code I have to drive the LEDs is as below. i is an unsigned int set to 5678. I have set large delays so I could observe the sequence, which occasionally became rather messy while I worked it out.

Thanks again to all of you helpful people.

colon=1; // turn on colon (RC0)

//***Splitting "i" into four digits***//
a=i%10;//4th digit is saved here
c=b%10;//3rd digit is saved here
e=d%10; //2nd digit is saved here
g=f%10; //1st digit is saved here
//***End of splitting***//

//***send digit to 4511 in turn - g then e then c then a****//

PORTB=0XF0; // turn on ULN2004 power to all 4 LEDs, clear digit bits

thebits = (char)g;
PORTB=PORTB | thebits; // turn on led 1
PORTB=PORTB ^ thebits; // turn off digit bits

thebits = (char)e;
PORTB=PORTB | thebits; // turn on led 2
PORTB=PORTB ^ thebits; // turn off digit bits

thebits = (char)c;
PORTB=PORTB | thebits; // turn on led 3
PORTB=PORTB ^ thebits; // turn off digit bits

thebits = (char)a;
PORTB=PORTB | thebits; // turn on led 4
PORTB=PORTB ^ thebits; // turn off digit bits


  • Pins.pdf
    82.9 KB · Views: 154
NTS, I think you are on the right track. Keep in mind however, that RC1 seemed to be inverted in my simulation - I have no idea why. If it works for you as written, then stick with it. Also, at a 4Mhz crystal, they toggled the enable lines with 5ms timers (5ms low, then high, then 5ms later next LED control goes low for 5ms). . Not sure how your code works in the final run, but maybe give some delay between going low then back high on the toggle bits. The board you have may have long traces, and there may be some "ringing" or capacitance effect on the signal lines if toggling them too quick.

Good luck.
Not open for further replies.

New Articles From Microcontroller Tips