;=======================================================================

; tm1638cc.s - s'AVR version by EH

;

; s'AVR version tested using LED&KEY board

;

; Examples to be used with the tm1638 library

; written by Ralf Jardon (cosmicos@gmx.net), May-July 2017

;

; Comments related to the datasheet refer to version 1.3 (EN)

;

; License: GNU GENERAL PUBLIC LICENSE, Version 3, 29 June 2007

;

; 24-AUG-2017 V1.0 includes support for up to 8 key buttons and a realtime clock

; 27-AUG-2017 V1.1 demo now including a 8*100 hrs elapsed timer

; 05-SEP-2017 V1.2 Elapsed time allows split time to calculate the correction

;                  various PRINT time routines moved from .INC to main programm

;=======================================================================

 

;.NOLIST

 

.INCLUDE "tm1638cc_EH.def"  ; various definitions, originally tm1638cc.h

.INCLUDE "tm1638cc.mac"     ; TM1638 macros for the SPI interface

 

.LIST

.LISTMAC

 

.CSEG

 

.ORG $0000                  ;  Start of program code after Reset

 

; Reset and Interrupt Vectors (two address locations each!):

; ATmega328P can use absolute JMP instructions instead of RJMP!!!

; Otherwise a NOP is required after RJMP (or after RETI).

 

        rjmp    init        ;  1 RESET      External Pin, Power-on Reset,

        nop                 ;  Brown-out Reset and Watchdog System Reset

        reti                ;  2 INT0addr   INT0 External Interrupt Request 0

        nop

        reti                ;  3 INT1addr   INT1 External Interrupt Request 1

        nop

        reti                ;  4 PCI0addr   PCINT0 Pin Change Interrupt Request 0

        nop

        reti                ;  5 PCI1addr   PCINT1 Pin Change Interrupt Request 1

        nop

        reti                ;  6 PCI2addr   PCINT2 Pin Change Interrupt Request 2

        nop

        reti                ;  7 WDTaddr    WDT Watchdog Time-out Interrupt

        nop

        reti                ;  8 OC2Aaddr   TIMER2 COMPA Timer/Counter2 Compare Match A

        nop

        reti                ;  9 OC2Baddr   TIMER2 COMPB Timer/Counter2 Compare Match B

        nop

        reti                ; 10 OVF2addr   TIMER2 OVF Timer/Counter2 Overflow

        nop

        reti                ; 11 ICP1addr   TIMER1 CAPT Timer/Counter1 Capture Event

        nop

        rjmp    time10ms    ; 12 OC1Aaddr   TIMER1 COMPA Timer/Counter1 Compare Match A

        nop                 ;               separate interrupt for 10ms timer

        reti                ; 13 OC1Baddr   TIMER1 COMPB Timer/Counter1 Compare Match B

        nop

        reti                ; 14 OVF1addr   TIMER1 OVF Timer/Counter1 Overflow

        nop

        reti                ; 15 OC0Aaddr   TIMER0 COMPA Timer/Counter0 Compare Match A

        nop

        reti                ; 16 OC0Baddr   TIMER0 COMPB Timer/Counter0 Compare Match B

        nop

        reti                ; 17 OVF0addr   TIMER0 OVF Timer/Counter0 Overflow

        nop

        reti                ; 18 SPIaddr    SPI, STC SPI Serial Transfer Complete

        nop

        reti                ; 19 URXCaddr   USART, RX USART Rx Complete

        nop

        reti                ; 20 UDREaddr   USART, UDRE USART, Data Register Empty

        nop

        reti                ; 21 UTXCaddr   USART, TX USART, Tx Complete

        nop

        reti                ; 22 ADCCaddr   ADC ADC Conversion Complete

        nop

        reti                ; 23 ERDYaddr   EE READY EEPROM Ready

        nop

        reti                ; 24 ACIaddr    ANALOG COMP Analog Comparator

        nop

        reti                ; 25 TWIaddr    TWI (I2C) 2-wire Serial Interface

        nop

        reti                ; 26 SPMRaddr   SPM READY Store Program Memory Ready

        nop

   

;=======================================================================

;                           INIT and MAIN LOOP

;=======================================================================

.ORG $100                       ; alternately .ORG INT_VECTORS_SIZE

 

init:

    ldi     AKKU, HIGH(RAMEND)  ; Initialize stack pointer

    out     SPH, AKKU

    ldi     AKKU, LOW(RAMEND)

    out     SPL, AKKU

    rcall   TM1638_INIT         ; Initialize Ports, SPI & TM1638

 

    cli                         ; prepare Timer1 interrupts (100 Hz, 10ms)

    ldi     AKKU, (1<<WGM12) | (1<<CS11) | (1<<CS10)    ; CTC OCR1A, /64

    sts     TCCR1B, AKKU        ; works with most standard xtal frequencies

    ; OCR1A will trigger the 100Hz/10ms timer and reset the CTC

    ldi     AKKU, HIGH(XTAL/6400-1) ; Compare register A high byte

    sts     OCR1AH, AKKU

    ldi     AKKU, LOW(XTAL/6400-1)  ; Compare register A low byte

    sts     OCR1AL, AKKU

    ldi     AKKU, (1<<OCIE1A)   ; only 10ms interrupt

    sts     TIMSK1, AKKU        ; Enable Timer1 Compare A

    clr     BUTTONS             ; mark pushed key buttons bitwise (up to 8)

    ldi     yl,low(clk10ms)     ; begin of clock timer values ...

    ldi     yh,high(clk10ms)    ; ... 10ms/sec/min/hrs in SRAM

    clr     AKKU

    FOR COUNT := #20            ; clock time, elapsed time, split time ...

        st      y+,AKKU         ; clear time locations in SRAM

    ENDF

    sei                         ; enable Interrupts

    ldi     AKKU,1

    mov     TRUE,AKKU           ; register TRUE stays always 1

 

    ldi     AKKU3, 1            ; "88888888", Text block 1

    rcall   TM1638_PRINT_TXT8

    rcall   TM1638_LEDS_BF      ; LEDs back and forth

 

    clr     AKKU3               ; "TM1638 DEMO", Text block 0

    rcall   TM1638_PRINT_MOVETEXT

    rcall   TM1638_LEDS_BF      ; LEDs back and forth

 

;=======================================================================

 

LOOP    ; (LOOP is not an address!)     ; Main Loop

    rcall   TM1638_CLEAR

    ldi     AKKU3, 4                    ; "TEST KEY", Text block 4

    rcall   TM1638_PRINT_TXT8

 

    LOOP                            ; TEST KEY loop

        rcall   delay500ms          ; if S1+S8 are pushed continuously

        clr     BUTTONS

        REPEAT

            rcall   TM1638_KEYPAD   ; check the TM1638 buttons

        UNTIL BUTTONS <> #0         ; wait until any button pressed

        mov     AKKU,BUTTONS        ; to check more than one button

        EXITIF AKKU == #S18         ; exit if both S1 and S8 are pressed

        rcall   TM1638_CLEAR        ; test and display all keys separately

        IF BUTTONS, S1

            ldi     TM1638_SEGM_BYTE,'1'

            ldi     TM1638_GRID_BYTE,0  ; left most digit

        ELSEIF BUTTONS, S2

            ldi     TM1638_SEGM_BYTE,'2'

            ldi     TM1638_GRID_BYTE,2  ; 2nd digit

        ELSEIF BUTTONS, S3

            ldi     TM1638_SEGM_BYTE,'3'

            ldi     TM1638_GRID_BYTE,4  ; 3rd digit

        ELSEIF BUTTONS, S4

            ldi     TM1638_SEGM_BYTE,'4'

            ldi     TM1638_GRID_BYTE,6  ; 4th digit

        ELSEIF BUTTONS, S5

            ldi     TM1638_SEGM_BYTE,'5'

            ldi     TM1638_GRID_BYTE,8  ; 5th digit

        ELSEIF BUTTONS, S6

            ldi     TM1638_SEGM_BYTE,'6'

            ldi     TM1638_GRID_BYTE,10 ; 6th digit

        ELSEIF BUTTONS, S7

            ldi     TM1638_SEGM_BYTE,'7'

            ldi     TM1638_GRID_BYTE,12 ; 7th digit

        ELSEIF BUTTONS, S8

            ldi     TM1638_SEGM_BYTE,'8'

            ldi     TM1638_GRID_BYTE,14 ; 8th digit

        ELSE

            ldi     TM1638_SEGM_BYTE,' '

            ldi     TM1638_GRID_BYTE,0  ; 1st digit

        ENDI

        rcall   TM1638_PRINT_CHAR

    ENDL

 

    LOOP                            ; now loop the various demo programs

        rcall   TM1638_CLEAR

        ldi     AKKU3, 3            ; "SELECT..", Text block 3

        rcall   TM1638_PRINT_TXT8

        rcall   delay500ms          ; if S1+S8 are pushed continuously

        clr     BUTTONS

        REPEAT

            rcall   TM1638_KEYPAD   ; check the TM1638 buttons

        UNTIL BUTTONS <> #0         ; wait until any button pressed

        EXITIF  BUTTONS, S8         ; button S8 leaves demos to TEST KEY

                                    ; select demo by button S1..S7

        IF BUTTONS, S1

            FOR COUNT := #3

                rcall   TM1638_TWIST_CW ; twist LEDs cw

            ENDF

            rcall   TM1638_CLEAR

            FOR COUNT := #3

                rcall   TM1638_TWIST_CCW    ; twist LEDs ccw

            ENDF

            rcall   TM1638_CLEAR

            rcall   TM1638_LEDS_BF  ; LEDs back and forth

        ELSEIF BUTTONS, S2

            clr     AKKU3           ; "LEDS DIM", Text block 0

            rcall   TM1638_PRINT_TXT8  

            FOR AKKU2 := #1         ; DIM LEDs 1x (or 2x)

                FOR COUNT := #7     ; step darker

                    mov     AKKU, COUNT

                    rcall   TM1638_BRIGHTNESS

                    rcall   Delay500ms

                ENDF

                REPEAT              ; step brighter again

                    mov     AKKU, COUNT

                    rcall   TM1638_BRIGHTNESS

                    rcall   Delay500ms

                    subi    COUNT,-1

                UNTIL COUNT > #7

            ENDF

            rcall   TM1638_LEDS_BF  ; LEDs back and forth

        ELSEIF BUTTONS, S3

            ldi     AKKU3, 1        ; Textblock "BINARY COUNTER"

            rcall   TM1638_PRINT_MOVETEXT

            clr     BUTTONS

            rcall   TM1638_COUNT_BIN

            rcall   Delay1s

            rcall   TM1638_LEDS_BF  ; LEDs back and forth

        ELSEIF BUTTONS, S4

            ldi     AKKU3, 2        ; Textblock "HEXACECIMAL COUNTER"

            rcall   TM1638_PRINT_MOVETEXT

            clr     BUTTONS

            rcall   TM1638_COUNT_HEX

            rcall   Delay1s

            rcall   TM1638_LEDS_BF  ; LEDs back and forth

        ELSEIF BUTTONS, S5

            ldi     AKKU3, 3        ; Textblock "DECIMAL COUNTER"

            rcall   TM1638_PRINT_MOVETEXT

            clr     BUTTONS

            rcall   TM1638_COUNT_DEC

            rcall   Delay1s

            rcall   TM1638_LEDS_BF  ; LEDs back and forth

        ELSEIF BUTTONS, S6

        ; S5 = take split time, can be repeated

        ; S6 = continue elapsed time

        ; S8 = exit split time or elapsed time and jump to SELECT loop

            ldi     AKKU3, 4        ; Textblock "ELAPSED TIME"

            rcall   TM1638_PRINT_MOVETEXT

            rcall   TM1638_CLEAR

            ldi     yl,low(clk10ms)         ; begin of clock values in SRAM

            ldi     yh,high(clk10ms)

            LOOP                            ; Elapsed time loop

                clr     BUTTONS

                REPEAT

                    rcall   TM1638_PRINT_TIME   ; update elapsed clock time

                    rcall   TM1638_KEYPAD       ; check the TM1638 buttons

                UNTIL BUTTONS <> #0             ; wait until any button pressed

                IF BUTTONS, S5                  ; take split time

                    ldi     AKKU,1

                    std     y+10,AKKU           ; mark split time

                    rcall   TM1638_CLEAR

                    LOOP

                        clr     BUTTONS

                        REPEAT

                            rcall   TM1638_PRINT_SPLIT  ; show split time

                            rcall   TM1638_KEYPAD   ; check the TM1638 buttons

                        UNTIL BUTTONS <> #0     ; wait until any button pressed

                        IF  BUTTONS, S5         ; take another split time shot

                            ldi     AKKU,1

                            std     y+10,AKKU   ; mark split time again

                        ENDI

                        EXITIF  BUTTONS, S6 ; back to elapsed time

                        EXITIF  BUTTONS, S8 ; leave elapsed time to SELECT

                    ENDL

                    EXITIF  BUTTONS, S6     ; back to elapsed time

                    EXITIF  BUTTONS, S8     ; leave elapsed time to SELECT

                ENDI

                EXITIF  BUTTONS, S8 ; leave elapsed time to SELECT

            ENDL

            rcall   TM1638_LEDS_BF  ; LEDs back and forth

        ELSEIF BUTTONS, S7          ; show the real-time clock until S8

        ; S3 = hour settings

        ; S4 = minute settings

        ; S5 = reset seconds, but only within hrs/min settings

        ; S1 = decrement hrs/min, can hold down for successive decrement

        ; S2 = increment hrs/min, can hold down for successive increment

        ; S7 = leave settings, but stay in the CLOCK loop and prevent S1/S2/S5

        ; S8 = exit clock time and jump to SELECT loop

            ldi     AKKU3, 5                ; Textblock "CLOCK TIME"

            rcall   TM1638_PRINT_MOVETEXT

            rcall   TM1638_CLEAR

            ldi     yl,low(clk10ms)         ; begin of clock values in SRAM

            ldi     yh,high(clk10ms)

            LOOP                                ; CLOCK loop

                clr     BUTTONS

                REPEAT

                    rcall   TM1638_PRINT_CLOCK  ; update clock time

                    rcall   TM1638_KEYPAD       ; check the TM1638 buttons

                UNTIL BUTTONS <> #0             ; wait until any button pressed

                IF BUTTONS, S3                  ; set hours

                    LOOP                        ; loop until S4, S7 or S8

                        clr     BUTTONS

                        REPEAT

                            rcall   TM1638_PRINT_CLOCK  ; update clock time

                            rcall   TM1638_KEYPAD   ; check the TM1638 buttons

                        UNTIL BUTTONS <> #0     ; wait until any button pressed

                        IF BUTTONS, S2          ; increment

                            ldd     AKKU,y+3    ; get hours

                            inc     AKKU

                            std     y+13,AKKU

                            IF AKKU > #23

                                clr AKKU

                                std y+13,AKKU   ; reset hrs

                            ENDI

                            ldd     AKKU,y+13

                            std     y+3,AKKU    ; restore hours

                        ELSEIF BUTTONS, S1      ; decrement

                            ldd     AKKU,y+3

                            subi    AKKU,1      ; (dec would not affect CY)

                            std     y+13,AKKU

                            IF C

                                ldi AKKU,23

                                std y+13,AKKU   ; roll over

                            ENDI

                            ldd     AKKU,y+13

                            std     y+3,AKKU    ; restore hours

                        ELSEIF BUTTONS, S5      ; reset seconds

                            ldi     AKKU,1

                            std     y+9,AKKU    ; mark reset seconds

                        ENDI

                        rcall   TM1638_PRINT_CLOCK  ; update clock time

                        EXITIF BUTTONS, S8      ; exit clock time

                        EXITIF BUTTONS, S7      ; exit clock settings

                        EXITIF BUTTONS, S4      ; to switch to minutes

                        rcall   delay500ms      ; for S1/S2 repeat cycle

                    ENDL           

                ELSEIF BUTTONS, S4              ; set minutes

                    LOOP                        ; loop until S3, S7 or S8

                        clr     BUTTONS

                        REPEAT

                            rcall   TM1638_PRINT_CLOCK  ; update clock time

                            rcall   TM1638_KEYPAD   ; check the TM1638 buttons

                        UNTIL BUTTONS <> #0     ; wait until any button pressed

                        IF BUTTONS, S2          ; increment

                            ldd     AKKU,y+2

                            inc     AKKU

                            std     y+12,AKKU

                            IF AKKU > #59

                                clr AKKU

                                std y+12,AKKU   ; reset min

                            ENDI

                            ldd     AKKU,y+12

                            std     y+2,AKKU    ; restore minutes

                        ELSEIF BUTTONS, S1      ; decrement

                            ldd     AKKU,y+2    ; min

                            subi    AKKU,1      ; (dec would not affect CY)

                            std     y+12,AKKU

                            IF C

                                ldi AKKU,59

                                std y+12,AKKU   ; roll over

                            ENDI

                            ldd     AKKU,y+12

                            std     y+2,AKKU    ; restore minutes

                        ELSEIF BUTTONS, S5      ; reset seconds

                            ldi     AKKU,1

                            std     y+9,AKKU    ; mark reset seconds

                        ENDI

                        rcall   TM1638_PRINT_CLOCK  ; update clock time

                        EXITIF BUTTONS, S8      ; exit clock time

                        EXITIF BUTTONS, S7      ; exit clock settings

                        EXITIF BUTTONS, S3      ; to switch to hours

                        rcall   delay500ms      ; for S1/S2 repeat cycle

                    ENDL

                ENDI

                EXITIF BUTTONS, S8              ; leave CLOCK

            ENDL

            EXITIF BUTTONS, S8                  ; leave CLOCK to SELECT

            rcall   TM1638_LEDS_BF              ; LEDs back and forth

        ENDI                                    ; end of selected loops

    ENDL

ENDL        ; END OF MAIN LOOP

 

;=======================================================================

;                           Subroutines

;=======================================================================

;

; LED chains back and forth

;

TM1638_LEDS_BF:

    rcall   TM1638_LEDS_L

    rcall   TM1638_LEDS_R

    ret

 

;=======================================================================

;

; LED chain to the right

;

TM1638_LEDS_R: 

    push    COUNT

    ldi TM1638_GRID_BYTE, 0x01      ; first LED address

    FOR COUNT := #8

        ldi TM1638_SEGM_BYTE,1      ; LED ON

        rcall   TM1638_SEND_DATA

        rcall   Delay100ms

        clr TM1638_SEGM_BYTE        ; LED OFF

        rcall   TM1638_SEND_DATA

        subi    TM1638_GRID_BYTE,-2 ; next LED address

    ENDF

    pop COUNT

    ret

;=======================================================================

;

; LED chain to the left

;

TM1638_LEDS_L: 

    push    COUNT

    ldi TM1638_GRID_BYTE, 0x0F      ; first LED address

    FOR COUNT := #8

        ldi     TM1638_SEGM_BYTE,1  ; LED ON

        rcall   TM1638_SEND_DATA

        rcall   Delay100ms

        clr     TM1638_SEGM_BYTE    ; LED OFF

        rcall   TM1638_SEND_DATA

        subi    TM1638_GRID_BYTE,2  ; next LED address

    ENDF

    pop     COUNT

    ret

 

;=======================================================================

;

; binary counter, 8 bit 0x00 through 0xff

;

TM1638_COUNT_BIN:

    push    AKKU

    clr AKKU

    REPEAT

        rcall   TM1638_PRINT_BIN    ; print value in AKKU

        rcall   Delay100ms

        rcall   TM1638_KEYPAD       ; check the TM1638 buttons

        EXITIF BUTTONS, S8          ; button S8 leaves counter demo

        inc     AKKU

    UNTIL AKKU == #0

    pop     AKKU

    ret

 

;=======================================================================

;

; hexadecimal counter, 16 bit AKKU2/AKKU, 0x0000 through 0xffff

;

TM1638_COUNT_HEX:

    push    AKKU

    push    AKKU2

    clr     AKKU

    clr     AKKU2

    REPEAT

        REPEAT

            rcall   TM1638_PRINT_HEX    ; print value

            IF AKKU <> #0xff

                rcall   Delay10ms       ; to prevent a delay during carry

            ENDI

            rcall   TM1638_KEYPAD       ; check the TM1638 buttons

            EXITIF BUTTONS, S8          ; button S8 leaves counter demo

            inc     AKKU

        UNTIL AKKU == #0                ; carry

        inc AKKU2

        EXITIF BUTTONS, S8              ; need 2nd button S8 test to leave

        rcall   TM1638_PRINT_HEX        ; print value

        rcall   Delay10ms

        ;EXITIF AKKU2 == #0x10          ; exit demo at 0x1000

    UNTIL AKKU2 == #0

    pop     AKKU2

    pop     AKKU

    ret

 

;=======================================================================

;

; decimal counter, 16 bit

;

TM1638_COUNT_DEC:

    ;cli

    push    AKKU

    push    AKKU2

    push    AKKU3

    push    XL

    push    XH

    clr     XL

    clr     XH

    REPEAT

        mov AKKU2, XL

        mov AKKU3, XH

        rcall   TM1638_PRINT_DEC    ; print values in AKKU2 and AKKU3

                                    ; as 16 bit number (LO and HI-Byte)

        rcall   Delay10ms

        ;EXITIF XH >= #8            ; stop at max 2048 for the demo

        rcall   TM1638_KEYPAD       ; check the TM1638 buttons

        EXITIF BUTTONS, S8          ; button S8 leaves counter demo

        adiw    XH:XL,1

    UNTIL Z                         ; maximum would be all 16 bits

    pop     XH

    pop     XL

    pop     AKKU3

    pop     AKKU2

    pop     AKKU

    ;sei

    ret

 

;=======================================================================

;

; twist arround CW from segment a through f

; EH: replaced inner REPEAT loop by a FOR loop

;

TM1638_TWIST_CW:

    push    AKKU

    push    COUNT

    ldi     AKKU, 1             ; start with segment a

    clr     TM1638_GRID_BYTE

    REPEAT

        FOR COUNT := #8

            mov     TM1638_SEGM_BYTE,AKKU      

            rcall   TM1638_SEND_DATA    ; activates only one LED

                                ; position is given by GRID_BYTE (digit)

                                ; and SEGM_BYTE (LED segment)

            subi    TM1638_GRID_BYTE,-2

        ENDF

        rcall   delay100ms

        clr     TM1638_GRID_BYTE

        rol     AKKU            ; next LED segment

    ;UNTIL AKKU == #0b01000000

    UNTIL AKKU,6                ; until segment g (not shown)

    pop     COUNT

    pop     AKKU

    ret

 

;=======================================================================

;

; twist arround CCW from segment f through a

; EH: replaced inner REPEAT loop by a FOR loop

;

TM1638_TWIST_CCW:

    push    AKKU

    push    COUNT

    ldi     AKKU, 0b00100000    ; start with segment f

    clr     TM1638_GRID_BYTE

    REPEAT

        FOR COUNT := #8

            mov     TM1638_SEGM_BYTE,AKKU      

            rcall   TM1638_SEND_DATA    ; activates only one LED

                                ; position is given by GRID_BYTE (digit)

                                ; and SEGM_BYTE (LED segment)

            subi    TM1638_GRID_BYTE,-2

        ENDF

        rcall   delay100ms

        clr     TM1638_GRID_BYTE

        ror     AKKU            ; next LED segment

    UNTIL C                     ; until shifted out

    pop     COUNT

    pop     AKKU

    ret

 

;=======================================================================

; TM1638_PRINT_TIME - elapsed time HH.MM.SS.MS is located in SRAM

; leading zero of HH is suppressed (replaced by space character)

; 8 LEDs used for overflow of 100s hours

; the right most digits show the 10ms read during reset

;

TM1638_PRINT_TIME:                  ; elapsed time

    push    AKKU2                   ; data from SRAM

    push    AKKU3                   ; digit position

    push    COUNT

    push    yl

    push    yh

    ldi     yl,low(cnthrs+2)        ; get HHH:MM:SS from SRAM

    ldi     yh,high(cnthrs+2)

    ld      AKKU2,-y                ; handle 100s of hours first

    ; ldi       AKKU2,3                 ; **** test only to show that it works ...

    ldi TM1638_GRID_BYTE, 0x01      ; address LED #8 (right most) = 1*100 hrs

    FOR COUNT := #8

        IF COUNT == AKKU2

            ldi TM1638_SEGM_BYTE,1  ; LED ON

        ELSE

            clr TM1638_SEGM_BYTE    ; LED OFF

        ENDI

        rcall   TM1638_SEND_DATA    ; set LED off/on

        subi    TM1638_GRID_BYTE,-2 ; next LED address

    ENDF

    mov     LEADZ, TRUE             ; prepare leading zero for 1st digit

    clr     AKKU3                   ; start at left most position

    FOR COUNT := #4

        ldi     TM1638_SEGM_BYTE,'0'; prepare AKKU = '0'

        ld      AKKU2,-y            ; get HH, MM, SS and 10 ms from SRAM

        REPEAT

            inc     TM1638_SEGM_BYTE

            subi    AKKU2, 10

        UNTIL C

        subi    AKKU2, -10

        dec     TM1638_SEGM_BYTE    ; correct the last inc

        IF LEADZ == TRUE            ; must be 1st position

            IF  TM1638_SEGM_BYTE == #'0'

                ldi     TM1638_SEGM_BYTE,' '

            ELSE

                clr     LEADZ           ; decimal place was 1-9

            ENDI

        ENDI

        mov     TM1638_GRID_BYTE,AKKU3

        rcall   TM1638_PRINT_CHAR

        clr     LEADZ                   ; no longer leading zeros

        subi    AKKU3,-2                ; next digit position

        ldi     TM1638_SEGM_BYTE,'0'    ; prepare AKKU = '0'

        add     TM1638_SEGM_BYTE,AKKU2  ; add remainder

        IF      AKKU3 <> #0x0e          ; not the last digit

            ori     TM1638_SEGM_BYTE,0x80   ; add DP to split digits

        ENDI

        mov     TM1638_GRID_BYTE,AKKU3

        rcall   TM1638_PRINT_CHAR

        subi    AKKU3,-2                ; next digit position

    ENDF

    pop     yh

    pop     yl

    pop     COUNT

    pop     AKKU3

    pop     AKKU2

    ret

 

;=======================================================================

; TM1638_PRINT_SPLIT - split time HH.MM.SS.MS is located in SRAM

; leading zero of HH is suppressed (replaced by space character),

; 8 LEDs used for overflow of 100s hours (from right to left),

; just the Y pointer is different from TM1638_PRINT_TIME

;

TM1638_PRINT_SPLIT:

    push    AKKU2                   ; data from SRAM

    push    AKKU3                   ; digit position

    push    COUNT

    push    yl

    push    yh

    ldi     yl,low(splhrs+2)        ; get HHH:MM:SS from SRAM

    ldi     yh,high(splhrs+2)

    ld      AKKU2,-y                ; handle 100s of hours first

    ldi TM1638_GRID_BYTE, 0x01      ; address LED #8 (right most) = 1*100 hrs

    FOR COUNT := #8

        IF COUNT == AKKU2

            ldi TM1638_SEGM_BYTE,1  ; LED ON

        ELSE

            clr TM1638_SEGM_BYTE    ; LED OFF

        ENDI

        rcall   TM1638_SEND_DATA    ; set LED off/on

        subi    TM1638_GRID_BYTE,-2 ; next LED address

    ENDF

    mov     LEADZ, TRUE             ; prepare leading zero for 1st digit

    clr     AKKU3                   ; start at left most position

    FOR COUNT := #4

        ldi     TM1638_SEGM_BYTE,'0'; prepare AKKU = '0'

        ld      AKKU2,-y            ; get HH, MM, SS and 10 ms from SRAM

        REPEAT

            inc     TM1638_SEGM_BYTE

            subi    AKKU2, 10

        UNTIL C

        subi    AKKU2, -10

        dec     TM1638_SEGM_BYTE    ; correct the last inc

        IF LEADZ == TRUE            ; must be 1st position

            IF  TM1638_SEGM_BYTE == #'0'

                ldi     TM1638_SEGM_BYTE,' '

            ELSE

                clr     LEADZ           ; decimal place was 1-9

            ENDI

        ENDI

        mov     TM1638_GRID_BYTE,AKKU3

        rcall   TM1638_PRINT_CHAR

        clr     LEADZ                   ; no longer leading zeros

        subi    AKKU3,-2                ; next digit position

        ldi     TM1638_SEGM_BYTE,'0'    ; prepare AKKU = '0'

        add     TM1638_SEGM_BYTE,AKKU2  ; add remainder

        IF      AKKU3 <> #0x0e          ; not the last digit

            ori     TM1638_SEGM_BYTE,0x80   ; add DP to split digits

        ENDI

        mov     TM1638_GRID_BYTE,AKKU3

        rcall   TM1638_PRINT_CHAR

        subi    AKKU3,-2                ; next digit position

    ENDF

    pop     yh

    pop     yl

    pop     COUNT

    pop     AKKU3

    pop     AKKU2

    ret

;=======================================================================

; TM1638_PRINT_CLOCK - clock time HH:MM:SS is located in SRAM

; leading zero of HH is suppressed

; (similar to TM1638_PRINT_TIME)

;

TM1638_PRINT_CLOCK:

    push    AKKU2                   ; data from SRAM

    push    AKKU3                   ; digit position

    push    COUNT

    push    yl

    push    yh

    ldi     yl,low(clkhrs+1)        ; get HH:MM:SS from SRAM

    ldi     yh,high(clkhrs+1)

    mov     LEADZ, TRUE             ; prepare leading zero for 1st digit

    clr     AKKU3                   ; start at left most position

    FOR COUNT := #3

        ldi     TM1638_SEGM_BYTE,'0'; prepare di9git = '0'

        ld      AKKU2,-y            ; get HH, MM and SS from SRAM

        REPEAT

            inc     TM1638_SEGM_BYTE

            subi    AKKU2, 10

        UNTIL C

        subi    AKKU2, -10

        dec     TM1638_SEGM_BYTE    ; correct the last inc

        IF LEADZ == TRUE            ; must be 1st position

            IF  TM1638_SEGM_BYTE == #'0'

                ldi     TM1638_SEGM_BYTE,' '

            ELSE

                clr     LEADZ           ; decimal place was 1-9

            ENDI

        ENDI

        mov     TM1638_GRID_BYTE,AKKU3

        rcall   TM1638_PRINT_CHAR

        clr     LEADZ                   ; no longer leading zeros

        subi    AKKU3,-2                ; next digit position

        ldi     TM1638_SEGM_BYTE,'0'    ; prepare digit = '0'

        add     TM1638_SEGM_BYTE,AKKU2  ; add remainder

        mov     TM1638_GRID_BYTE,AKKU3

        rcall   TM1638_PRINT_CHAR

        subi    AKKU3,-2                ; next digit position

        EXITIF AKKU3 > #0x0e            ; all positions done

        ldi     TM1638_SEGM_BYTE,'-'    ; print separator

        mov     TM1638_GRID_BYTE,AKKU3

        rcall   TM1638_PRINT_CHAR

        subi    AKKU3,-2                ; next digit position

    ENDF

    pop     yh

    pop     yl

    pop     COUNT

    pop     AKKU3

    pop     AKKU2

    ret

 

;=======================================================================

; other subroutines and TM1638 character font:

 

; TM1638 library, compiled from "tm1638cc.inc_EH.s" using label prefix _I:

.INCLUDE "tm1638cc.inc_EH.asm"

 

; delay subroutines, compiled from "tm1638cc_delay_EH.s", label prefix _D:

.INCLUDE "tm1638cc_delay_EH.asm"

 

; interrupt based timer, compiled from "tm1638cc_timer.s", label prefix _T:

.INCLUDE "tm1638cc_timer_EH.asm"

 

; NOTE: in general all included .asm files being generated by s'AVR

; must use DIFFERENT label prefixes (could be any from _A through _Z)

 

.INCLUDE "tm1638cc_font.inc"                ; TM1638 character font

 

;=======================================================================

; constant text:

 

MOVETEXT:                                   ; 35+1 characters each

.db "            TM1638 DEMO            ",0 ; TEXT_BLOCK 0

.db "          BINARY COUNTER           ",0 ; TEXT_BLOCK 1

.db "       HEXADECIMAL COUNTER         ",0 ; TEXT_BLOCK 2

.db "         DECIMAL COUNTER           ",0 ; TEXT_BLOCK 3

.db "       ELAPSED TIME        ",0,0,0,0,0,0,0,0,0     ; TEXT BLOCK 4

.db "       CLOCK TIME        ",0,0,0,0,0,0,0,0,0,0,0   ; TEXT BLOCK 5

 

TEXT10:             ; 8+2 characters each

.db "LEDS DIM",0,0  ; TEXT10, Block 0

.db "88888888",0,0  ; TEXT10, Block 1, showing all 7 segments w/o DP

.db "(-88.88)",0,0  ; TEXT10, Block 2, showing extra characters ( - . )

.db "SELECT..",0,0  ; TEXT10, Block 3, select demo by button

.db "TEST KEY",0,0  ; TEXT10, Block 4, test keys

 

.DSEG

 

.ORG    SRAM_START  ; 0x0100

 

; keep the next 2x 4 bytes together (being addressed by YH:YL)

 

clk10ms:    .db 0       ; 0 count 10ms clock time

clksec:     .db 0       ; 1 clock seconds

clkmin:     .db 0       ; 2 clock minutes

clkhrs:     .db 0       ; 3 clock hours

 

cnt10ms:    .db 0       ; 4 count 10ms elapsed time

cntsec:     .db 0       ; 5 count seconds

cntmin:     .db 0       ; 6 count minutes

cnthrs:     .db 0       ; 7 count hours

cnthrsh:    .db 0       ; 8 count 100s of hrs, shown by LEDs 1 through 8

 

rstsec:     .db 0       ; 9 = 1 indicates that seconds should be reset

split:      .db 0       ; 10 = 1 indicates to take split time

spare1:     .db 0       ; 11 spare

setmin:     .db 0       ; 12 used to set minutes

sethrs:     .db 0       ; 13 used to set hours

 

spl10ms:    .db 0       ; 14 store 10ms split time

splsec:     .db 0       ; 15 store seconds

splmin:     .db 0       ; 16 store minutes

splhrs:     .db 0       ; 17 store hours

splhrsh:    .db 0       ; 18 store 100s of hrs, shown by LEDs 1 through 8

spare2:     .db 0       ; 19 spare

 

.EXIT