I am new to programming embedded systems, so any help is appreciated with my question. My task is to program (in C) a timer that counts up on a 7 segment common cathode display such that it will read for example: 000, 001, ..., 010, 011, ... 110, ... 999

I am displaying all 3 digits at the same time via multiplexing with 3 N channel MOSFETs, by quickly switching on and off the gates of the MOSFETs (via GPIO).

What I have so far:

  • I have code that will make a timer for one digit; it displays and increments 0 to 9 but for 1 digit
  • I also have code that will switch on/off GPIO pins (including the MOSFET gates and each segment of the display

What I am missing is how I can put this all together so that will become what I want. The best I have gotten is that one digit will light and count 0 - 9, then it turns off. Then the next digit will light up and count 0 -9, then it turns off and etc.

Any tips? Not exactly looking for entire code write up, just maybe an outline of steps I can take.

  • \$\begingroup\$ The idea is to save on I/O pins. You blink the leds you want lit in a sequence/pattern/loop and you do it fast enough that the human eye cannot see the blinking. This saves on the number of pins required but also allows for the segments desired to be on to appear to be on. \$\endgroup\$ – old_timer Dec 7 '14 at 14:10

The trick here is that you should not treat each digit as a separate entity.

Basically, multiplexing is a way of sharing a small number of IO pins to control a larger number of physical things, in this case LEDs. This is called time-division multiplexing. Multiplexing is just a way of driving N*M devices with N+M IO pins.

What you're missing here is that you don't count for each digit internally. Instead, you have a counter that maintains the overall counter value.

Say the internal counter has a value of 502. First, you illuminate the number 1 digit, with the value 5. Then, you illuminate the number 2 digit, with the value 0, and finally, the number 3 digit with the value 2. There is no incrementing or really any knowledge of what the value 502 even means.

If you want to increment the counter, you have to alter the internal counter number, not anything having to do with the multiplexing system.

For an even more basic implementation, separate the entire concept of numbers from the multiplexing. In this case, you have a array in memory that's just dictates which LEDs in the array are lit. Your multiplexing system just sits there and scans that array, lighting up each part in turn, and nothing else. The code that handles or is even aware that the values in the array represent numbers doesn't know the digits are multiplexed, or even exist. It just knows that this bit means that that LED should be illuminated as it lights up each display segment in turn.

The code that writes the values into the array is what handles determining what ordering of bits means what digits.

Critically, the counting and the multiplexing are separate processes. For multiplexing to be effective in a display system, the multiplexing has to run fast (100+ times a second). However, since the code that modifies the array is separate, it can run much more slowly (e.g. at a rate humans can track, etc...).


The point is that counting and displaying are two separate processes.

To give you a more practical answer, here's how I've done this recently on a PIC (note: I'm at a random tinkering level):

  1. Set up one timer so that it overflows every one second and generates an interrupt. The interrupt routine relative to this timer will then add 1 to a previously initalized variable and set up the timer so that it starts counting again (i.e. setting up the initial value that you need so that it sends an interrupt after 1 second). So you have a variable that keeps the count. This number can be anything between 000 and 999, so you have to add an if...else stcuture in this same routine to reset the variable to zero if it reaches the limit.

  2. In the main, set up a loop that updates an array of numbers by putting in the digits of the current number, e.g. if the number is 391, it will put 3, 9 and 1 in the array. Just do this like dis[3]=number/1000; dis[2]=(number-dis[3]*1000)/100; etc. you get the drift, the remainder gets thrown away every time. This doesn't need to be done that often, humans are slow anyway. This isn't done in the interrupt routine because it's non-urgent calculations and you can't waste time there.

  3. Create another interrupt routine relative to another timer, set up so that it generates an interrupt approximately 50 times per second, this way you will not be able to see the displays turn on and off. In this routine, you turn off all displays (with display I mean the single 7 segment box), then turn on the one you want and display the digit you want. Then fix the timer bits so that the interrupt happens again after 1/50 s. This way, that display will stay lit with that number until the next interrupt. The next time, you will have to display another digit, on the following display. To keep track of this, use a n variable that goes from 0 to 2 and gets increased by one each time there's an interrupt from the display timer, and reset to 0 before the end of the interrupt routine if it has reached the number 2 (because you'll have to display the first/0th digit the next time, on the first/0th display). This way the code just has to take the nth element of the array, write it to the displays and turn on the nth display (e.g. write 0x01<<n to the register that decides which display is turned on, so it shifts the 1 to the approriate bit).

As you can see, the display uses one timer and one interrupt routine, and it behaves independently from the number. The fact that you're counting seconds instead of displaying any other number is completely irrelevant to the display driving part.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.