Pfad: Home => AVR-DE => Anwendungen => RGB-Dünne-Berg-Uhr m16 => Assembler-Quellcode
RGB-Anzeige 15:39:13 AVR-Anwendungen

RGB-Dünne-Berg-Uhr mit ATmega16
Software für die RGB-BCD-Uhr
Logo

Assembler-Quellcode für die RGB-Dünne-Berg-Uhr

Der Original-Quellcode im Assembler-Format ist hier.

;
; ***********************************
; * RGB-Duenne-Berg-Uhr ATmega16    *
; * Version 1.0 Januar 2019         *
; * (C)2019 by avr-asm-tutorial.net *
; ***********************************
;
.nolist
.include "m16adef.inc" ; Define device ATmega16A
.list
;
; *************************************
;  D E B U G G I N G   S W I T C H E S
; *************************************
;
; Accelerate watch by a factor
.equ cAccel = 1 ; Acceleration of clock, 1..1000
;    (should be 1 in final version)
;
.equ Yes = 1 ; Yes for all switches
.equ No = 0 ; No for all switches
;
; Light all LEDs in all colors one by one in the rows:
;   1. blue - green - red for delay seconds each
;   2. ones, twos, fours, eights, tens, twenties, fourties
;   3. seconds - minutes - hours
.equ dbg_leds = No ; Should be no in final version
.equ dbg_leds_delay = 10 ; On-Time in 50 ms multiples
;
; Debug the ADC: Set hours to MSB result
.equ dbg_adc = No ; Should be no in final version
;
; Debug the keys:
;   Leds dark if no key pressed
;   Set hour tens red on key 1
;   Set hour twenties on key 2
;   (Disables all normal operation!)
.equ dbg_key = No
;
; Debug the color balance:
;   Lights all three LEDs around and around
;   (Disables all normal operation!)
.equ dbg_colbal = No
;
; Monitoring of registers during input phase
.equ dbg_moni_flags = No ; Monitor the flags
.equ dbg_moni_bounce = No ; Monitor the bounce counter
;
;
; **********************************
;        H A R D W A R E
; **********************************
;
; Device: ATmega16A, Package: 40-pin-PDIP
;           __________
;        1 /          |40
;   AH o--|PB0     PA0|--o POT
;   AM o--|PB1     PA1|--o NC
;   AS o--|PB2     PA2|--o NC
;   K1 o--|PB3     PA3|--o C0B
;   K2 o--|PB4     PA4|--o C0G
; MOSI o--|PB5     PA5|--o C0R
; MISO o--|PB6     PA6|--o C1B
;  SCK o--|PB7     PA7|--o C1G
;  RES o--|RESET  AREF|--o AREF
;  +5V o--|VCC     GND|--o 0V
;   0V o--|GND    AVCC|--o AVCC
; 4MHz o--|XTAL2   PC7|--o C4B
; XTAL o--|XTAL1   PC6|--o C3R
;  C4G o--|PD0     PC5|--o C3G
;  C4R o--|PD1     PC4|--o C3B
;  C5B o--|PD2     PC3|--o C2R
;  C5G o--|PD3     PC2|--o C2G
;  C5R o--|PD4     PC1|--o C2B
;  C6B o--|PD5     PC0|--o C1R
;  C6G o--|PD6     PD7|--o C6R
;       20|___________|21
;
;
; **********************************
;  P O R T S   A N D   P I N S
; **********************************
;
.equ pRgbC1O = PORTA ; RGB1 Cathode Output port
.equ pRgbC1D = DDRA ; RGB1 Cathode Direction port
.equ bRgbC1M = 0xF8 ; RGB1 Cathode Output Mask
.equ pRgbC2O = PORTC ; RGB2 Cathode Output port
.equ pRgbC2D = DDRC ; RGB2 Cathode Direction port
.equ pRgbC2M = 0xFF ; RGB2 Cathode Output Mask
.equ pRgbC3O = PORTD ; RGB3 Cathode Output port
.equ pRgbC3D = DDRD ; RGB3 Cathode Direction port
.equ pRgbC3M = 0xFF ; RGB3 Cathode Output Mask
.equ pRgbAO = PORTB ; RGB Anode Output port
.equ pRgbAD = DDRB ; RGB Anode Direction port
.equ pRgbAM = 0x07 ; RGB Anode Mask
.equ pKeyI = PINB ; Key input port
.equ bKey1 = PINB3 ; First key
.equ bKey2 = PINB4 ; Second key
;
; ******************************************
;   A D J U S T A B L E   C O N S T A N T S
; ******************************************
;
.equ clock=4000000 ; Define clock frequency
;
; Constants for color composition
.equ bBlue = 0 ; Blue led bit
.equ bGreen = 1 ; Green led bit
.equ bRed = 2 ; Red led bit
;
; Colors for the four quarters
.equ cColor1 = 255-(1<<bBlue) ; Color quarter 1
.equ cColor2 = 255-(1<<bGreen) ; Color quarter 2
.equ cColor3 = 255-(1<<bRed) ; Color quarter 3
.equ cColor4 = 255-((1<<bRed)|(1<<bBlue)) ; Color quarter 4
; Error checking of colors
.if ((cColor1&0x07)==0)||((cColor2&0x07)==0)||((cColor3&0x07)==0)||((cColor4&0x07)==0)
  .error "One of the colors has three color bits at zero!"
  .endif
;
; Start time of watch: time to be set at start-up
.equ starthour = 20 ; Start at 20 hours
.equ startminute = 0 ; Start at zero minute
.equ startsecond = 0 ; Start at zero seconds
;
; When key input active: blink hour/minute/second
.equ BlinkPeriod = 85 ; 85% on, 15% off
;
; Key input bouncing parameter
.equ BouncePeriod = 50 ; Debouncing period for keys in ms
;
; Input active time-out
.equ InputTimeOutMinutes = 5 ; Time in minutes to skip input period
.if InputTimeOutMinutes > 7
  .error "Input time-out minutes too large!"
  .endif
;
; ****************************************************
;  F I X E D  &  D E R I V I V E D  C O N S T A N T S
; ****************************************************
;
; Clock signals for second increase and MUX
;   Clock > Presc > CTC > SecDiv > Seconds
;   4 MHz    1     16000     250
.equ cTc1Presc = 1 ; TC1 Prescaler
.equ cTc1Clk = clock / cTc1Presc ; Frequency TC1
.equ cTc1CompA = 15999 ; Int for Mux
.equ cSecDiv = cTc1Clk/(cTc1CompA+1) ; TC0 Second divider
;
; Switch leds off after blink period
.equ cBlinkOff = ((100-BlinkPeriod)*cSecDiv+50) / 100 ; Second divider
;
; ADC constants
.equ cAdcCnt = 64 ; Sum up 64 ADC results
.equ cAdcPs = 32 ; ADC prescaler
.equ cAdcN = 13 ; Number of cycles
.equ cAdcTime = (cAdcCnt*cAdcPs*cAdcN*1000)/clock ; Time in ms
.equ cInpTO = 65536-(clock/cAdcCnt/cAdcPs/cAdcN)*60*InputTimeOutMinutes
.if cInpTO < 0
  .error "Input time-out too long!"
  .endif
.equ cBounce = (BouncePeriod+cAdcTime/2)/cAdcTime+1 ; Bounce counter
;
; **********************************
;       R E G I S T E R S
; **********************************
;
; used: R2:R1:R0 for binary conversion to color
.def rInpToL = R3 ; Time out input, LSB
.def rInpToH = R4 ; dto., MSB
.def rHrInp = R5 ; Input hour
  .equ sInput = 5
.def rMinInp = R6 ; Input minute
.def rSecInp = R7 ; Input second
.def rCmp = R8 ; Compare value for conversion
.def rConvCnt = R9 ; Counter for time conversion
.def rAdcRes = R10 ; MSB of ADC sum
.def rAdcL = R11 ; ADC sum, LSB
.def rAdcH = R12 ; dto., MSB
.def rAdcCnt = R13 ; ADC counter
.def rSecDiv = R14 ; Seconds divider
.def rSreg = R15 ; Save/Restore status port
.def rmp = R16 ; Define multipurpose register
.def rimp = R17 ; Multipurpose inside ints
;  Flags for flow control
.def rFlag = R18 ; Flag register
  ; Those four bits control key input
  ;   OSM_ = xxx0 = Normal operation, no time setting, no monitoring
  ;        = 0001 = Time setting hours, monitoring = Led one green
  ;        = 0011 = dto., minutes, monitoring = Led two blue
  ;        = 0111 = dto., seconds, monitoring = Led four green
  ;        = 1xx1 = dto., end time setting, monitoring = Leds eight/ten/twenty
  .equ bSetA = 0 ; Key flag, for hour setting
  .equ bSetM = 1 ; Flag for minute setting
  .equ bSetS = 2 ; Flag for second setting
  .equ bSetO = 3 ; Flag for end of time setting
  ; bBlink set when bSetA=1 and rSecDiv cycle reaches switching value
  .equ bBlink = 4 ; Switch active leds off
  ; bNoUpd set when bBlink is set, cleared at second start
  .equ bNoUpd = 5 ; Do not update during off-period
  ; Set by TC1A-ISR when a second is over
  .equ bSec = 6 ; Flag second over
  ; Set by ADC-Complete ISR when 64 measurements completed
  .equ bAdc = 7 ; ADC flag
.def rHr = R19 ; Time hours
  .equ sTime = 19 ; Pointer to time info for displaying time
.def rMin = R20 ; Time minutes
.def rSec = R21 ; Time seconds
.def rCol = R22 ; Color
.def rColCop = R23 ; Copy of rCol
.def rBcd = R24 ; BCD coded time
.def rBounce = R25 ; Debouncing counter for key inputs
; used: R27:R26 = X for conversion to cathode bits outside ints
; used: R29:R28 = Y for pointer for multiplexing cycle
; used: R31:R30 = Z for diverse purposes outside ints
;
; **********************************
;           S R A M
; **********************************
;
.dseg
.org SRAM_START
;
; MUX buffer
sRgb:
.byte 4 ; Four bytes: RGBC1, RGBC2, RGBC3,AGBA, Hours
.byte 4 ; Four bytes: RGBC1, RGBC2, RGBC3,AGBA, Minutes
.byte 4 ; Four bytes: RGBC1, RGBC2, RGBC3,AGBA, Seconds
sRgbEnd:
;
; **********************************
;           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
	nop
	reti ; INT0, unused
	nop
	reti ; INT1, unused
	nop
	reti ; OC2, unused
	nop
	reti ; OVF2, unused
	nop
	reti ; ICP1, unused
	nop
	rjmp Oc1AIsr ; OC1A, MUX and second counting
	nop
	rjmp Oc1BIsr ; OC1B, anode driver off for dimming
	nop
	reti ; OVF1, unused
	nop
	reti ; OVF0, unused
	nop
	reti ; SPI, unused
	nop
	reti ; URXC, unused
	nop
	reti ; UDRE, unused
	nop
	reti ; UTXC, unused
	nop
	rjmp AdccIsr ; ADCC, ADC cycle
	nop
	reti ; ERDY, unused
	nop
	reti ; ACI, unused
	nop
	reti ; TWI, unused
	nop
	reti ; INT2, unused
	nop
	reti ; OC0, unused
	nop
	reti ; SPMR, unused
	nop
;
; *****************************************
;  I N T - S E R V I C E   R O U T I N E S
; *****************************************
;
; TC1 Compare Match A Interrupt Service Routine
Oc1AIsr:
  in rSreg,SREG ; Save SREG
  dec rSecDiv ; Decrease second divider
  brne Oc1AIsr1 ; Not zero, perform MUX
  ldi rimp,cSecDiv ; Restart seconds divider
  mov rSecDiv,rimp
  sbr rFlag,1<<bSec ; Set seconds flag
  cbr rFlag,1<<bNoUpd ; Updates on
Oc1AIsr1:
  ldi rimp,0x1F ; Clear anode drivers
  out pRgbAO,rimp
  ld rimp,Y+ ; Read first cathodes
  out pRgbC1O,rimp ; Write first RGB port
  ld rimp,Y+ ; Read second cathodes
  out pRgbC2O,rimp ; Write second RGB port
  ld rimp,Y+ ; Read third cathodes
  out pRgbC3O,rimp ; Write third RGB port
  ld rimp,Y+ ; Read anodes
  out pRgbAO,rimp ; Write anode
  cpi YL,sRgbEnd ; End of buffer?
  brne Oc1AIsr2 ; No
  ldi YH,High(sRgb) ; Restart Mux
  ldi YL,Low(sRgb)
Oc1AIsr2:
  sbrs rFlag,bSetA ; Key input active?
  rjmp Oc1AIsr3 ; No
  ldi rimp,cBlinkOff ; Seconds divider reached off?
  cp rimp,rSecDiv ; Blink cycle reached
  brne Oc1AIsr3 ; No, skip flag setting
  sbr rFlag,(1<<bBlink)|(1<<bNoUpd) ; Set blink flag to turn input off
Oc1AIsr3:
  out SREG,rSreg ; Restore SREG
  reti
;
; OC1B Interrupt Service Routine
;   switches anode driver off for dimming
Oc1BIsr:
  ldi rimp,0b00011111 ; Anode driver bits to one
  out pRgbAO,rimp ; in anode driver port
  reti
;
; ADC Conversion Complete Interrupt Service Routine
;   sums up 64 results, if complete: copy MSB, clear sum, set flag
;   restart ADC conversion
AdccIsr:
  in rSreg,SREG ; Save SREG
  in rimp,ADCL ; Read ADC result LSB
  add rAdcL,rimp ; add to sum LSB
  in rimp,ADCH ; Read MSB
  adc rAdcH,rimp ; add to MSB
  dec rAdcCnt ; Decrease counter
  brne AdccIsr1 ; Not zero, restart ADC
  mov rAdcRes,rAdcH ; Copy MSB result
  clr rAdcL ; Restart sum LSB
  clr rAdcH ; dto., MSB
  ldi rimp,cAdcCnt ; Restart counter
  mov rAdcCnt,rimp ; in counter register
  sbr rFlag,1<<bAdc ; Set ADC flag
AdccIsr1:
  ; Restart ADC
  ldi rimp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS0)
  out ADCSRA,rimp ; in ADC control port
  out SREG,rSreg ; Restore SREG
  reti
;
; **********************************
;  M A I N   P R O G R A M   I N I T
; **********************************
;
Main:
	ldi rmp,High(RAMEND) ; End of SRAM, MSB
	out SPH,rmp ; Init MSB stack pointer
	ldi rmp,Low(RAMEND) ; End of SRAM, LSB
	out SPL,rmp ; Init LSB stack pointer
  ; Init SRAM MUX buffer
  ldi XH,High(sRgb) ; Point to SRAM buffer, MSB
  ldi XL,Low(sRgb) ; dto., LSB
Main1:
  ldi rmp,0b11111000 ; First buffer byte
  st X+,rmp ; Cathodes 1 off
  ldi rmp,0xFF ; all others FF
  st X+,rmp ; Cathodes 2 off
  st X+,rmp ; Cathodes 3 off
  adiw XL,1 ; Jump over anode byte
  cpi XL,Low(sRgbEnd) ; End of buffer?
  brne Main1 ; No, go on
  ldi rmp,0b00011110 ; Anode driver hours
  sts sRgb+3,rmp ; Hour anode active
  ldi rmp,0b00011101 ; Anode driver miinutes
  sts sRgb+7,rmp ; Minute anode active
  ldi rmp,0b00011011 ; Anode driver seconds
  sts sRgb+11,rmp ; Second anode active
  ; Init the I/O ports
  ldi rmp,pRgbAM|(1<<bKey1)|(1<<bKey2) ; RGB Anode Mask plus key pull-ups
  out pRgbAO,rmp ; RGB Anode Output port
  ldi rmp,pRgbAM ; RGB Anode Mask
  out pRgbAD,rmp ; RGB Anode Direction port
  ldi rmp,bRgbC1M ; RGB1 Cathode Output Mask
  out pRgbC1O,rmp ; RGB1 Cathode Output port
  out pRgbC1D,rmp ; RGB1 Cathode Direction port
  ldi rmp,pRgbC2M ; RGB2 Cathode Output Mask
  out pRgbC2O,rmp ; RGB2 Cathode Output port
  out pRgbC2D,rmp ; RGB2 Cathode Direction port
  ldi rmp,pRgbC3M ; RGB3 Cathode Output Mask
  out pRgbC3O,rmp ; RGB3 Cathode Output port
  out pRgbC3D,rmp ; RGB3 Cathode Direction port
;
; *************************************
;  H A R D W A R E   D E B U G G I N G
; *************************************
;
; Routines for hardware debugging
;   Those do not perform normal counting but
;   end in indefinite loops!
.if dbg_key == Yes
  ; Debug the attached keys
  ;   Set hour tens red if key 1 pressed
  ;   Set hour twenties red if key 2 pressed
	  ldi rmp,0b00011110 ; Anode hours on
	  out pRgbAO,rmp 
	dbg_key_loop:
	  sbic pKeyI,bKey1 ; Skip if key 1 low
	  sbi pRgbC3O,PORTD1 ; Red LED off
	  sbis pKeyI,bKey1 ; Skip if key 1 high
	  cbi pRgbC3O,PORTD1 ; Red LED on
	  sbic pKeyI,bKey2 ; Skip if key 2 low
	  sbi pRgbC3O,PORTD4 ; Red LED off
	  sbis pKeyI,bKey2 ; Skip if key 2 high
	  cbi pRgbC3O,PORTD4 ; Red Led on
	  rjmp dbg_key_loop ; Repeat on and on again
  .endif
.if dbg_colbal == Yes
  ; Debug the color balance of all leds
  ;   Switch all leds to white one by one
  ;   and fastly change to the next led
  ;   Colors should be clean white, but
  ;   only 1/20th brightness
  ColBal_loop:
    ldi rMin,0xFF ; Start with upper leds off
    ldi rHr,0xFF
  ColBal_loop1:
    ldi rBcd,0b00011011 ; Start anodes with seconds
  ColBal_loop2:
    ldi rSec,0b11000000 ; Start with seconds ones
    ldi rmp,20 ; 20 leds to cycle
  ColBal_loop3:
    out pRgbC1O,rSec ; Set cathodes, seconds
    out pRgbC2O,rMin ; dto., minutes
    out pRgbC3O,rHr ; dto., hours
    out pRgbAO,rBcd ; Set anode driver
    ori rSec,0b00000111 ; Set all three lower bits
    lsl rSec ; Shift to next led, seconds
    rol rMin ; dto., minutes
    rol rHr ; dto., hours
    lsl rSec ; and to overnext led
    rol rMin
    rol rHr
    lsl rSec ; and to third led
    rol rMin
    rol rHr
    dec rmp
    brne ColBal_loop3 ; Continue led out and shift
    ori rBcd,0b00100000 ; Set next key to one
    lsr rBcd ; Next anode
    brcs ColBal_loop2 ; Not at the end
    rjmp ColBal_loop1 ; Restart all new
  .endif
.if dbg_leds == Yes
  ; Debug the leds: Set the leds
  ;   a) blue-green-red,
  ;   b) ones, twos, fours, eights, tens, twentys, fourtys
  ;   c) seconds, minutes, hours 
  Led_loop1:
    ldi rMin,0xFF ; Upper leds off
    ldi rHr,0xFF
    ldi rBcd,0b00011011 ; Start anodes seconds
  Led_loop2:
    ldi rSec,0b11110000 ; Start with seconds ones
    ldi rmp,21 ; 21 leds to cycle
    sbrs rBcd,0 ; Hour cycle?
    ldi rmp,18 ; 18 leds only
  Led_loop3:
    out pRgbC1O,rSec ; Set cathodes, second
    out pRgbC2O,rMin ; dto., minute
    out pRgbC3O,rHr ; dto., hour
    out pRgbAO,rBcd ; Set anode driver
    ldi rCol,dbg_leds_delay ; Multiple 50 ms delay
  Led_loop4:
    ldi ZH,High((5*clock)/400) ; Delay loop 50 ms, MSB
    ldi ZL,Low((5*clock)/400) ; dto., LSB
  Led_loop5:
    sbiw ZL,1 ; Count down, 2 clock cycles
    brne Led_loop5 ; 2 clock cycles for branching
    ; 4 clock cycles = 1 us @4 MHz
    ; 50.000 us per loop
    dec rCol ; Count delay down
    brne Led_loop4 ; Next delay cycle
    ori rSec,0b00000100 ; Set blue cathode led 0 off
    lsl rSec ; Next cathode, second
    rol rMin ; Next cathode, minute
    rol rHr ; Next cathode, hour
    dec rmp ; Downcount led
    brne Led_loop3 ; Next led output
    lsr rBcd ; Next anode
    brcs Led_loop2 ; Restart with first led
    rjmp Led_loop1 ; Restart at the beginning
  .endif
; *****************************************
;  C O N T I N U E   N O R M A L   I N I T
; *****************************************
  ; Init the start time of the watch
  ldi rHr,starthour
  ldi rMin,startminute
  ldi rSec,startsecond
  ; Init the ADC
  ldi rmp,1<<REFS0 ; VREF=AVCC, ADC channel 0
  out ADMUX,rmp ; to MUX port
  clr rAdcL ; Restart sum LSB
  clr rAdcH ; dto., MSB
  ldi rmp,cAdcCnt ; Restart counter
  mov rAdcCnt,rmp
  ; Start the ADC: Int Enable, clock prescaler = 32
  ldi rmp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS0)
  out ADCSRA,rmp ; in ADC control port
  ; Init TC1 as MUX/second timer/anode driver off
  ldi rmp,High(cTC1CompA/cAccel) ; CTC compare value, MSB
  out OCR1AH,rmp ; to compare port MSB
  ldi rmp,Low(cTC1CompA/cAccel) ; dto., LSB
  out OCR1AL,rmp ; dto., LSB
  clr rmp ; Switch LEDs to lowest brightness
  out OCR1BH,rmp ; MSB
  out OCR1BL,rmp ; LSB
  ldi rmp,0 ; WGM10 and WGM11 to 0
  out TCCR1A,rmp
  ldi rmp,(1<<WGM12)|(1<<CS10) ; CTC on compare A, Prescaler=1
  out TCCR1B,rmp ; Start TC1
  ldi rmp,(1<<OCIE1A)|(1<<OCIE1B) ; Enable compare match interrupts
  out TIMSK,rmp ; in timer interrupt mask
  ; Init flags
  clr rFlag ; All flags off
  ; Init sleep
  ldi rmp,1<<SE ; Enable sleep idle
  out MCUCR,rmp ; in master control port
	sei ; Enable interrupts
;
; **********************************
;    P R O G R A M   L O O P
; **********************************
;
Loop:
  sleep ; Go to sleep
  nop ; Dummy for wake-up
  sbrc rFlag,bSec ; Second flag set?
  rcall Second ; Perform second increase
  sbrc rFlag,bAdc ; ADC conversion sum complete?
  rcall AdcRdy ; Perform ADC service
  sbrc rFlag,bBlink ; Off-period reached?
  rcall Blink ; Switch leds off
  rjmp Loop
;
; *********************************************
;  T I M E   I N C R E A S E  &  D I S P L A Y
; *********************************************
;
Second:
  cbr rFlag,1<<bSec ; clear flag
  ; Increase time by one second
  inc rSec ; Increase seconds
  cpi rSec,60 ; End of minute?
  brcs DisplayTimeInp ; No, output time
  clr rSec ; Restart second
  inc rMin ; Next minute
  cpi rMin,60 ; End of hour?
  brcs DisplayTimeInp ; No, output time
  clr rMin ; Restart minute
  inc rHr ; Next hour
  cpi rHr,24 ; End of day?
  brcs DisplayTimeInp ; No, output time
  clr rHr ; Restart hour
DisplayTimeInp:
  ; Display current time or the input time?
  ldi ZH,High(sTime) ; Point to time hours
  ldi ZL,Low(sTime)
  ; Output input time instead?
  sbrs rFlag,bSetA ; Key input active?
  rjmp Convert ; No, display current time
DisplayInput:
  ldi ZH,High(sInput) ; Output input time, MSB
  ldi ZL,Low(sInput) ; dto., LSB
;
; Convert time/input to display
Convert:
  ldi XH,High(sRgb) ; Point X to SRAM buffer, MSB
  ldi XL,Low(sRgb) ; dto., LSB
  ldi rmp,3 ; Three bytes to convert
  mov rConvCnt,rmp ; Set convert counter
  ldi rmp,24/4 ; Comparer for hours
  mov rCmp,rmp ; To compare register
ReadDateTime:
  ld rmp,Z ; Read the next data byte time/input
  ldi rCol,cColor1 ; Set color for quarter 1
  cp rmp,rCmp ; Compare with first quarter value
  brcs ToBcd ; Smaller, convert to BCD
  ldi rCol,cColor2 ; Set color for quarter 2
  lsl rCmp ; Compare value * 2
  cp rmp,rCmp ; Compare with second quarter value
  brcs ToBcd ; Smaller, convert to BCD
  ldi rCol,cColor3 ; Set color for quarter 3
  mov R0,rCmp ; Copy compare value
  lsr R0 ; Divide by two
  add rCmp,R0 ; Add to compare value, 3/4
  cp rmp,rCmp ; Compare with third quarter value
  brcs ToBcd ; Smaller, convert to BCD
  ldi rCol,cColor4 ; Set color for quarter 4
ToBcd:
  ldi rmp,60/4 ; Set compare value for minutes/seconds to 15
  mov rCmp,rmp ; in compare register
  ; Read and convert value to BCD in rBcd
  ld rmp,Z+ ; Read time/input byte again, point to next
  ldi rBcd,-0x10 ; Tens to minus 1
ToBcd1:
  subi rBcd,-0x10 ; Add tens
  subi rmp,10 ; Subtract 10 from value
  brcc ToBcd1 ; No carry, continue adding tens and subtracting
  subi rmp,-10 ; Add ten to restore last subtraction
  or rBcd,rmp ; Add the ones to the tens
ToRgb:
  ldi rmp,7 ; Seven times three colors
  clr R0 ; Clear buffer, byte 1
  clr R1 ; dto., byte 2
  clr R2 ; dto., byte 3
ToRgb1:
  ldi rColCop,0x07 ; Color all ones = leds of
  lsr rBcd ; Shift next BCD bit to carry
  brcc ToRgb2 ; Bit is zero, led off
  mov rColCop,rCol ; Bit is one, led to color
ToRgb2:
  ; Shift the three color bits into the buffer
  lsr rColCop ; Shift first color bit to carry
  ror R2 ; and into buffer from high to low
  ror R1
  ror R0
  lsr rColCop ; Shift second color bit to carry
  ror R2 ; and into buffer from high to low
  ror R1
  ror R0
  lsr rColCop ; Shift third color bit to carry
  ror R2 ; and into buffer from high to low
  ror R1
  ror R0
  dec rmp ; Count led down
  brne ToRgb1 ; Next led
  st X+,R0 ; Store buffer in SRAM for mux display, byte 1
  st X+,R1 ; dto., byte 2
  st X+,R2 ; dto., byte 3
  adiw XL,1 ; jump over anode byte
  dec rConvCnt ; Decrease counter
  brne ReadDateTime ; Read and convert next byte
  ret ; Conversion done
;
; ****************************************
;  A D C   C Y C L E   C O M P L E T E D
; ****************************************
;
; Perform reaction on ADC sum complete
AdcRdy:
  cbr rFlag,1<<bAdc ; Clear the ADC flag
  .if dbg_adc == Yes
    ; Display ADC result as 0..23 on hour position
    ldi rmp,24 ; Convert to hour
	  rcall Multiply
	  mov rHr,ZH ; Write to hour
	  ldi ZH,High(sTime) ; Point Z to actual time, MSB
	  ldi ZL,Low(sTime) ; dto., LSB
	  rcall Convert ; Display the current time
	  .endif
  sbrc rFlag,bSetA ; No time setting active?
  rjmp AdcDebounce ; No, check debounce
  ; Input inactive, set dim value and check key 1 pressed
  ldi rmp,250 ; Multiply ADC MSB by 250
  rcall Multiply
  lsr ZH ; Divide by 2, MSB
  ror ZL ; dto., LSB
  lsr ZH ; Divide by 4, MSB
  ror ZL ; dto., LSB
  out OCR1BH,ZH ; Set compare B port in TC1, MSB
  out OCR1BL,ZL ; dto., LSB
  sbic pKeyI,bKey1 ; Key 1 pressed?
  rjmp AdcRdyRet ; No
  sbr rFlag,1<<bSetA ; Set Set flag
  cbr rFlag,(1<<bSetS)|(1<<bSetM)|(1<<bSetO) ; Clear the other flags
  mov rSecInp,rSec ; Copy seconds
  mov rMinInp,rMin ; Copy minutes
  rjmp AdcSetHour ; Set hour to ADC MSB result and debounce
AdcDebounce:
  tst rBounce ; Bouncing period ended?
  breq AdcOFlag ; Yes, check O flag set
  sbis pKeyI,bKey1 ; Key 1 active?
  rjmp AdcRestartBounce ; Yes, restart bounce counter
  sbis pKeyI,bKey2 ; Key 2 active?
  rjmp AdcRestartBounce ; Yes, restart bounce counter
  dec rBounce ; Decrease debounce counter
  rjmp AdcRdyRet ; Done
AdcOFlag:
  sbrs rFlag,bSetO ; O flag set?
  rjmp AdcKey1 ; No, check key 1 pressed
  cbr rFlag,1<<bSetA ; Clear time set flag
  rjmp DisplayTimeInp
AdcKey1:
  sbic pKeyI,bKey1 ; Key 1 pressed?
  rjmp AdcKey2 ; No, check key 2
  sbrs rFlag,bSetS ; S flag set?
  rjmp AdcKey1M ; No, check M flag
  cbr rFlag,1<<bSetS ; Clear S flag
  ldi rmp,60 ; Multiply by 60
  rcall Multiply
  mov rMinInp,ZH ; Set minutes
  mov rSecInp,ZH ; and set seconds
  rjmp AdcRestartBounce
AdcKey1M:
  sbrs rFlag,bSetM ; M flag set?
  rjmp AdcSetO ; No, set O flag, leave input mode
  cbr rFlag,1<<bSetM ; Clear M flag
  ldi rmp,60 ; Multiply by 60
  rcall Multiply
  mov rMinInp,ZH ; Set minutes input
  rjmp AdcSetHour ; and set hour
AdcKey2:
  sbic pKeyI,bKey2 ; Key 2 pressed?
  rjmp AdcTimeOut ; No, check input change
  sbrs rFlag,bSetS ; S flag set?
  rjmp AdcKey2M ; No, check M flag
  ldi rmp,60 ; Multiply by 60
  rcall Multiply
  ldi rmp,cSecDiv ; Restart second divider for a full second
  mov rSecDiv,rmp ; Seconds divider to restart = restart second
  cbr rFlag,1<<bSec ; Clear second flag if currently set
  mov rSec,ZH ; Set seconds
  mov rMin,rMinInp ; Copy input minutes to time minutes
  mov rHr,rHrInp ; Copy input hours to time hours
  rjmp AdcSetO ; Set O flag to leave input mode
AdcKey2M:
  sbrs rFlag,bSetM ; M flag set?
  rjmp AdcKey2H ; No, check hour flag
  sbr rFlag,1<<bSetS ; Set S flag
  ldi rmp,60 ; Multiply ADC MSB by 60
  rcall Multiply
  mov rMinInp,ZH ; Set minute
  mov rSecInp,ZH ; Set second
  rjmp AdcRestartBounce ; Restart bounce counter
AdcKey2H:
  sbr rFlag,1<<bSetM ; Set minute flag
  cbr rFlag,1<<bSetS ; Clear second flag
  ldi rmp,60 ; Multiply ADC MSB by 60
  rcall Multiply
  mov rMinInp,ZH ; Set minute
  rjmp AdcSetHour ; and hour
AdcTimeOut:
  inc rInpToL ; Check time-out, LSB
  brne AdcNoKey ; Not zero
  inc rInpToH ; dto., inc MSB
  brne AdcNoKey ; Not zero
  ; Time-out input period
  cbr rFlag,1<<bSetA ; Clear TSet flag
  rjmp DisplayTimeInp ; Display time
AdcNoKey:
  sbrc rFlag,bNoUpd ; No uddate flag set?
  rjmp AdcRdyRet ; Yes, do not update
  ldi XH,High(sInput) ; Point X to hour input, MSB
  ldi XL,Low(sInput) ; dto., LSB
  ldi rmp,24 ; Convert MSB ADC to hours
  rcall Multiply
  sbrs rFlag,bSetM ; M flag set?
  rjmp AdcNoKey1 ; No, check change
  adiw XL,1 ; Next position
  ldi rmp,60 ; Convert MSB ADC to minutes/seconds
  rcall Multiply
  sbrc rFlag,bSetS ; S flag clear?
  adiw XL,1 ; No, increase address
AdcNoKey1:
  ld rmp,X ; Read current value at position
  cp ZH,rmp ; Compare with new value
  breq AdcRdyRet ; Not changed, do nothing
  st X,ZH ; Store changed value
  rjmp DisplayInput
AdcSetHour:
  ldi rmp,24 ; Multiply MSB ADC by 24
  rcall Multiply
  mov rHrInp,ZH
  rjmp AdcRestartBounce
AdcSetO:
  sbr rFlag,1<<bSetO ; Set O flag
AdcRestartBounce:
  ldi rmp,High(cInpTO)
  mov rInpToH,rmp
  ldi rmp,Low(cInpTO)
  mov rInpToL,rmp
  ldi rBounce,cBounce
AdcRdyRet:
.if dbg_moni_flags == Yes
  mov rSecInp,rFlag ; Copy rFlag to seconds input
  rcall DisplayTimeInp ; and display
  .endif
.if dbg_moni_bounce == Yes
  mov rSecInp,rBounce ; Copy bounce to seconds input
  rcall DisplayTimeInp
  .endif
  ret
;
; Multiply MSB of last ADC result by rmp
;   MSB Result in ZH
;   rmp is multiplicator
Multiply:
  mov R0,rAdcRes ; Copy MSB ADC result to R0
  clr R1 ; Clear MSB multiplier
  clr ZL ; Clear multiplication result in Z, LSB
  clr ZH ; dto., MSB
Multiply1:
  tst rmp ; Ready multiplying?
  breq Multiply3 ; Yes
  lsr rmp ; Next bit
  brcc Multiply2 ; Not one, skip adding
  add ZL,R0 ; Add multiplicator, LSB
  adc ZH,R1 ; dto., MSB
 Multiply2:
  lsl R0 ; Multiplicator * 2, LSB
  rol R1 ; dto., MSB
  rjmp Multiply1 ; Continue multiplication
Multiply3:
  ret
;
; Blink active input leds off
Blink:
  cbr rFlag,1<<bBlink ; Clear flag
  sbrs rFlag,bSetS ; Seconds active?
  rjmp Blink1
  clr rSecInp ; Seconds to zero
  rjmp DisplayTimeInp ; and display
Blink1:
  sbrs rFlag,bSetM ; Minutes active?
  rjmp Blink2
  clr rMinInp ; Minutes to zero
  rjmp DisplayTimeInp
Blink2:
  clr rHrInp ; Hours to zero
  rjmp DisplayTimeInp
;
; End of source code
;



Lob, Tadel, Fehlermeldungen, Genöle und Geschimpfe oder Spam bitte über das Kommentarformular an mich.

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