What is the dynamic display methods for LEDs (78K0/Kx2, 78K0S/Kx1+)?
Question:
Answer:
[Introduction]
Dynamic display methods are used for displaying a lot of information. See also the FAQ section entitled "Dynamic and static".
The following describes the dynamic display method used for the circuit that was described as the figure "Example of matrix connection for LEDs" in the FAQ section entitled "LED drive methods" category.
[Display method]
Here, 16 LEDs are divided into four groups: L1 to L4, L5 to L8, L9 to L12, and L13 to L16. In P44 to P47, 0 is set to the ports corresponding to the LED groups including the LEDs to be turned on, and 1 is set to the other ports. P40 to P43 are used to specify the LEDs to be turned on. As shown in the figure below, 0 is set to P44, P45, P46, and P47 in that order, for low-level output from those ports. In combination with this, the corresponding LED turning-on pattern is output to P40 to P43.
The display is switched every 2.5 ms, so that within 10 ms (when at 100 Hz) turning on of the whole LEDs is completed. Consequently, the system clock is used as a 4 MHz clock that is generated by dividing 8 MHz high-speed internal oscillation clock by 2. This clock is also divided by 64 for count clock of the 8-bit timer. Additionally, the count clock is divided by 156 with the 8-bit timer to generate interval interrupts at approximately 400 Hz. The display is changed in these interval interrupt servicing.
[Sample program 1]
The following shows a sample program (for 78K0S/Kx1+) coded in assembly language. A sample program in C language is shown in sample program 2.
To specify a display, two 8-bit LED status variables (LEDSTATUS1 and LEDSTATUS2) corresponding to the LEDs to be turned on are provided, and the display data is set to these variables. During the timer interrupt servicing, the data corresponding to four LEDs is extracted from the bits corresponding to the LEDs to be turned on. This data is combined with the data specifying the display groups and then output to port 4 to turn on LEDs. This is repeated four times to complete the display.
• Generation of display data
To divide the LED status information into four groups before turning on LEDs, a display data pattern is extracted from the LED status based on the information indicating which of the four display iterations has been specified. To generate the display data, information indicating which of the four groups has been specified is generated by the X register and information indicating which LED is to be turned on is generated by the A register, and then these are combined. Processing time is shortened by performing parallel processing of the information indicating the LED group and the information indicating the LEDs to be turned on, and then combining these processing results. The sample program shown below mainly contains processing of group selection information from the X register and processing of the specific LED turning-on information from the A register.
DATWORK DSEG SADDR NEXTDATA: DS 1 ; For storing next display data LEDSTATUS1: DS 1 ; Information for turning on LED1 to LED8 ; (1 = ON) LEDSTATUS2: DS 1 ; Information for turning on LED9 to LED16 ; (1 = ON) COUNT: DS 1 ; Display iteration information (0 to 3) GETLED: MOV A,LEDSTATUS1 ; Read status of LED1 to LED8 MOV X,#11101111b ; Select signal for LED1 to LED4 BF COUNT.1,$NEXT1 ; Branch to NEXT1 if LED1 to LED8 are displayed MOV A,LEDSTATUS2 ; Otherwise, Read status of LED9 to LED16 MOV X,#10111111b ; Select signal for LED9 to LED12 NEXT1: BF COUNT.0,$NEXT2 ; Branch if LED1 to LED4 or LED9 to LED12 ROR A,1 ; Set valid LED bits to lower 4 bits ROR A,1 ROR A,1 ROR A,1 XCH A,X ; Send group select signal to A register ROL A,1 ; Shift select signal to next group XCH A,X ; A:LED status, X:Group information NEXT2: OR A,#11110000b ; Mask group information AND A,X ; Combine display data MOV NEXTDATA,A ; Save next display data RET
• Display of data (timer interrupt servicing)
Each group of LEDs is turned on using interrupts that are generated every 2.5 ms.
The subroutine shown above is used to generate the data to be displayed.
First, the current display is deleted, then the data that was previously calculated is output to a port to execute the display. Afterward, the next group is selected and its display data is set up.
The reason why previously calculated data is used is to minimize any timing variation effects.
TMH1INT: PUSH AX MOV A,NEXTDATA ; Read display data information MOV P4,#11110000b ; Turning off all LEDs MOV P4,A ; Display new data INC COUNT ; Select next group MOV A,#00000011b ; Mask number of groups displayed. AND A,COUNT ; If all columns have been completed, MOV COUNT,A ; set next group. CALL !GETLED ; Generate next display data. : Other required processing is coded here. : POP AX DUMMY: RETI ; End of interrupt servicing
• Initialization processing
Initialization processing includes setting the stack pointers, waiting for power supply activation, and initializing memory and other on-chip peripheral hardware that is used. Afterward, the timer is started and interrupt masking is canceled, then other processing is performed. When a timer interrupt occurs, the LED display starts.
The reset vectors and interrupt vectors are programmed as shown below. Dummy vectors are set so that the results for unused interrupts are returned by a RETI instruction, without performing any processing for them.
RSTVECT CSEG AT 0 DW START ;00:Vector for reset start processing DW DUMMY ;02: DW DUMMY ;04: DW DUMMY ;06:INTLVI DW DUMMY ;08:INTP0 DW DUMMY ;0A:INTP1 DW TMH1INT ;0C:INTTMH1 DW DUMMY ;0E:INTTM000 DW DUMMY ;10:INTTM010 DW DUMMY ;12:INTAD CSEG START: MOVW AX,#STACKP MOVW SP,AX CALL !POWERON ; Wait for power supply activation CALL !INITIO ; Hardware initialization CALL !INITRAM ; RAM initialization : : SET1 TMHE1 ; Start timer CLR1 TMMKH1 ; Cancel masking of timer interrupts EI : Other desired processing is coded here : ; ; Wait for power supply activation ; (wait until power supply voltage reaches at least 2.7 V) ; POWERON: DI MOV LVIS,#00000111b ; VLI=2.7V MOV LVIM,#10000000b ; Start low voltage detection MOV PCC,#00 ; CPU clock is fx/4 MOV WDTM,#01110000b ; Stop WDT SET1 LSRSTOP ; Stop low-speed internal oscillator MOV A,#50 PONLOOP: DEC A BNZ $PONLOOP ; Wait more than 0.2 ms PONLOOP2: BT LVIF,$PONLOOP2 ; Wait for power supply voltage to reach 2.7 V MOV PPCC,#01 ; CPU clock is fx/2 RET ; ; RAM initialization ; INITRAM: MOV COUNT,#3 MOV LEDSTATUS1,#0 MOV LEDSTATUS2,#0 MOV NEXTDATA,#11110000b RET ; ; Hardware initialization settings for timer H1, port 4, etc. ; INITIO: MOV P4,#11110000b ; Initial value (all LEDs off) MOV PM4,#00 ; Port 4 set to all output MOV TMHMD1,#00110000b ; Timer mode setting ; |||++----- Interval timer mode ; +++------- Count clock fXP/64 MOV CMP01,#155 ; Set interval period MOV IF0,#00 ; Clear interrupt : Other required initialization processing is coded here : RET
[Sample program 2]
The following describes an example of an LED display program coded in C language. In this example, there is additional processing that adds 1 to the display pattern about once per second.
• Declarations
Since this program controls interrupts except during I/O operations involving on-chip peripherals, a #pragma directive is declared at the start of the program, as shown below. In the prototype declaration, GETLED is declared as the function that performs interrupt servicing.
Coffee break In the C language that is used for 78K Series products, certain functions are expanded for embedded uses within the standard C language. Declarations are required to enable use of these expanded functions. The main declarations are "#pragma SFR", used as a key word for on-chip peripheral I/O operations, as well as "#pragma EI", "#pragma NOP", and other directives that specify how various CPU instructions will be used in C language programs. Finally, the "#pragma INTERRUPT INTTMH1 GETLED" directive is used to combine the CPU's vector interrupt (in this case, INTTMH1) with the actual processing function (in this case, GETLED). |
In addition, in the prototype declaration, hdwinit is declared to perform hardware initialization.
As a variable, LEDSTATUS contains information on LEDs to be turned on, and in this case it is processed as a 16-bit variable. SECTIMER is used to count one second of time. NEXTDATA and COUNT are used with the same meaning they have in assembly language programs.
#pragma SFR #pragma EI #pragma DI #pragma NOP #pragma INTERRUPT INTTMH1 GETLED unsigned int LEDSTATUS,SECTIMER; unsigned char NEXTDATA,COUNT; __interrupt void GETLED(void); void hdwinit(void);
• Initialization processing block
In the 78K's C language program, initialization processing for on-chip peripheral I/O operations can be performed before the main part of the program is executed. The special-purpose function (hdwinit) is reserved for this purpose. The tasks that must be processed early on are coded in the hdwinit function.
Coffee break In an "All Flash" type of 78K microcontroller, the hardware configuration is determined by referencing the option byte when the CPU is started. Afterward, execution starts from the address stored in the reset vector (addresses 0 and 1). In an assembly language program, the reset vector is coded as part of the program, but in a C language program, a startup routine is used instead. For further description of this startup routine see the FAQ section entitled"First execution tasks". The startup routine performs the setting of the stack pointer and other processing needed to execute C language programs. This routine includes a hdwinit function call. Once this series of processing has been completed, the startup routine calls the main function coded in C language to execute the C language program. |
The hdwinit function shown below first stops the watchdog timer, then uses low voltage detection to wait for the power supply voltage to rise. Once low voltage detection has started, it takes 0.2 ms before accurate results can be obtained, and a software timer is used for this wait operation. When the power supply voltage reaches at least 2.7 V, the CPU's operating clock is set to 4 MHz and the target ports, timers, etc. are initialized.
void hdwinit(void){ unsigned char work1; LVIS = 0b00000111; /* select VLI=2.7V */ LVIM = 0b10000000; /* Start VLI detection */ PCC = 0x00; /* CPU clock is fx/4 */ WDTM = 0b01110000; /* Stop WDT */ LSRSTOP = 1; /* Stop Low speed OSC */ /* wait for 0.2ms */ for (work1 = 0; work1 < 10; work1++){ NOP(); } while ( LVIF ){ NOP(); } /* wait VDD > 2.7V */ PPCC = 0b00000001; /* CPU clock is fx/2 */ P4 = 0b11110000; /* Clear All LED */ PM4 = 0x00; /* Port 4 is Output */ TMHMD1 = 0b00110000; /* set interval timer mode */ CMP01 = 155; /* Interval = 2.5ms */ IF0 = 0x00; }
• Main processing block
The main function sets initial values for variables. Afterward, it starts the time and waits for the variable that counts one-second periods (SECTTIMER) to reach a value of 0. When one second has elapsed, 1 is added to the display data (LEDSTATUS) value. Data is written to the SECTIMER variable from both the main function and the interrupt function, so exclusive control should normally be used for this. However, exclusive control (in this case, enabling or prohibiting interrupts) is not performed here since processing is completed within the interrupt interval (2.5 ms).
void main(void){ COUNT = 3; NEXTDATA = 0b1111000; LEDSTATUS = 1; SECTIMER = 400; TMHE1 = 1; TMMKH1 = 0; EI(); while(1){ while(SECTIMER){ NOP(); } SECTIMER = 400; LEDSTATUS++; } }
• Interrupt servicing block
Interrupts are triggered and executed every 2.5 ms using timer H1. Consequently, "__interrupt" is declared at the start of functions to indicate when the function is an interrupt servicing function. Otherwise, these functions are similar to functions that do not include arguments or return values.
Most of the processing concerns the generation of data patterns that are output to ports to set up displays. One such function is to generate a select signal for the group that corresponds to the groups to be displayed. This function is implemented by using a switch statement in which values are set to NEXTDATA according to the COUNT variable. Another function extracts display data. The data to be displayed (LEDSTATUS) is right-shifted precisely the required number of times, and data other than the lower four bits is masked to implement this function. The two sets of data acquired in this way are then combined to form a data pattern for the next display.
Other processing includes outputting the previously generated data pattern to a port, updating the display group for the next display, and counting out another second.
__interrupt void GETLED(void){ unsigned int work1; unsigned char work2; P4 = 0b11110000; /* Clear LED */ P4 = NEXTDATA; /* Turn on specified LED */ work1 = COUNT; /* Get Display Group Number */ switch(work1){ case 0: NEXTDATA = 0b11100000; break; case 1: NEXTDATA = 0b11010000; break; case 2: NEXTDATA = 0b10110000; break; case 3: NEXTDATA = 0b01110000; } work1 *= 4; work2 = LEDSTATUS >> work1; work2 &= 0b00001111; work1 = (unsigned char) work2; NEXTDATA |= work1; COUNT = (COUNT+1) & 0b00000011; SECTIMER--; }