Author Topic: PIC16 XC8 7 seg cathode multiplexing  (Read 765 times)

0 Members and 1 Guest are viewing this topic.

Offline nexusTopic starter

  • Regular Contributor
  • *
  • Posts: 194
  • Country: us
PIC16 XC8 7 seg cathode multiplexing
« on: January 08, 2021, 09:43:17 pm »
Hi All,

I am a noob with microcontrollers and embedded programming in general. I just made a simple board with a PIC16F1788 that I want to use as a controller for a standard 4 wire PC fan. This is my first PIC project ever.

The schematic is attached.

Essentially, the end game function is intended to be this:

Turning on, I want the PIC16 to generate 25 kHz PWM out to the fan to control the speed. The user can adjust fan speed by changing the PWM duty cycle using a rotary encoder. Turning the encoder one way will increase PWM duty cycle, turning the other way will decrease.

When the user is not adjusting the PWM, the PIC will display the fan speed (in RPM) as read from the fan's tach signal, which is an open collector that pulls low twice per fan revolution.
When the user adjusts the PWM, the display will change to show PWM duty between 0-100. After 2 or 3 seconds of not using the encoder, it will go back to the fan tachometer display.

I have fabricated one board and have been experimenting with driving the display. This is where I am falling short; before dealing with anything else, I need to solve the display multiplexing problem.

As you can see from the schematic, the cathodes are multiplexed as opposed to the anodes. This requires less resistors than conventional anode multiplexing, but the complexity in software is increased. If I drive the display using regular anode multiplexing, it gets very dim as you increase the multiplex speed.

I am struggling greatly to write firmware using microchips free XC8 compiler in MPLABX IDE v5.40. Just cannot wrap my head around how to implement cathode multiplexing in software. The digit masking routines in C seems rather challenging, especially for someone like myself with mediocre hobbyist-level programming knowledge.

If anyone is an XC8 wizard and/or has dealt with a similar display driving challenge in this ecosystem, any pointers on how to accomplish this in software would be greatly appreciated!
« Last Edit: January 08, 2021, 09:44:55 pm by nexus »
 

Offline ggchab

  • Frequent Contributor
  • **
  • Posts: 276
  • Country: be
Re: PIC16 XC8 7 seg cathode multiplexing
« Reply #1 on: January 08, 2021, 10:23:25 pm »
With this type of configuration, I think you must drive more than one segment at a time. I you drive a full digit, the brightness will be too much dependent on the number of segments turned on.
So, if I am not wrong, the average current per segment will be something like 1/32 x 3.5 / 390. A bit less than 0.3mA ! Not that much...
I think you should experiment with the 390 ohm resistors to avoid burning the LED. Once you are sure everything is working, you will have to reduce them (or even, remove them). But if your code crashes while a LED is on, you will probably destroy it  :-[
 

Offline nexusTopic starter

  • Regular Contributor
  • *
  • Posts: 194
  • Country: us
Re: PIC16 XC8 7 seg cathode multiplexing
« Reply #2 on: January 08, 2021, 11:12:54 pm »
Yes, the way this this type of arrangement is driven must be as follows:

Both cathodes and anodes require a mask. Lets say I want to display an integer "i". If i = 1, then the anodes for display positions 1,2,3 must be off. Only the last digit anode must be on. Then, I would cycle each segment individually for the number "1".

If i = 11, then the only difference is that both anodes for digits 3 and 4 will be turned on. Nothing else differs from i = 1.

However, lets say I wanted to display i = 12. Now, when I multiplex the segments (cathodes), only 1 segment is in common between "1" and 2". So when I cycle through segments 1 through 7, the anodes need to be masked appropriately as well. I'm just having trouble combining the two masks in software because my understanding of C and XC8 are barely functional.
 

Offline Dabbot

  • Regular Contributor
  • *
  • Posts: 192
  • Country: au
Re: PIC16 XC8 7 seg cathode multiplexing
« Reply #3 on: January 09, 2021, 12:39:44 am »
You multiplex the display in the same manner regardless of which value you're displaying.

Set yourself up 4 variables for each digit, then do the following:


Start of loop

Set RA3 low (turn digit 4 off)
Set RC to digit 1's variable
Set RA6 high (turn digit 1 on)

Wait 5ms

Set RA6 low (turn digit 1 off)
Set RC to digit 2's variable
Set RA7 high (turn digit 2 on)

Wait 5ms

Set RA7 low (turn digit 2 off)
Set RC to digit 3's variable
Set RA4 high (turn digit 3 on)

Wait 5ms

Set RA4 low (turn digit 3 off)
Set RC to digit 4's variable
Set RA3 high (turn digit 4 on)

Wait 5ms

Go to start of loop


How you do this in code is up to you. Ideally you will want to handle this in an interrupt, but give yourself some time to get it going in a way you will most easily understand first.
« Last Edit: January 09, 2021, 12:45:36 am by Dabbot »
 

Offline Ian.M

  • Super Contributor
  • ***
  • Posts: 12865
Re: PIC16 XC8 7 seg cathode multiplexing
« Reply #4 on: January 09, 2021, 12:42:56 am »
Its really no different to normal digit multiplexing.  You activate one segment at a time, and *all* the digit cathodes that have that segment lit.  To do so, you have a buffer array with a byte for each segment, containing bits for each digit.  The multiplexing should run in a timer ISR, for one segment at a time.  Simply deactivate the previous segment, increment the segment index (with wraparound when it goes out of range), output the digit bits from the array at the current segment index, and activate the segment.  The segment index should be static and local to the ISR, and the buffer array needs to be volatile and have file scope or be global.

The complexity comes when you need to write numbers to the buffer array,  e.g. to clear a digit, you need to go through the whole array, masking that digit's bit to 0.   To display a single digit of a number on a specific digit position, again you loop through the whole array masking that digit's bit, but each time masking it to either 1 or 0 depending on whether or not the number needs  that segment illuminated.  Repeat sequentially with other digits till the whole number is displayed.   That's all in the main program, though if you've got any savvy, you'll write a function for it to encapsulate the mess and keep it all in one place.

Incidentally, its a poor design choice - resistors are far cheaper than ultrabright 7 segment LEDs vs standard ones, and by multiplexing the segments, at best you can get a 1/8 duty cycle, but for four more resistors you could have multiplexed the digits for a 1/4 duty cycle and double the brightness, + made the code much simpler
« Last Edit: January 09, 2021, 12:55:38 am by Ian.M »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf