;--------------------------------------------------------------- ; CARL4.ASM G. Forrest Cook 2005/02/23 ; CARL: Cout Accumulator for Radiation Levels ; Licensed under version 2.0 of the GNU General Public License (GPL) ; ; Version 2 counts down in minutes/seconds ; Version 3 inlines the lcd writing to lay off the stack ; Version 4 uses an HD44780 1X16 LCD display (DMC16117A equiv) ; ; 6HC705K1 CDV-700 Geiger Counter pulse counter ; Just barely fits in the processor, no room for new features ;--------------------------------------------------------------- ;MODE ABSOLUTE ; Set assembly mode $BASE 10T PORTA EQU 00H ; Ports PORTB EQU 01H DDRA EQU 04H ; DDRs DDRB EQU 05H TSCR EQU 08H ; Timer status/control reg TCNTR EQU 09H ; Timer counter register ISCR EQU 0AH ; Interrupt status/control reg PDRA EQU 010H ; Pulldown Regs PDRB EQU 011H MORADD EQU 0017H ; MOR ROM ADDRESS RAMORG EQU 00E0H ; BOTTOM OF RAM EPROM EQU 0200H ; BOTTOM OF EPROM COPR EQU 03F0H ; COP timer clear register INTVEC EQU 03F8H ; INTERRUPT VECTORS START HERE ASET EQU 0FFH ; DDR A SETUP, bits 0-7 out ASETI EQU 0FCH ; DDR A bits 0-1 inputs AINIT EQU 000H ; PORT A INITIAL COND (LEDs off) APUL EQU 000H ; No pull downs (LCD ins may do pull up) BSET EQU 003H ; DDR B SETUP, bit 0 out, bit 1 out BINIT EQU 0 ; PORT B INITIAL COND BPUL EQU 000H ; No pull downs MORSET EQU 019H ; MOR DATA, SWAIT, LVRE, COPEN TSCRDA EQU 027H ; TSCR SETUP: 00100111 TOIE, TOFR, RTIFR, RTI/COP ISCRDA EQU 082H ; ISCR SETUP: 10000010 TINIA EQU 0A1H ; Use these 3 values for a real chip (1 second delay) TINIB EQU 007H LCDDLY EQU 0FFH ; Pause for lcd commands and data, 080H is too short. ;TINIA EQU 007H ; Use these 3 values with the ICS (approx. 1 sec) ;TINIB EQU 000H ;LCDDLY EQU 001H ; Pause for lcd commands and data ;--------------------------------------------------------------- ORG MORADD ; MOR ADDRESS DB MORSET ; MOR DATA ;--------------------------------------------------------------- ORG RAMORG ; Bottom of 32 bytes of RAM SAVEX: DS 1 ; temp storage NEWTIC: DS 1 ; Tick Flag TIMR1A: DS 1 ; Timer 1 low register TIMR1B: DS 1 ; Timer 1 high register TIMR1Z: DS 1 ; Timer 1 zero flag SECSC: DS 1 ; Seconds Counter C SECSB: DS 1 ; Seconds Counter B SECSA: DS 1 ; Seconds Counter A (units) SECCHG: DS 1 ; Seconds changed check GCDIGS: DS 1 ; Number of count digits GEIGCD: DS 1 ; Geiger Count Digit data (near stack on purpose) GEIGCC: DS 1 ; Geiger Count Digit data GEIGCB: DS 1 ; Geiger Count Digit data GEIGCA: DS 1 ; Geiger Count Digit data (units) ; Stack grows up from here ;--------------------------------------------------------------- ORG EPROM ; BOTTOM OF EPROM ;--------------------------------------------------------------- ; LCD1.ASM main ; Initialize the micro state and loop START: LDA #ASET ; Set up ADDR STA DDRA LDA #AINIT ; Init port A data STA PORTA LDA #APUL ; Setup pulldowns STA PDRA LDA #BSET ; Set up BDDR STA DDRB LDA #BINIT ; Init port B data STA PORTB LDA #BPUL ; Setup pulldowns STA PDRB LDA #TSCRDA ; init 1SCR, enable timer ints STA TSCR LDA #ISCRDA ; init ISCR STA ISCR JSR GCTINI ; initialize the geiger count JSR TMRINI ; Reload the seconds counter JSR SECINI ; initialize the seconds count JSR LCDINI ; Send init sequence to the LCD JSR SECDSP ; display seconds LDA #1 ; display run message JSR RUNDSP BSR GCTDSP ; initial geiger count display CLI ; enable interrupts INFLOP: LDA #0 ; reset the COP timer STA COPR JSR INSWCH ; check reset switch AND #001H BEQ CNTRES ; Reset everything if switch is 0 LDA TIMR1Z ; Check for counter at zero BNE TMREND LDA SECSA ; only update seconds dislay if seconds change CMP SECCHG BEQ SAMSEC LDA SECSA ; save new second units STA SECCHG JSR SECDSP ; display seconds SAMSEC: LDA NEWTIC ; Update display if new tics show up BEQ INFLOP ; otherwise just loop CLR NEWTIC BSR GCTDSP ; Display geiger count BRA INFLOP ; loop to beginning CNTRES: CLRA ; display stop message BSR RUNDSP BSR GCTDSP ; Display geiger count RSHLOP: LDA #0 ; reset the COP timer STA COPR BSR INSWCH ; loop while reset switch is on (0) AND #001H BEQ RSHLOP JSR GCTINI ; initialize the geiger count BSR GCTDSP ; Display geiger count JSR TMRINI ; Reload the seconds counter JSR SECINI ; initialize the seconds count BSR SECDSP ; display seconds LDA #1 ; dislay run char BSR RUNDSP BRA INFLOP TMREND: BSR SECDSP ; display seconds at 0 CLRA ; dislay stop char BSR RUNDSP TMRELP: LDA #0 ; reset the COP timer STA COPR BSR INSWCH ; loop while reset switch is on AND #001H BNE TMRELP BRA CNTRES ;--------------------------------------------------------------- ; Display the geiger count, stored in ram as length+string GCTDSP: LDA #0C2H ; Decimal geiger count Display Location BSR LCDCMD LDA GEIGCD BSR LCDDAT ; store in the lcd LDA #0C3H BSR LCDCMD LDA GEIGCC BSR LCDDAT ; store in the lcd LDA #0C4H BSR LCDCMD LDA GEIGCB BSR LCDDAT ; store in the lcd LDA #0C5H BSR LCDCMD LDA GEIGCA BSR LCDDAT ; store in the lcd RTS ;--------------------------------------------------------------- ; Display the seconds count, stored in ram as length+string SECDSP: LDA #082H ; Decimal time counter Display Location BSR LCDCMD LDA SECSC BSR LCDDAT ; store in the lcd LDA #083H BSR LCDCMD LDA SECSB BSR LCDDAT ; store in the lcd LDA #084H BSR LCDCMD LDA SECSA BSR LCDDAT ; store in the lcd RTS ;--------------------------------------------------------------- ; Run/stop display RUNDSP: BEQ STPDSP LDA #087H ; R/S display location BSR LCDCMD LDA #'R' BSR LCDDAT ; store in the lcd RTS STPDSP: LDA #087H ; R/S display location BSR LCDCMD LDA #'S' BSR LCDDAT ; store in the lcd RTS ;--------------------------------------------------------------- ; Input control switch bits INSWCH: LDA #ASETI ; input port A0 to LCD STA DDRA ; set port bits to input LDA PORTA TAX LDA #ASET ; set back to output STA DDRA TXA RTS ;--------------------------------------------------------------- ; Send a single command byte from A to the LCD LCDCMD: STA PORTA LDA #002H ; Toggle the E pin in command mode STA PORTB STX SAVEX ; delay LDX #LCDDLY DELAY1: LDA #0 ; reset the COP timer STA COPR DECX BNE DELAY1 LDX SAVEX CLR PORTB RTS ;--------------------------------------------------------------- ; Send a single data byte from A to the LCD LCDDAT: STA PORTA LDA #003H ; Toggle the E pin in data mode STA PORTB STX SAVEX ; delay LDX #LCDDLY DELAY2: LDA #0 ; reset the COP timer STA COPR DECX BNE DELAY2 LDX SAVEX LDA #001H STA PORTB RTS ;--------------------------------------------------------------- ; Init the geiger count GCTINI: LDA #4 ; set the count digits STA GCDIGS TAX LDA #'0' ; initialize geiger count digits GCDINL: STA GCDIGS,X DECX BNE GCDINL CLR NEWTIC ; clear tick flag RTS ;--------------------------------------------------------------- ; Init the seconds counter SECINI: LDA #'0' STA SECSA ; units position always reset to 0 STA SECCHG ; change comparison register BSR INSWCH ; check reset switch AND #002H BNE SEC600 ; Check 60 or 600 seconds LDA #'6' ; 60 STA SECSB LDA #'0' STA SECSC RTS SEC600: LDA #'0' ; 600 STA SECSB LDA #'6' STA SECSC RTS ;--------------------------------------------------------------- ; Send initialization chars to the LCD LCDINI: LDA #038H ; 8 bit i/o, 1/16 duty, 5x7 font BSR LCDCMD LDA #001H ; clear display BSR LCDCMD LDA #00CH ; display on, curor off BSR LCDCMD RTS ;--------------------------------------------------------------- ; Init the Timer Value (0x07A1=1 sec, 0x0004 with emulator) TMRINI: LDA #TINIB STA TIMR1B LDA #TINIA STA TIMR1A CLR TIMR1Z RTS ;--------------------------------------------------------------- ; External IRQ pin interrupt routine ; Recursive subr call eats stack, do inline code. EXTINT: LDX GCDIGS ; set index to last digit position DECX INC GEIGCD,X ; Increment Geiger count digit 1 LDA GEIGCD,X CMPA #'9' BLS EXTIRT LDA #'0' ; roll up to next digit STA GEIGCD,X DECX INC GEIGCD,X ; Increment Geiger count digit 2 LDA GEIGCD,X CMPA #'9' BLS EXTIRT LDA #'0' ; roll up to next digit STA GEIGCD,X DECX INC GEIGCD,X ; Increment Geiger count digit 3 LDA GEIGCD,X CMPA #'9' BLS EXTIRT LDA #'0' ; roll up to next digit STA GEIGCD,X DECX INC GEIGCD,X ; Increment Geiger count digit 4 LDA GEIGCD,X CMPA #'9' BLS EXTIRT LDA #'0' ; roll up to next digit STA GEIGCD,X DECX EXTIRT: INC NEWTIC ; Turn on tick flag RTI ;--------------------------------------------------------------- ; Periodic 512uS timer interrupt routine, 3 byte binary count down TIMINT: BSET 3,TSCR ; clear the TOF bit by banging on TOFR LDA TIMR1A BEQ TIM1AZ ; XX00 DEC TIMR1A ; usual subtract 1 case RTI TIM1AZ: LDA TIMR1B BEQ TIM1BZ ; 0000 DEC TIMR1B ; roll under to FF DEC TIMR1A RTI TIM1BZ: BSR TMRINI ; Reload the seconds counter DEC SECSA ; Decrement the seconds count LDA SECSA CMPA #'/' ; check for seconds digit A underflow BLS SECAUF CMPA #'0' ; check for seconds digit A underflow BEQ SZCHEK ; check for all zero seconds digits (done) RTI SECAUF: LDA #'9' STA SECSA DEC SECSB ; decrement 10 seconds count LDA SECSB CMPA #'/' ; check for seconds digit B underflow BLS SECBUF RTI SECBUF: LDA #'9' STA SECSB DEC SECSC ; decrement 100 seconds count LDA SECSC CMPA #'/' ; check for seconds digit C underflow BLS SECCUF RTI SECCUF: LDA #'0' ; 3 digit rollunder case STA SECSC RTI SZCHEK: LDA SECSB ; Check for the digits B and C at 0 CMPA #'0' BNE SZSKIP LDA SECSC CMPA #'0' BNE SZSKIP INC TIMR1Z ; Set the timer done flag SZSKIP: RTI ;--------------------------------------------------------------- ORG INTVEC ; INTERRUPT VECTOR ADDRESSES TIMER: DW TIMINT ; TIMER INT ADD EXINT: DW EXTINT ; EXTERNAL INTERRUPT ADD SWINT: DW START ; SOFTWARE INT RESET: DW START ; RESET ADDRESS ;---------------------------------------------------------------