Pfad: Home => AVR-Übersicht => Anwendungen => DCF77-Empfänger => DCF Display => Assembler Quellcode
DCF77-Empfang Anwendungen von
AVR-Einchip-Prozessoren AT90S, ATtiny, ATmega und ATxmega
Assembler Quellcode DCF77 Anzeige
Logo

6.4 Assembler-Quellcode für die DCF77-Anzeige mit ATtiny24

Dies ist die Software für die DCF77-Anzeige mit dem ATtiny24. Der Assembler-Quellcode ist hier im asm-Format.

;
; ***********************************
; * DCF77 watch ATtiny24 Version 4  *
; * (C)2019 by avr-asm-tutorial.net *
; ***********************************
;
.nolist
.include "tn24def.inc" ; Define device ATtiny24
.list
;
; **********************************
;  D E B U G G I N G   S W I T C H
; **********************************
;
.equ No = 0 ; Answers
.equ Yes = 1
;
; Debug the display routine
.equ Debug_display = No ; 0=No debugging, 1=debugging only
.if Debug_display == Yes
  .equ Debug_displayH = 'm' ; The High parameter
  .equ Debug_displayL = 59 ; The Low parameter
  .endif
;
; **********************************
;        H A R D W A R E
; **********************************
;
; Works with an tiny24-lcd experimental board
;   as described under
;   http://www.avr-asm-tutorial.net/avr_en/apps/tn24_lcd/tn24_lcd.html
;   and one of the DCF77 receivers as decribed under
;   http://www.avr-asm-tutorial.net/avr_en/apps/dcf77_rcvr/dcf77_rcvr.html
; Connects with a tn45/85 DCF decoder, receives serial
;   data from the tn45/85, decodes and displays it on
;   the LCD
;
; Device: ATtiny24, Package: 14-pin-PDIP_SOIC
;
;              _________
;           1 /         |14
;   + 5 V o--|VCC    GND|--o 0 V
;  LCD-RS o--|PB0    PA0|--o Serial Clock DCF RX
; LCD-R/W o--|PB1    PA1|--o Serial Data DCF RX
;   RESET o--|RESET  PA2|--o NC
;   LCD-E o--|PB2    PA3|--o NC
;  LCD-D7 o--|PA7    PA4|--o LCD-D4
;  LCD-D6 o--|PA6    PA5|--o LCD-D5
;          7 |__________|8
;
;
; **********************************
;  P O R T S   A N D   P I N S
; **********************************
;
; Serial signal input ports and pins
.equ pSerialClkO = PORTA ; Serial Clk output port
.equ pSerialClkD = DDRA ; Serial Clk direction port
.equ pSerialClkI = PINA ; Serial Clk input port
.equ bSerialClkO = PORTA0 ; Serial Clk output pin
.equ bSerialClkD = DDA0 ; Serial Clk direction pin
.equ bSerialClkI = PINA0 ; Serial Clk input pin
.equ pSerialDataO = PORTA ; Serial Data output port
.equ pSerialDataD = DDRA ; Serial Data direction port
.equ pSerialDataI = PINA ; Serial Data input port
.equ bSerialDataO = PORTA1 ; Serial Data output pin
.equ bSerialDataD = DDA1 ; Serial Data direction pin
.equ bSerialDataI = PINA1 ; Serial Data input pin
;
; *************************************
;  L C D . I N C   P A R A M E T E R S
; *************************************
;
.equ clock = 1000000 ; Clock frequency of controller in Hz
; LCD size:
  .equ LcdLines = 4 ; Number of lines (1, 2, 4)
  .equ LcdCols = 20 ; Number of characters per line (8..24)
; LCD bus interface
  .equ LcdBits = 4 ; Bus size (4 or 8)
  ; If 4 bit bus:
    .equ Lcd4High = 1 ; Bus nibble (1=Upper, 0=Lower)
  .equ LcdWait = 0 ; Access mode (0 with busy, 1 with delay loops)
; LCD data ports
  .equ pLcdDO = PORTA ; Data output port
  .equ pLcdDD = DDRA ; Data direction port
; LCD control ports und pins
  .equ pLcdCEO = PORTB ; Control E output port
  .equ bLcdCEO = PORTB2 ; Control E output portpin
  .equ pLcdCED = DDRB ; Control E direction port
  .equ bLcdCED = DDB2 ; Control E direction portpin
  .equ pLcdCRSO = PORTB ; Control RS output port
  .equ bLcdCRSO = PORTB0 ; Control RS output portpin
  .equ pLcdCRSD = DDRB ; Control RS direction port
  .equ bLcdCRSD = DDB0 ; Control RS direction portpin
; If LcdWait = 0:
  .equ pLcdDI = PINA ; Data input port
  .equ pLcdCRWO = PORTB ; Control RW output port
  .equ bLcdCRWO = PORTB1 ; Control RW output portpin
  .equ pLcdCRWD = DDRB ; Control RW direction port
  .equ bLcdCRWD = DDB1 ; Control RW direction portpin
; If you need binary to decimal conversion:
  .equ LcdDecimal = 1 ; If defined: include those routines
; If you need binary to hexadecimal conversion:
  .equ LcdHex = 1 ; If defined: include those routines
; If simulation in the SRAM is desired:
  ;.equ avr_sim = 1 ; 1=Simulate, 0 or undefined=Do not simulate
;
; **********************************
;   A D J U S T A B L E   C O N S T
; **********************************
;
; Serial time-out
;   - previous received bits ignored
;   - restarting serial collection process
.equ cSerialTOSelected = 5000 ; Serial timeout, in us
;
; Weekday display language
.equ cLangEn = No ; No=German, Yes=English
;
; **********************************
;  F I X  &  D E R I V.  C O N S T
; **********************************
;
; TC0 as seconds clock
.equ cPrescTc0 = 8 ; TC0 prescaler value
.equ cDividerTc0 = 125 ; TC0 CTC divider
.equ cTc0FreqInt = clock/cPrescTc0/cDividerTc0 ; TC0 int frequency
.equ cSec = cTc0FreqInt ; Counter for seconds
;
; TC0 as timeout counter for serial signal
.equ cSerialKBaud = 10 ; Baud rate of serial signal
.equ cSerialTimeBitus = 1000000/16/(cSerialKBaud*1000)*(clock/1000000) ; Time per bit, us
.equ cSerialTimeWordus = 16*cSerialTimeBitus
.equ cSerialTOFreq = 1000000/cSerialTOSelected ; in Hz
.equ cSerialTO = cTc0FreqInt/cSerialTOFreq ; TO Counter value
;
; **********************************
;       R E G I S T E R S
; **********************************
;
; free: R0 to R11
.def rDcfBits = R12 ; The last eight bit received
.def rSerialL = R13 ; Serial bits received, LSB
.def rSerialH = R14 ; dto., MSB
.def rSreg = R15 ; Save/Restore status port
.def rmp = R16 ; Define multipurpose register
.def rimp = R17 ; Multipurpose in interrupts
.def rFlag = R18 ; Flags
  .equ bSec = 0 ; One second is over
  .equ bRxIn = 1 ; 16 bits received
.def rSerialBits = R19 ; Received serial bits
.def rSerialTO = R20 ; Serial time-out counter
.def rRxL = R21 ; Received byte LSB
.def rRxH = R22 ; dto., MSB
; free: R23
.def rSecL = R24 ; 16-bit downcounter seconds, LSB
.def rSecH = R25 ; dto., MSB
; free: R26 to R29
; used: R31:R30 = Z for LCD operations
;
; **********************************
;           S R A M
; **********************************
;
.dseg
.org SRAM_START
; Date and time set
sTime:
  sTimeWd:
    .byte 1
  sTimeDay:
    .byte 1
  sTimeMonth:
    .byte 1
  sTimeYear:
    .byte 1
  sTimeHour:
    .byte 1
  sTimeMinute:
    .byte 1
  sTimeSecond:
    .byte 1
  sTimeEnd:

; TimeTable constants
.equ cTimeWd = 0
.equ cTimeDay = 1
.equ cTimeMonth = 2
.equ cTimeYear = 3
.equ cTimeHour = 4
.equ cTimeMinute = 5
.equ cTimeSecond = 6
.equ cTimeNone = 255

;
; **********************************
;         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
	reti ; EXT_INT0
	rjmp Pci0Isr ; PCI0, serial clock pin
	reti ; PCI1
	reti ; WATCHDOG
	reti ; ICP1
	reti ; OC1A
	reti ; OC1B
	reti ; OVF1
	rjmp Ocr0aIsr ; OC0A, seconds counter
	reti ; OC0B
	reti ; OVF0
	reti ; ACI
	reti ; ADCC
	reti ; ERDY
	reti ; USI_STR
	reti ; USI_OVF
;
; **********************************
;  I N T - S E R V I C E   R O U T .
; **********************************
;
; PCINT0 Interrupt service routine
Pci0Isr: ; 7 clock cycles for int and vector jump
  sbis pSerialClkI,bSerialClkI ; Is clock high?  +1/2=8/9
  reti ; No, skip, +4=12
  ; Clock input is high, collect data bit, 9 cycles
  in rSreg,SREG ; Save SREG, +1=10
  clc ; Clear carry, bit = 0, +1=11
  sbic pSerialDataI,bSerialDataI ; Is data low?, +1/2=12/13
  sec ; No, high bit received, +1 = 13
  rol rSerialL ; Roll into received bits, LSB, +1=14
  rol rSerialH ; and into MSB, +1=15
  dec rSerialBits ; Down-count bits, +1=16
  brne Pci0Isr1 ; Not zero, continue, +1/2=17/18
  mov rRxL,rSerialL ; Copy received bits, LSB, +1=18
  mov rRxH,rSerialH ; dto., MSB, +1=19
  ldi rSerialBits,16 ; Restart counter, +1=20
  sbr rFlag,1<<bRxIn ; Set received flag, +1=21
Pci0Isr1: ; 18/21 cycles
  ldi rSerialTO,cSerialTO ; Restart time out, +1=19/22
  out SREG,rSreg ; Restore SREG, +1=20/23
  reti ; +4=24/27
;
; OCR0A Interrupt, seconds counting and serial time-out
Ocr0aIsr:
  in rSreg,SREG ; Save SREG
  sbiw rSecL,1 ; Down-count seconds counter
  brne Ocr0aIsr1 ; Not zero, skip this section
  ldi rSecH,High(cSec) ; Restart counter, MSB
  ldi rSecL,Low(cSec) ; dto., LSB
  sbr rFlag,1<<bSec ; Set seconds flag
Ocr0aIsr1:
  dec rSerialTO ; Time-out counter
  brne Ocr0aIsr2
  ldi rSerialTO,cSerialTO ; Restart counter
  ldi rSerialBits,16 ; Restart bit counter
Ocr0aIsr2:
  out SREG,rSreg ; Restore SREG
  reti
;
; **********************************
;  M A I N   P R O G R A M   I N I T
; **********************************
;
Main:
.ifdef SPH
  ldi rmp,High(RAMEND)
  out SPH,rmp
  .endif
	ldi rmp,Low(RAMEND)
	out SPL,rmp ; Init LSB stack pointer
;
; **********************************
;       D E B U G G I N G
; **********************************
;
.if Debug_display == Yes
    ldi rRxH,Debug_displayH ; Load high parameter
    ldi rRxL,Debug_displayL ; Load low parameter
    rcall DisplayDCF ; Call display
  Debug_display_loop:
    rjmp Debug_display_loop
  .endif
;
; **********************************
;     N O R M A L   I N I T
; **********************************
; Init the LCD
  rcall LcdInit ; Init LCD operation
  rcall LcdFrame
; Init serial clock and data pins
  sbi pSerialClkO,bSerialClkO ; Set pull-up on serial clock
  sbi pSerialDataO,bSerialDataO ; and on serial data
  cbi pSerialClkD,bSerialClkD ; Clock pin as input
  cbi pSerialDataD,bSerialDataD ; Data pin as input
; Init seconds counting and serial reception
  ldi rSecH,High(cSec) ; Start seconds counter, MSB
  ldi rSecL,Low(cSec) ; dto., LSB
  ldi rSerialTO,cSerialTO ; Serial collection restart counter
; Init serial clock pin as PCINT
  ldi rmp,1<<PCINT0 ; Clock pin as external int source
  out PCMSK0,rmp ; in int mask 0
  ldi rmp,1<<PCIE0 ; Enable pcint 0
  out GIMSK,rmp
; Init TC0 as seconds clock and for serial time-out
  ldi rmp,cDividerTC0 - 1 ; CTC value to
  out OCR0A,rmp ; Compare A
  ldi rmp,1<<WGM01 ; CTC on compare A
  out TCCR0A,rmp ; to control register A
  ldi rmp,1<<CS01 ; Prescaler = 8
  out TCCR0B,rmp ; to control register B
  ldi rmp,1<<OCIE0A ; Compare A interrupt
  out TIMSK0,rmp ; to TC0 int mask register
; Init sleep mode
  ldi rmp,1<<SE ; Sleep enable, mode idle
  out MCUCR,rmp ; to master control register
; Enable Ints
	sei ; Enable interrupts
;
; **********************************
;    P R O G R A M   L O O P
; **********************************
;
Loop:
  sleep ; Go sleeping
  nop ; Dummy for wake-up
  sbrc rFlag,bRxIn ; No word received?
  rcall DisplRx ; No, display that
  sbrc rFlag,bSec ; Second over?
  rcall Second ; Yes
	rjmp loop
;
; ***********************************
;  F L A G   H A N D L I N G
; ***********************************
;
; A second is over
Second:
  cbr rFlag,1<<bSec ; Clear second flag
  ldi ZH,2 ; Set second position on LCD
  ldi ZL,11
  rcall LcdPos ; Set LCD position to Z
  lds rmp,sTimeSecond ; Read seconds from SRAM
  inc rmp ; Next second
  cpi rmp,60 ; End of minute?
  brcs Second1 ; No, continue
  clr rmp ; Restart seconds
Second1:
  sts sTimeSecond,rmp ; Save seconds
  rjmp LcdDec2 ; Write seconds as 2-digit decimal

;
; A word has been received, display it
DisplRx:
  cbr rFlag,1<<bRxIn ; Clear flag
  ldi ZH,RawLine ; Raw data output line
  ldi ZL,RawCol ; Raw data output column
  rcall LcdPos ; Position to the LCD
  mov rmp,rRxH ; Display parameter character
  rcall LcdChar ; on LCD position
  mov rmp,rRxL ; Display value as hex
  rcall LcdHex2 ; on current LCD position
;
; Display received messages
DisplayDCF:
  ldi ZH,High(2*PosTable) ; Point Z to table, MSB
  ldi ZL,Low(2*PosTable) ; dto., LSB
DisplayDCF1:
  lpm rmp,Z+ ; Read character from table
  tst rmp ; Zero?
  breq DisplayDCFUnknown ; Yes, unknown param
  cp rRxH,rmp ; This parameter received?
  breq DisplayDCF2 ; Yes, display
  adiw ZL,5 ; Point to next parameter in list
  rjmp DisplayDCF1 ; Text next parameter
DisplayDCFUnknown:
  ret ; Ignore message
DisplayDCF2:
  ; Display this parameter
  lpm XH,Z+ ; Read position on LCD, line
  lpm XL,Z+ ; dto., column
  push ZH ; Save address on stack
  push ZL
  mov ZH,XH ; Copy position to Z, line
  mov ZL,XL ; dto., column
  rcall LcdPos ; Position to the LCD
  pop ZL ; Restore address from stack
  pop ZH
  lpm rmp,Z+ ; Read time position
  cpi rmp,cTimeNone ; No time setting?
  breq DisplayDCFOutMode ; Yes, skip
  cpi rmp,cTimeMinute ; Minute setting?
  brne DisplayDCFSetTime
  clr XL
  sts sTimeSecond,XL ; Clear second
DisplayDCFSetTime:
  ldi XH,High(sTime) ; Point X to time in SRAM, MSB
  ldi XL,Low(sTime) ; dto., LSB
  add XL,rmp ; Add time position
  ldi rmp,0 ; Any carry
  adc XH,rmp ; add to MSB
  st X,rRxL ; Write time
DisplayDCFOutMode:
  lpm rmp,Z ; Read output mode
  cpi rmp,1 ; 2-digit decimal?
  breq DisplayDCF2dig ; 1 = display 2-digit decimal
  brcs DisplayDCFAsc ; 0 = display ASCII char
  cpi rmp,3 ; Weekday?
  breq DisplayDCFWd ; 3 = display weekday
  brcs DisplayDCF3dig ; 2 = display 3-digit decimal
  ; Display the last four DCF bits
  mov rmp,rRxL ; Read parameter value
  lsr rmp ; A zero or one to carry
  rol rDcfBits ; Roll into register
  mov rmp,rDcfBits ; Copy DCF bits
  swap rmp ; Lower to upper bits
  ldi XL,4 ; Four bits to be displayed
DisplayDCFBits:
  lsr rmp ; Highest bit to carry
  push rmp ; Save bits on stack
  ldi rmp,'0' ; A zero to display
  brcc DisplayDCF0 ; Display that
  inc rmp
DisplayDCF0:
  rcall LcdChar ; Display bit on LCD
  pop rmp ; Restore bits from stack
  dec XL ; Next character
  brne DisplayDCFBits ; Continue
  rjmp DisplayDCFDone
;
; Display Weekday
DisplayDCFWd:
  ldi ZH,High(2*WdTable) ; Point Z to weekday table, MSB
  ldi ZL,Low(2*WdTable) ; dto., LSB
  mov rmp,rRxL ; Read weekday
  lsl rmp ; Two characters per weekday
  add ZL,rmp ; Add to table
  ldi rmp,0 ; Add carry
  adc ZH,rmp ; to ZH
  lpm rmp,Z+ ; Read first character
  rcall LcdChar ; Write to LCD
  lpm rmp,Z ; Read second character
  rcall LcdChar ; Write to LCD
  rjmp DisplayDCFDone
; Display as ASCII character
DisplayDCFAsc:
  mov rmp,rRxL ; Read parameter value
  rcall LcdChar
  rjmp DisplayDCFDone
; Display 3-digit decimal
DisplayDCF3dig:
  mov rmp,rRxL ; Read parameter value
  rcall LcdDec3
  rjmp DisplayDCFDone
; Display 2-digit decimal
DisplayDCF2dig:
  mov rmp,rRxL ; Read parameter value
  rcall LcdDec2
DisplayDCFDone:
  ret
;
; Position table
;   First byte: ASCII char parameter
;   Second/third: Line & column to display
;   Fourth: Type of display =
;     0=ASCII, 1=2-digit decimal, 2=3-digit decimal
;     3=Weekday (0=Monday), 4=Last four DCF77 digits
PosTable:
  .db 'R',2,16,cTimeNone,2,0 ; Restart message
  .db 'C',1,16,cTimeNone,2,0 ; Frequency scan complete
  .db 'S',2,16,cTimeNone,2,0 ; Signal strength, 3-digit decimal
  .db 'F',1,16,cTimeNone,2,0 ; Frequency, 3-digit decimal
  .db 'm',2,8,cTimeMinute,1,0 ; Minutes, 2-digit decimal
  .db 'h',2,5,cTimeHour,1,0 ; Hours, 2-digit decimal
  .db 'W',3,5,cTimeWd,3,0 ; Weekday, Monday based 2 ASCII chars
  .db 'D',3,9,cTimeDay,1,0 ; Day, 2-digit decimal
  .db 'M',3,12,cTimeMonth,1,0 ; Month, 2-digit decimal
  .db 'Y',3,15,cTimeYear,1,0 ; Year, 2-digit decimal
  .db '0',0,16,cTimeNone,4,0 ; DCF77-Bit Zero, 4 last DCF77 bits
  .db '1',0,16,cTimeNone,4,0 ; dto., One
  .db 'E',3,19,cTimeNone,0,0 ; DCF77 error, one ASCII char
  .db 'B',1,16,cTimeNone,2,0 ; Number of received bity, 3-digit decimal
  .db 'a',1,16,cTimeNone,2,0 ; Debug medium, 3-digit decimal
  .db 'd',2,16,cTimeNone,2,0 ; Debug difference, 3-digit decimal
  .db 0,0 ; End of table
;
; Table of weekdays
WdTable:
.if cLangEn == Yes
  .db "MoTuWdThFrSaSu"
  .else
  .db "MoDiMiDoFrSaSo"
  .endif
;
; Via serial transfer received parameters
;   Status reports
;     'R': Restart
;     'C': F scan complete
;     'S': Signal strength
;     'F': Frequency
;   Received time
;     'm': Minutes
;     'h': Hours
;     'W': Weekday
;     'D': Day
;     'M': Month
;     'Y': Year
;   Bit-Monitoring
;     '0': Zero received
;     '1': One received
;   DCF77 errors
;     'E': DCF77 error
;     'B': Number of bits received <> 59
;   Debugging
;     'a': Medium value
;     'd': Difference Max-Min
;
; ***********************************
;     L C D   R O U T I N E S
; ***********************************
;
LcdFrame:
  ldi rmp,1 ; Clear the LCD
  rcall LcdCtrl ; as control command
  ldi ZH,0 ; To line 1 colukmn 1
  ldi ZL,0
  rcall LcdPos ; Positioning
  ldi ZH,High(2*InitFrame) ; Z to text frame
  ldi ZL,Low(2*InitFrame)
  rjmp LcdText
;
;   20 chars per line
InitFrame:
  .db "DCF77 Serial RX tn24",0x0D,0xFF
  .db "Raw data: ___ F:___ ",0x0D,0xFF
  .db "Time __:__:__ S:___ ",0x0D,0xFF
  .db "Date __, __.__.__ E_",0xFE,0xFF
;      01234567890123456789
.equ RawLine = 1
.equ RawCol = 10
;
; Include lcd.inc
.include "lcd.inc" ; Load include file
;
; End of source code




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