Path:AVR-EN => Applications => double dice tn24 => Assembler source code
Double dice tn24 Application of
AVR-Single-Chip-Controller AT90S, ATtiny, ATmega and ATxmega
Double dice with ATtiny24 and 7-segment display
Assembler source code

Logo

Assembler source code for the double dice with ATtiny24

Link to .asm source code file

;
; ***********************************
; * Double dice with ATtiny24/44/84 *
; * Counts dice events in EEPROM    *
; * Version 1 as of December 2017   *
; * http://www.avr-asm-tutorial.net *
; ***********************************
;
.equ device = 24 ; can be 24, 44 or 84
;
.nolist
.if device == 84
    .include "tn84adef.inc" ; Define device ATtiny84A
    .endif
.if device == 44
    .include "tn44adef.inc" ; Define device ATtiny44A
    .endif
.if device == 24
    .include "tn24adef.inc" ; Define device ATtiny24A
    .endif
.list
;
; **************************************
;   Debug switches, inactive state = 0
; **************************************
;
; Debugging of the dice routine to test
.equ debug_dice = 0 ; one for jump to debug dice routine
.equ test_dice1 = 5 ; Test value dice 1, 0 to 5
.equ test_dice2 = 5 ; Test value dice 2, 0 to 5
.equ count_preload = 65535 ; Counter preloading, 0 to 16,777,215
;
; Disable debouncing for faster simulation
.equ NoDebouncing = 0 ; 1 disables debouncing
;
; **********************************
;        H A R D W A R E
; **********************************
;              _______
;           1 /       |14
;      VCC o-|VCC  GND|-o GND
;           2|        |13
;   digit2 o-|PB0  PA0|-o Segm a
;           3|        |12
;   digit1 o-|PB1  PA1|-o Segm b
;           4|        |11
;    RESET o-|RES  PA2|-o Segm c
;           5|        |10
;      KEY o-|INT0 PA3|-o Segm d
;           6|        |9
;   Segm p o-|PA7  PA4|-o Segm e
;           7|        |8
;   Segm g o-|PA6  PA5|-o Segm f
;            |________|
;
;
; **********************************
;  P O R T S   A N D   P I N S
; **********************************
;
.equ pCathO = PORTA
.equ pCathD = DDRA
.equ pMuxO  = PORTB
.equ pMuxD  = DDRB
.equ bMux2  = PORTB0
.equ bMux1  = PORTB1
.equ pKeyO  = PORTB
.equ pKeyD  = DDRB
.equ pKeyI  = PINB
.equ bKey   = PORTB2
;
; **********************************
;   A D J U S T A B L E   C O N S T
; **********************************
;
.equ clock=1000000 ; Define clock frequency
.if NoDebouncing == 1
  .equ cDebounceTime = 0
  .else
  .equ cDebounceTime = 300 ; in ms
  .endif
.equ cBlankTime = 10 ; Time until display off
;
; **********************************
;  F I X  &  D E R I V.  C O N S T
; **********************************
; 8-bit TC0 counter as MUX driver in CTC mode
.equ cTc0prescaler = 64
.equ cTc0divider = 128
.equ fmux = clock / cTc0prescaler / cTc0divider ; = 122 Hz
;
; 16-bit TC1 counter as dice counter in CTC mode
.equ cTc1prescaler = 8
.equ cTc1divider = 133
.equ cDice2 = clock / cTc1prescaler /cTc1divider ; = 939 Hz
.equ cDebounce = cDebounceTime / 8 ; = 12
;
; 16-bit counter for blanking display
.equ cBlank = cBlankTime * cDice2
;
; **********************************
;       R E G I S T E R S
; **********************************
;
.def rNmbr1 = R0 ; used for dicing
.def rNmbr2 = R1 ; used for dicing
.def rComb = R2 ; combined dices
.def rEep = R3 ; Number of bytes to write to EEP
; free: R4 to R13
.def rDebc = R14 ; debounce key
.def rSreg = R15 ; Save/Restore status port
.def rmp = R16 ; Define multipurpose register
.def rimp = R17 ; Multipurpose inside interrupts
.def rMux1 = R18 ; Multiplex digit 1
.def rMux2 = R19 ; Multiplex digit 2
.def rDice1 = R20 ; Dice counter 1
.def rDice2 = R21 ; Dice counter 2
; free: R22 to R23
.def rBlankL = R24 ; LSB blank counter
.def rBlankH = R25 ; dto., MSB
; used: R27:R26 = X pointer for EEPROM write
; free: R29:R28 = Y 
; used: R31:R30 = Z for LPM instructions
;
; **********************************
;           S R A M
; **********************************
;
.dseg
.org SRAM_START
sCounterBegin:
    .byte 6*6*3
sCounterEnd:
;
.if sCounterBegin != SRAM_START
    .error "sCounterBegin has to be at SRAM_START"
    .endif
;
; **********************************
;         C O D E
; **********************************
;
.cseg
.org 000000
;
; **********************************
; R E S E T  &  I N T - V E C T O R S
; **********************************
	rjmp Main ; Reset vector
	rjmp Int0Isr ; EXT_INT0
	reti ; PCI0
	reti ; PCI1
	reti ; WATCHDOG
	reti ; ICP1
	rjmp OC1AIsr ; OC1A
	reti ; OC1B
	reti ; OVF1
	rjmp OC0AIsr ; OC0A
	reti ; OC0B
	reti ; OVF0
	reti ; ACI
	reti ; ADCC
	rjmp EERdyIsr ; ERDY
	reti ; USI_STR
	reti ; USI_OVF
;
; **********************************
;  I N T - S E R V I C E   R O U T .
; **********************************
;
; External interrupt 0:
;   Start dicing if debounce counter = 0
Int0Isr:
     in rSreg,SREG ; save SREG
     tst rDebc ; debounce counter at zero?
     brne Int0Isr1 ; no, ignore signal
     sbis pKeyI,bKey ; skip on rising edges
     set ; set T flag
     ldi rimp,cDebounce ; start debounce
     mov rDebc,rimp
     reti ; return from int
Int0Isr1:
     sbr rMux1,0x80 ; decimal point dice 1 off
     out SREG,rSreg ; restore SREG
     reti ; return from int
;
; Compare match int TC1:
;    Increase dice 2, blanking function
OC1AIsr:
     in rSreg,SREG ; save SREG
     inc rDice2    ; increase dice 2
     cpi rDice2,6  ; reached 6?
     brcs OC1AIsr1 ; yes, skip next
     clr rDice2     ; restart at 0
OC1AIsr1:
     sbiw rBlankL,1 ; decrease blank counter
     brne OC1AIsr2 ; not zero
     ldi rimp,0xFF ; turn digit 1 off
     mov rMux1,rimp ; blank digit 1
     ldi rimp,0x7F ; turn decimal point on
     mov rMux2,rimp ; blank digit 2
OC1AIsr2:
     out SREG,rSreg ; restore SREG
     reti          ; return from int
;
; Compare match int TC0:
;    MUX output toggle and dice 1
OC0AIsr:
     in rSreg,SREG ; save SREG
     sbic pMuxO,bMux2 ; Skip if Mux=2
     rjmp OC0AIsr1 ; Go to Mux=1
     sbi pMuxO,bMux2 ; Disable Mux2
     out pCathO,rMux1 ; Cathodes to digit 1
     cbi pMuxO,bMux1 ; Enable Mux1
     rjmp OC0AIsr2
OC0AIsr1:
     sbi pMuxO,bMux1 ; Disable Mux1
     out pCathO,rMux2 ; Cathodes to digit 2
     cbi pMuxO,bMux2 ; Enable Mux2
OC0AIsr2:
     inc rDice1 ; next dice 1
     cpi rDice1,6 ; end reached?
     brcs OC0AIsr3
     clr rDice1 ; restart
OC0AIsr3:
     tst rDebc ; Debounce at zero?
     breq OC0AIsr4 ; yes
     dec rDebc
OC0AIsr4:
     out SREG,rSreg
     reti
;
; EEPROM write operations
;
EeRdyIsr:
     in rSreg,SREG ; save SREG
     dec rEep ; count bytes to write down
     brne EeRdyIsr1 ; go on writing
     cbi EECR,EERIE ; clear int enable bit
     out SREG,rSreg ; restore SREG
     reti ; return from interrupt
EeRdyIsr1:
     ld rimp,-X ; read next byte from SRAM
     out EEDR,rimp
     mov rimp,XL ; read LSB address
     subi rimp,SRAM_START
     out EEARL,rimp ; write LSB address
.if device == 84
     ldi rimp,0 ; write MSB address
     out EEARH,rimp
     .endif
     sbi EECR, EEMPE ; set master write enable
     sbi EECR, EEPE ; set write enable
     out SREG,rSreg ; restore SREG
     reti ; return from interrupt
;
; **********************************
;  M A I N   P R O G R A M   I N I T
; **********************************
;
Main:
     ldi rmp,Low(RAMEND)
     out SPL,rmp ; Init LSB stack pointer
.if device == 84 ; ATtiny84: two byte address
     ldi rmp,High(RAMEND)
     out SPH,rmp ; Init MSB stack pointer
     .endif
     ; Init anode driver port
     sbi pMuxO,bMux1 ; output pin Mux1 to 1
     sbi pMuxO,bMux2 ; output pin Mux2 to 1
     sbi pMuxD,bMux1 ; pin Mux1 as output
     sbi pMuxD,bMux2 ; pin Mux2 as output
     ; Init display segment port
     ldi rmp,0xFF ; Display segments
     out pCathO,rmp ; all bits to 1
     out pCathD,rmp ; all bits output
     ; Init display test
     ldi rmp,0x00 ; all segments on
     mov rMux1,rmp ; to display mux digit 1
     mov rMux2,rmp ; to display mux digit 2
     ldi rBlankH,High(3*cDice2) ; wait 3 seconds
     ldi rBlankL,Low(3*cDice2)
     ; Init key input
     cbi pKeyD,bKey ; key input pin as input
     sbi pKeyO,bKey ; internal pull-up on
     ; Read EEPROM content to SRAM
     rcall ReadEep
.if debug_dice == 1
     ldi rDice1,test_dice1
     ldi rDice2,test_dice2
     ldi XH,HIGH(sCounterBegin+18*test_dice1+3*test_dice2)
     ldi XL,LOW(sCounterBegin+18*test_dice1+3*test_dice2)
     ldi rmp,Byte1(count_preload)
     st X+,rmp
     ldi rmp,Byte2(count_preload)
     st X+,rmp
     ldi rmp,Byte3(count_preload)
     st X+,rmp
     rcall dice
     .endif
     ; Init timer 1 as CTC counter
     ldi rmp,High(cTc1Divider-1) ; CTC compare match A
     out OCR1AH,rmp
     ldi rmp,Low(cTc1Divider-1)
     out OCR1AL,rmp
     clr rmp ; Init mode TC1
     out TCCR1A,rmp
     ldi rmp,(1<<WGM12)|(1<<CS11) ; Prescaler=8, CTC-A
     out TCCR1B,rmp
     ldi rmp,1<<OCIE1A ; Compare match interrupt
     out TIMSK1,rmp
     ; Init timer 0 as CTC counter
     ldi rmp,cTc0Divider-1 ; Compare match A
     out OCR0A,rmp
     ldi rmp,1<<WGM01 ; CTC-A mode
     out TCCR0A,rmp
     ldi rmp,(1<<CS01)|(1<<CS00) ; Prescaler = 64
     out TCCR0B,rmp
     ldi rmp,1<<OCIE0A ; Compare match interrupt
     out TIMSK0,rmp
     ; Init sleep and INT0
     ldi rmp,(1<<SE)|(1<<ISC00) ; Sleep mode idle, INT0 on both edges
     out MCUCR,rmp
     ldi rmp,1<<INT0 ; enable INT0 interrupt
     out GIMSK,rmp
     ; Interrupts
     sei ; Enable interrupts
;
; **********************************
;    P R O G R A M   L O O P
; **********************************
;
Loop:
     sleep ; stop execution until int wakes up
     nop ; dummy after wakeup
     brtc Loop ; T flag is clear, go to sleep
     rcall Dice ; roll a dice
     rjmp loop ; go to sleep again
;
; Dice a combination of two numbers,
;   increase count and start write
;   to EEPROM
Dice:
     clt ; clear T flag
     ldi rBlankH,High(cBlank) ; start blank delay
     ldi rBlankL,Low(cBlank)
     mov rNmbr1,rDice1 ; copy current counters
     mov rNmbr2,rDice2
     mov rmp,rNmbr1 ; convert to 7-segment
     rcall To7Seg ; number 1 to 7-segment
     mov rMux1,rmp ; and write to display 1
     cbr rMux1,0x80 ; Decimal point dice 1 on
     mov rmp,rNmbr2 ; convert to 7-segment
     rcall To7Seg ; number 2 to 7-segment
     mov rMux2,rmp ; and write to display 2
     mov rComb,rNmbr1 ; copy number 1
     lsl rComb ; multiply by 2
     lsl rComb ; multiply by 4
     add rComb,rNmbr1 ; multiply by 5
     add rComb,rNmbr1 ; multiply by 6
     add rComb,rNmbr2 ; add number 2
     mov rmp,rComb ; multiply by 1
     lsl rmp ; multiply by 2
     add rmp,rComb ; multiply by 3
     ldi XH,HIGH(sCounterBegin)
     ldi XL,LOW(sCounterBegin)
     add XL,rmp ; add displacement to LSB
     ldi rmp,0
     adc XH,rmp ; add carry to MSB
     clr rEep ; zero EEPROM bytes
 Dice1:
     inc rEep ; increase number of EEPROM bytes
     ld rmp,X ; read byte from SRAM
     inc rmp
     st X+,rmp ; write back to SRAM
     breq Dice1 ; repeat if zero
 Dice2:
     sbic EECR,EERIE ; wait until EERIE is clear
     rjmp Dice2
     ld rmp,-X ; read previous byte from SRAM
     out EEDR,rmp ; write to data register
     mov rmp,XL ; SRAM address to rmp
     subi rmp,SRAM_START ; subtract address
     out EEARL,rmp ; write LSB address to EEPROM
 .if device == 84
     ldi rmp,0 ; Clear MSB EEPROM address
     out EEARH,rmp
     .endif
     cli ; disable interrupts
     sbi EECR, EEMPE ; set master write enable
     sbi EECR, EEPE ; set write enable
     sei ; enable interrupts
     sbi EECR,EERIE ; enable EE complete interrupts
     ret
;
; **********************************
;    S E V E N - S E G M E N T
; **********************************
;
; Convert rmp to 7-segment in rmp
;   Uses Z
To7Seg:
     ldi ZH,HIGH(2*SegmTable)
     ldi ZL,LOW(2*SegmTable)
     add ZL,rmp ; add rmp to table address
     ldi rmp,0 ; add carry
     adc ZH,rmp
     lpm rmp,Z ; read table entry to rmp
     ret
;
; Seven-Segment table
;   The segment is on if the bit is 0
;   and the anode driver bit is 0
;   __a
; f| g|b       __   __        __   __
;  |--|    |   __|  __| |__| |__  |__
; e|__|c   |  |__   __|    |  __| |__|
;    d
;     pgfedcba
; 0 = 11000000 ; inverted!
; 1 = 11111001
; 2 = 10100100
; 3 = 10110000
; 4 = 10011001
; 5 = 10010010
; 6 = 10000010
;
SegmTable:
.db 0b11111001,0b10100100 ; 1, 2
.db 0b10110000,0b10011001 ; 3, 4
.db 0b10010010,0b10000010 ; 5, 6
SegmTableEnd:
;
; ***********************************
;    E E P R O M - C O N T E N T
; ***********************************
; Each dice combination between 11 and 66
; has a three byte counter that counts
; how often this combination has been
; diced.
; The EEPROM content is read to SRAM on
; restart. Dicing increases the respective
; SRAM counter and writes 1, 2 or 3 bytes
; back to the EEPROM.
;
.eseg
.org 0x0000
EsegBegin:
    .db 0,0,0,0,0,0 ; counter dice combinations 11 + 12
    .db 0,0,0,0,0,0 ; 13 + 14
    .db 0,0,0,0,0,0 ; 15 + 16
    .db 0,0,0,0,0,0 ; 21 + 22
    .db 0,0,0,0,0,0 ; 23 + 24
    .db 0,0,0,0,0,0 ; 25 + 26
    .db 0,0,0,0,0,0 ; 31 + 32
    .db 0,0,0,0,0,0 ; 33 + 34
    .db 0,0,0,0,0,0 ; 35 + 36
    .db 0,0,0,0,0,0 ; 41 + 42
    .db 0,0,0,0,0,0 ; 43 + 44
    .db 0,0,0,0,0,0 ; 45 + 46
    .db 0,0,0,0,0,0 ; 51 + 52
    .db 0,0,0,0,0,0 ; 53 + 54
    .db 0,0,0,0,0,0 ; 55 + 56
    .db 0,0,0,0,0,0 ; 61 + 62
    .db 0,0,0,0,0,0 ; 63 + 64
    .db 0,0,0,0,0,0 ; 65 + 66
EsegEnd:
;
; Read EEPROM content to SRAM
;
.cseg
ReadEep:
    ldi XH,0 ; X points to EEPROM start
    ldi XL,0
    ldi ZH,HIGH(sCounterBegin) ; Z points to SRAM
    ldi ZL,Low(sCounterBegin)
.if device == 84
    out EEARH,XH ; MSB address to EEPROM
    .endif
ReadEep1:
    out EEARL,XL ; LSB address to EEPROM
    sbi EECR,EERE ; EEPROM read strobe
    in rmp,EEDR ; read byte
    st Z+,rmp ; store in SRAM
    adiw XL,1 ; increase address
    cpi ZL,sCounterEnd ; all read?
    brcs ReadEep1 ; no, go on
    ret ; done, return
;
; End of EEPROM
;
; End of source code



Praise, dispraise, error reports, criticaster, scolding and unqualified spam please via the comments page to me.

©2017 by http://www.avr-asm-tutorial.net