For part 1 of this series, covering the design of the I/O Expander firmware, please see this Hackster Post.
The 7-segment display is a classic display technology, commonly used to show everything from time to counter values. Each display is composed of an array of LEDs which form each of the display segments. Two of the biggest challenges with these types of displays are the number of I/O needed and the amount of current to sink or source into each segment. By using the PIC16F15244 as an I/O expander, the power dissipation and quantity of I/O required by the main microcontroller are reduced.
The PIC16F15244 device family can be used to drive the display directly due to the strong sinking and sourcing capabilities of the device, so long as the I/O current is kept within the limits defined in the device datasheet.Example Code
For testing functionality, we developed an Arduino compatible library (not endorsed or related to Arduino). It is provided along with the required firmware for the PIC16F15244 family device is available on Github. Inside the Github repository, there are 2 software examples:
- 123_gettingStarted - Displays “1 2 3” on the display. This code is a good starting point to tinker with.
- countdownTimer - The display shows a 10 second countdown timer with a reset button.
Note: Program the device before wiring RA0 and RA1 - these are used by the programmer.Initializing the Countdown Timer
Important: Before continuing, be sure to program the PIC16F15244 device with the “Advanced I2C Expander” Code Example and install the communication library (located in the same repository).
For this example, pins 6 – 0 are the outputs to the 7-segment display. Pin 7 is a connection to a push-button which resets the countdown timer.
On start, the program resets the device to the default settings that the device was compiled with. The other configuration steps are blocked until the INT line is asserted by the device, which indicates that the settings have been applied and the device is ready for more I2C communication.
On PIC® MCUs, the TRIState (TRISx) register controls the direction of the I/O. If a bit is set to 0, then it is an output, while a 1 indicates the pin is an input. For this example, TRISx, where the x indicates the I/O PORT that is being controlled by the example, should be set to 0x80 (in binary: 0b1000 0000) to control the display and utilize the pushbutton.
For the pushbutton to operate correctly, the button needs to be pulled-up to Vdd when the button is not pressed. This ensures the button is at a logic 1 when idle. When the button is pressed, the button connects the I/O line to ground, which causes the line to fall to a logic 0. To achieve this without adding an extra resistor, the internal weak pull-up (WPUx) resistors are turned on for this I/O line.
Next, the interrupt events need to be setup for the I/O expander. There are two possible interrupt sources when running – interrupt on change (IOC) [caused by rising edges (IOCxP) or falling edges (IOCxN)] and memory operation completion. In the case of this example, the only interrupt (after the initial reconfiguration) is when the button is pressed (IOCxN) or when the button is released (IOCxP). By default, the falling edge is used, however using the released edge is also a valid configuration. Both events can be enabled at the same time, however the status register does not differentiate between the two.Setting Up the Display
If the display used is a common-anode display, then the device sinks current when the segments are on. With a common-cathode display, the inverse is true. In order to turn off the LEDs, it is necessary for the I/O lines to be at the inverse of the ON state. Table 1 shows the relationship in more detail.
Alternatively, the lines could be tri-stated (TRISx) to turn them off, however it is more power efficient and better practice to change the output logic level (LATx) due to leakage current.Countdown Timer Looping Code
Note: Before running this example, please select the function to match the type of display in use.
set7SegmentActiveLow- Used for Common Anode Displays
set7SegmentActiveHigh- Used for Common Cathode Displays
In the loop, the program checks for a flag that is set when the interrupt (INT) line goes low, indicating a change in state for the pushbutton. When this flag is set, the IOC register is cleared by reading it, and the counter is reset to 10.
If the counter is not 0, then (counter – 1) is shown on the display. When the counter equals 0, then the display flashes at 2 Hz while showing 0, as shown in figure 2.Concluding Remarks
This code example shows one way that the I/O expander can be used to simplify a larger and more complex system. Creating this functionality without an I/O expander would add at least 5 additional I/O lines to the main microcontroller. The saved I/O lines could be used to add more features or to use a physically smaller, and almost certainly cheaper, microcontroller.
For the final part of this series, covering the use of the I/O Expander to create a keypad controller, please see this Hackster post.