Skip to main content
Renesas Electronics America - Knowledgebase

LED drive methods (78K0/Kx2, 78K0S/Kx1+)

Latest Updated:11/01/2007


LED drive methods (78K0/Kx2, 78K0S/Kx1+)


LED displays are the simplest output method used for microcontrollers. In contrast to LCDs or VFDs (Vacuum Fluorescent Displays), LED displays do not require a display controller and are relatively easy to use. Furthermore, they operate using the same power supply that operates the microcontroller and they are small in all respects, so they are now widely used.

Coffee Break

Recently, LEDs are commonly found in blue as well as the three primary colors. Their applications include Christmas lights, and their increasing popularity is also due to their long service life and low power consumption.
Despite the rapidly growing use of LEDs all around us, the fact remains that each LED color requires a different drive voltage. The earliest LEDs were red ones, which use a relatively low voltage (1.5 to 1.8 V). The more recent blue LEDs require quite a bit more: about 3 V.

[Basic drive method using ports]
When using a microcontroller to drive LEDs, the usual method is to use port functions. The left side of the figure below shows one basic connection method whereby the LED is connected between the port and ground and current is emitted from the port to drive the LEDs. The right side of the figure shows another basic connection method whereby the LED is connected between the port and a positive power supply and the port collects the current to drive the LEDs. Which of these methods to use is determined based on the port's drive capacity and the amount of current needed for the required LED brightness. 

LED brightness.

Coffee Break

 The connection methods shown above use a series resistor connected to the LED, which works to protect the port from an overcurrent. For LEDs, the current that flows in relation to the voltage varies greatly: very little current flows up to a certain voltage value, but above that value the current flow rapidly increases. This trend is illustrated in the figure at right.
Since microcontroller ports basically output digital signals (with a value of 0 or 1), the voltage drop at the port is limited to 1V or less even when the current flow is 5mA. When the current fluctuates by about half this amount, so that the voltage drop is only about 0.5V, that amount is applied to the LED, which increases the current about tenfold. To avoid this, a resistor is used to limit the current.

[Control by program]
When port 40 is connected as described above, the LED is turned on by outputting 1 to the port in the connection shown at left or by outputting 0 to the port in the connection shown at right. When only one LED is being controlled, it is simple to do this using bit manipulation.

  • LED ON processing using connection shown on left side: SET1 P4.0 (in C language, P4.0=1;)
  • LED ON processing using connection shown on right side: CLR1 P4.0 (in C language, P4.0=0;)

Thus, the LED's ON/OFF status can be controlled via these port operations. (See the LED drive examples in the figure below.)

[Drive current boost method]
If the amount of current needed to turn on the LED is too large to be driven by the microcontroller, a transistor is added. Normally, even when the LED's current is large, it will not exceed 100 mA, so a small signal transistor for low frequency amplification will suffice.

In this connection example, the signal is inverted by the transistor, so the LED is turned on when 1 is output to the port.

[Drive example for multiple LEDs]
In the examples shown above, one port is used to turn on one LED. However, when numerous LEDs are used, it is not possible to assign each LED to a different port. One solution is to use a dynamic display method involving a matrix. The following configuration can be used when the LED current is 2 mA or less and no more than four LEDs are turned on at the same time.


In the 78K0S/Kx1+, the port's drive capacity is 5 mA on the high side and 10 mA on the low side, i.e., it is larger on the low side. Although these values differ in the 78K0/Kx2, here too the low side has the greater drive capacity. The current that flows to the LED is determined based on the weaker of these two drive capacity values.

[Sample program 1]
For this connection, 1 is set to the higher port and 0 is set to the lower port for the LEDs to be turned on.
For example, to turn on L1's LED, 1 is set to P40 while 0 is set to P41 to P43, and 0 is set to P44 while 1 is set to P45 to P47.

        MOV     P4,# 11100001b  (In C language, P4 = 0b11100001;)

Since it is troublesome to set an immediate value for each LED, a table listing the corresponding LEDs (L1 to L16) is usually prepared and used as a table referencing for control. In the following table, 0 indicates LED OFF while 1 to 16 correspond to individual LEDs that are turned on.

        DB      11110000b       ; OFF
        DB      11100001b       ; LED1 ON data
        DB      11100010b       ; LED2 ON data
        DB      11100100b       ; LED3 ON data
        DB      11101000b       ; LED4 ON data
        DB      11010001b       ; LED5 ON data
        DB      11010010b       ; LED6 ON data
        DB      11010100b       ; LED7 ON data
        DB      11011000b       ; LED8 ON data
        DB      10110001b       ; LED9 ON data
        DB      10110010b       ; LED10 ON data
        DB      10110100b       ; LED11 ON data
        DB      10111000b       ; LED12 ON data
        DB      01110001b       ; LED13 ON data
        DB      01110010b       ; LED14 ON data
        DB      01110100b       ; LED15 ON data
        DB      01111000b       ; LED16 ON data

The following is an example of a program that turns on one of the LEDs using this table. In this program, the LED to be turned on is specified via the X register.

        PUSH    HL
        MOV     A,#LOW LEDDATA          ; Lower bits of table address
        ADD     A,X                     ; Add offset
        MOV     L,A
        MOV     A,#HIGH LEDDATA         ; Higher bits of table address
        ADDC    A,#0                    ; Carry to higher order
        MOV     H,A                     ; Set HL to table's read pointer 
        MOV     A,[HL]                  ; Read data
        MOV     P4,A                    ; Output to port
        POP     HL

[Sample program 2]
When the same processing is coded in C language, the LED ON data is set up as an array. The individual LEDs to be turned on are used as array numbers so that the LED ON data is read. An example of the C language code for this is shown below.
The array is defined by LEDSTATUS, comprised on 17 elements (unsigned char: byte data). This structure's array is defined using the name "disp".

typedef unsigned char LEDSTATUS[17];
const LEDSTATUS disp = {
        0b11110000,     // OFF
        0b01111000,     // LED1 ON data
        0b01110100,     // LED2 ON data
        0b01110010,     // LED3 ON data
        0b01110001,     // LED4 ON data
        0b10111000,     // LED5 ON data
        0b10110100,     // LED6 ON data
        0b10110010,     // LED7 ON data
        0b10110001,     // LED8 ON data
        0b11011000,     // LED9 ON data
        0b11010100,     // LED10 ON data
        0b11010010,     // LED11 ON data
        0b11010001,     // LED12 ON data
        0b11101000,     // LED13 ON data
        0b11100100,     // LED14 ON data
        0b11100010,     // LED15 ON data
        0b11100001,     // LED16 ON data

LEDON shown below is an example of a function that actually turns on LEDs using this array. This function calls the LED to be turned on (unsigned char: byte) as a argument. First the LED is turned off, then data is read from the array, and when the data is written to P4 the specified LED is turned on.

void    LEDON(unsigned char LEDNUMBER){
        P4 = 0b11110000;                /* Clear LED         */
        P4 = disp[LEDNUMBER];           /* Turn on specified LED */

While a table referencing is used in assembly language, in C language an array is referenced. Usually, setting the data definitions in the array (data table) takes more time than coding the program itself. Also, since this array is stored in ROM, const is declared at the start of the array's declaration to indicate that this array elements are constants.

[Use of sample program 2]
The following describes how program sample 2 is used. In this example, LED1 to LED16 are turned on successively at an interval of approximately one second when operating at 4 MHz and using timer H1.

#pragma SFR
#pragma NOP
void    main(void){
        unsigned char work1;

        P4 = 0b11110000;                /* Clear All LED        */
        PM4 = 0x00;                     /* Port 4 is Output     */

        TMHMD1 = 0b01000000;            /* set interval timer mode */
        CMP01 = 60;                     /* Interval = 60ms     */
        IF0 = 0x00;
        work1 = 0x01;
        TMHE1 = 1;
                LEDON(work1++);         /* LED on               */
                while(TMIFH1 == 0){
                NOP();                  /* wait timer interrupt */
                TMIFH1 = 0;
                if(work1 == 17) work1 = 1;

In this case, a timer is used to measure the timing for switching among the LEDs being turned on. The timer is set to operation mode (interval timer mode) and the count clock is set via the mode register, while the values to be counted are set to the compare register (CMP01) before starting (by setting 1 to TMHE1). With these settings, the timer issues an interrupt at the specified time interval, which sets an interrupt request flag (TMIFH1). Although this processing does not strictly require use of interrupts, in this case polling is performed using "while (TMIFH1 == 0)". Once the interrupt request flag is set, the loop can be omitted.
Once the loop is omitted, the interrupt request flag is cleared (TMIFH1 = 0). With an ordinary vector interrupt, once the interrupt has been received and a branch to the vector has occurred, the interrupt request flag is cleared automatically, but when polling is used it must be cleared by the program.

In addition to using vector interrupts or polling such as shown here, a timeout waiting method can be used. This method uses a power saving function (standby function) that stops the CPU's operations. During standby mode, the CPU is restarted by an interrupt request from the timer in order to resume processing. This means that masking of interrupts must be cleared in order to release standby mode. The main function described above is therefore changed as follows.

When a standby is set, in addition to a HALT instruction, a STOP instruction may also be used, which also stops the clock oscillation. However, in this case STOP should not be used because the timer needs to continue counting out the time. To use HALT, a #pragma directive must declare use of the HALT instruction. This is why "#pragma HALT" is added at the beginning. To cancel masking of interrupts, "TMMKH1 = 0" is also added. Since vector interrupts are not used, the CPU is set to interrupt disabled state.
On this basis, the "while" statement is changed to "HALT()" in order to wait for a timer interrupt.

For further description of interrupts, see the FAQ section entitled "Basic operations of interrupt service".
For further description of standby mode, see the FAQ section entitled "Standby operation".
Suitable Products