home *** CD-ROM | disk | FTP | other *** search
- * Micro Cornucopia Magazine Issue #49
- * 6805 Controller Example Project Code
- *
- * EXAMPLE.ASM
- *
- * Sample program showing design of control program, to be run from
- * the EPROM of an MC68HC705 MCU. The program monitors one channel
- * of A/D, using an MC145041 Serial A/D converter chip. LEDs are
- * sequenced as needed, depending on the value of the A/D channel.
- *
- * The A/D chip connects to the MCU through the Serial Peripheral
- * Interface (SPI). The chip select line for the A/D is bit 3 of MCU
- * Port C; a low on this line selects the A/D chip.
- *
- * Three status LEDs connect to bits 0-2 of MCU port C. LED1 (port C,
- * bit 0) stays on at all times, to show the program is actually running.
- * LED2 (port C, bit 1) stays on at all times, provided the A/D value
- * stays below $40. If the value rises to between $40 and $7F, LED2
- * blinks once per second. If the value rises above $7F, LED2 goes out.
- * LED3 (port C, bit 2) only comes on if the A/D value reaches $80.
- * If the value lies between $80 and $BF, LED3 stays on. If the value
- * rises above $BF, LED3 blinks once per second.
- *
- * The code for routine TIME and much of the code in MAIN comes directly
- * from the example development project in the M68HC05 Microcontroller
- * Applications Guide. Refer to pages 4-24 for the original listing.
- * The same program is provided by Motorola as Freeware and as source
- * code on the program disc that accompanies the Applications Guide.
- * I would give credit to the original programmer, if I knew who he/she
- * was.
- *
-
-
- *
- * Register equates
- *
-
- PORTA EQU $00 Port A data register
- PORTB EQU $01 Port B data register
- PORTC EQU $02 Port C data register
- PORTD EQU $03 Port D data register
- DDRA EQU $04 Data direction, Port A
- DDRB EQU $05 Data direction, Port B
- DDRC EQU $06 Data direction, Port C
- SPCR EQU $0A SPIE,SPE,-,MSTR;CPOL,CPHA,SPR1,SPR0
- SPSR EQU $0B SPIF,WCOL,-,MODF;-,-,-,-
- SPDR EQU $0C SPI Data
- BAUD EQU $0D -,-,SCP1,SCP0;-,SCR2,SCR1,SCR0
- SCCR1 EQU $0E R8,T8,-,M;WAKE,-,-,-
- SCCR2 EQU $0F TIE,TCIE,RIE,ILIE;TE,RE,RWU,SBK
- SCSR EQU $10 TDRE,TC,RDRF,IDLE;OR,NF,FE,-
- SCDR EQU $11 SCI Data
- RDR EQU $11 SCI Receive Data (same as SCDR)
- TDR EQU $11 SCI Transmit Data (same as SCDR)
- TCR EQU $12 ICIE,OCIE,TOIE,0;0,0,IEGE,OLVL
- TSR EQU $13 ICF,OCF,TOF,0; 0,0,0,0
- ICAP EQU $14 Input Capture Reg (Hi-$14, Lo-$15)
- OCMP EQU $16 Output Compare Reg (Hi-$16, Lo-$17)
- TCNT EQU $18 Timer Count Reg (Hi-$18, Lo-$19)
- ALTCNT EQU $1A Alternate Count Reg (Hi-$1A, Lo-$1B)
-
- *
- * Following equates are timer values to produce a 50 msec delay
- * using the MCU timing registers. Use ONLY one pair of values,
- * depending on the MCU timing crystal for the target system.
- *
-
- TMRCNTL EQU $D4 FOR 2.0 MHZ CLOCK
- TMRCNTH EQU $30
-
- * TMRCNTL EQU $6A FOR 1.0 MHZ CLOCK
- * TMRCNTH EQU $18
-
-
-
- ORG $50 START OF VARIABLES IN RAM
-
- TEMPA RMB 1 TEMP STORAGE FOR ACC
- TEMPX RMB 1 TEMP STORAGE FOR XR
-
- TIC RMB 1 50 MSEC TICS; 0-19, 20 TICS = 1 SEC
- SEC RMB 1 CURRENT TIME IN SECONDS
- MIN RMB 1 CURRENT TIME IN MINUTES
- HR RMB 1 CURRENT TIME IN HOURS
- AMPM RMB 1 CURRENT TIME (0 = AM, 1 = PM)
- DAY RMB 1 CURRENT DAY (1 = SUN...7 = SAT)
-
-
- LED1 RMB 1 CONTROL BYTE FOR LED1 (0 = DARK)
- LED2 RMB 1 CONTROL BYTE FOR LED2 (0 = DARK)
- LED3 RMB 1 CONTROL BYTE FOR LED3 (0 = DARK)
-
-
- ORG $0100 START OF PROGRAM IN ROM
-
- INIT RSP INITIALIZE THE STACK POINTER
-
- *
- * Set timer and SPI characteristics.
- *
-
- LDA #$50 SPI: MCU IS MASTER, 2 USEC CLOCK
- STA SPCR WRITE TO SPI CONTROL REG
- CLRA TIMER: NO INTERRUPTS OR PINS USED
- STA TCR WRITE TO TIMER CONTROL REG
-
- *
- * Set up port C, bits 0-2 for output as LED controllers.
- * Clear LED control bytes (turns LEDs off later).
- *
- * Set up port C, bit 3 for output as A/D chip select.
- *
-
- LDA #$0F BITS 0-3 = OUTPUT, ALL OTHERS = INPUT
- STA DDRC SETUP PORT C
- CLR LED1 SHOW ALL LEDS AS OFF
- CLR LED2
- CLR LED3
-
- *
- * Initialize clock to show 12:00 AM Sunday.
- *
-
- CLR TIC ZERO THE TIC COUNTER
- CLR SEC SET SECONDS TO 0
- LDA #12 SET HOUR TO NOON
- STA HR
- CLR MIN SET MINUTES TO 0
- CLR AMPM SET TO MORNING
- LDA #1 SET DAY TO SUNDAY
- STA DAY
-
- *
- * ----- END OF INITIALIZATION -----
- *
-
-
-
- *
- * MAIN
- *
- * This loop gets executed once each 50 msec, based on the
- * MCU's internal timer. The compare register is loaded
- * with a target value. When the timer hits that value,
- * bit 6 of the Output Compare Register (OCR) gets set,
- * marking the end of a 50 msec interval.
- *
- * At each interval, the timer is reloaded, the time/day clock
- * is updated, and the chain of subroutines at the bottom of
- * the loop is executed. So long as the chain takes no more
- * than 50 msec to complete, the MCU will stay on-time.
- *
-
- MAIN EQU *
- BRCLR 6,TSR,MAIN LOOP HERE UNTIL TIME OUT
- LDA OCMP+1 LOW BYTE OF OCR
- ADD #TMRCNTL CALCULATE NEW TIMER TARGET
- STA TEMPA
- LDA OCMP DO BOTH HALVES OF 16-BIT VALUE
- ADC #TMRCNTH
- STA OCMP
- LDA TEMPA
- STA OCMP+1 TIMER TARGET RELOADED
-
- LDA TIC GET TIC COUNTER
- INCA BUMP IT
- STA TIC AND SAVE NEW VALUE
- CMP #20 DONE ONE SECOND YET?
- BLO ARNC1 IF NOT, DON'T CLEAR TIC
- CLR TIC YES, START A NEW SECOND
- ARNC1 EQU *
-
- *
- * End of the timing loop; following chain of subroutine calls
- * must complete within 50 msecs.
- *
-
- JSR TIME UPDATE TIME-OF-DAY CLOCK
- JSR PROCESS READ A/D, SET LED CONTROL BYTES
- JSR LEDS PROCESS PENDING LED COMMANDS
- BRA MAIN DO IT ALL AGAIN
-
- *
- * TIME
- *
- * Update the time-of-day clock.
- *
-
- TIME EQU *
- TST TIC Check for TIC=zero
- BNE XTIME If not; just exit
- INC SEC SEC=SEC+1
- LDA #60
- CMP SEC Did SEC -> 60 ?
- BNE XTIME If not; just exit
- CLR SEC Seconds rollover
- INC MIN MIN=MIN+1
- CMP MIN A still 60; MIN=60 ?
- BNE XTIME If not; just exit
- CLR MIN Minutes rollover
- INC HR HR=HR+1
- LDA HR For comparisons
- CMP #13 HR=13 ?
- BNE ARNS1 If not; skip
- LDA #1
- STA HR Set HR=1
- BRA XTIME Exit
- ARNS1 CMP #12 HR=12 ?
- BNE XTIME If not; just exit
- LDA AMPM
- EOR #%00000001 Invert AM/PM bit
- STA AMPM 0=AM, 1=PM
- BNE XTIME If not AM now; just exit
- INC DAY DAY=DAY+1
- LDA DAY
- CMP #8 Day rollover ?
- BNE XTIME If not; just exit
- LDA #1
- STA DAY Set Day to 1 (SUN)
- XTIME RTS
-
-
-
- *
- * LEDS -- Process any pending LED commands, based on the LED
- * control bytes.
- *
- * Each LED control byte determines whether an LED is turned on
- * or off. If the byte is 0, that LED is always turned off by this
- * routine. If the byte is not 0, the corresponding LED is always
- * turned on and the control byte is decremented.
- *
- * If this routine is called each slice (20 times per second), the
- * longest period of time an LED can remain lit without intervention
- * is 255 * 50 msec = 12750 msec or 12.75 seconds.
- *
-
- LEDS TST LED1 NEED TO TURN ON LED1?
- BEQ LED1N BRANCH IF TIME TO TURN OFF
- BCLR 0,PORTC TURN ON LED1 (ACTIVE LOW)
- DEC LED1 COUNT THIS 50 MSEC
- BRA LED2T GO TEST LED2
- LED1N BSET 0,PORTC TURN OFF LED1
-
- LED2T TST LED2 DO IT AGAIN FOR LED2
- BEQ LED2N
- BCLR 1,PORTC USE BIT 1 FOR LED2
- DEC LED2
- BRA LED3T
- LED2N BSET 1,PORTC
-
- LED3T TST LED3 SAME AGAIN FOR LED3
- BEQ LED3N
- BCLR 2,PORTC USE BIT 2 FOR LED3
- DEC LED3
- BRA LEDSX
- LED3N BSET 2,PORTC
- LEDSX RTS
-
-
- *
- * PROCESS -- Change LED control bytes as needed to reflect current
- * status of A/D input.
- *
- * If TIC holds a 0 (first 50 msec slice of each second), read channel
- * 0 of the A/D and trash the returned value.
- *
- * If TIC holds a 1 (second 50 msec slice of each second), read
- * channel 0 of the A/D and process the LED states, depending on the
- * following:
- *
- * Value range Action taken
- * ----------- --------------------------------------------
- *
- * $00 - $3F Turn LED2 on for one second, turn LED3 off.
- * $40 - $7F Turn LED2 on for .5 seconds, turn LED3 off.
- * $80 - $BF Turn LED2 off, turn LED3 on for one second.
- * $C0 - $FF Turn LED2 off, turn LED3 on for .5 seconds.
- *
- * All other values of TIC are ignored by this routine. Note
- * that LED1 is always on.
- *
-
- PROCESS
- LDA #$FF GET LONGEST ON-TIME
- STA LED1 ALWAYS LEAVE LED1 ON
- LDA TIC GET CURRENT TIC VALUE
- BNE PROCS1 BRANCH IF NOT FIRST TIC
- BSR A2D LOAD UP CHANNEL 0 VALUE
- BRA PROCSX AND LEAVE
-
- PROCS1 CMP #1 IS THIS THE SECOND TIC?
- BNE PROCSX BRANCH IF NOT
- CLRA LOAD UP CHANNEL 0 AGAIN
- BSR A2D AND READ THAT CHANNEL
-
- CMP #$40 IS VALUE IN GOOD RANGE?
- BHS PROCS2 BRANCH IF NOT
- CLR LED3 TURN OFF LED3
- LDA #20 TURN ON LED2 FOR 1 SECOND
- STA LED2
- BRA PROCSX AND LEAVE
-
- PROCS2 CMP #$80 IS VALUE IN FAIR RANGE?
- BHS PROCS3 BRANCH IF NOT
- CLR LED3 TURN OFF LED3
- LDA #10 TURN ON LED2 FOR .5 SECONDS
- STA LED2
- BRA PROCSX AND LEAVE
-
- PROCS3 CMP #$C0 IS VALUE IN POOR RANGE?
- BHS PROCS4 BRANCH IF NOT
- CLR LED2 TURN OFF LED2
- LDA #20 TURN ON LED3 FOR 1 SECOND
- STA LED3
- BRA PROCSX AND LEAVE
-
- PROCS4 CLR LED2 MUST BE BAD, SHUT OFF LED2
- LDA #10 TURN ON LED3 FOR .5 SECONDS
- STA LED3
-
- PROCSX RTS
-
-
- *
- * A2D -- Read selected channel of serial A/D (MC145041).
- *
- * Enter with A/D channel number in ACC. Returns analog value
- * in ACC. Assumes chip select line to A/D chip is driven by
- * port C, bit 3 (active low).
- *
- * Note that the value returned by A2D corresponds to the most
- * recent previous channel number transmitted, not the current
- * channel number! Therefore, unless you know for a fact that
- * the last channel number you sent was the one you want to read
- * now, you had better call this routine twice, using the same
- * channel number.
- *
-
- A2D
- TST SPSR CLEAR SPIF
- BCLR 3,PORTC PULL CHIP SELECT LINE LOW
- ASLA MOVE CHANNEL NUMBER TO HIGH NYBBLE
- ASLA
- ASLA
- ASLA
- STA SPDR SEND CHANNEL TO SPI
-
- SPIFLP BRCLR 7,SPSR,SPIFLP WAIT UNTIL COMPLETE
- BSET 3,PORTC RELEASE CHIP SELECT
- LDA SPDR GET VALUE RETURNED
- RTS
-
-
-
- *
- * Set up the RESET vector. This is required for code that will
- * be moved into the MCU's EPROM for later execution.
- *
-
- ORG $1FFE RESET VECTOR
-
- FDB INIT POINT TO START OF PROGRAM