Written some cool source code? Upload it to Programmer's Heaven.
*/
*/

View \MOTRCTL.ASM

Hc11 program for automatic motor control

Submitted By: WEBMASTER
Rating: Not rated (Rate It)


**      MOTOR CONTROL   - Code for the HC11
*
*       This programs uses prompts and a dummy terminal to communicate
*       with the user.  The program will drive a motor automatically or
*       operate with user control.  The choice is the users.
*
*       In the automatic mode the program generates a pwm signal of  constant 
*       frequency and variable duty cycle. The duty cycle changes from 0%
*       to 99% then back to 1% then the cycle is repeated until
*       the HC11 is reset. Port B bits 0 and 1 are complememts of
*       eachother and represent the direction of a turning motor.
*       The direction changes after each cycle.
*       The motor with this program will start in the forward direction
*       and accelerate to full speed then will deccelarate to stop.
*       The motor will now change direction and accelerate in the
*       reverse direction until full speed then will deccelerate to
*       stop then the whole cycle is repeated. Short delays occurr
*       between each change in duty cycle to decrease the acceleration
*       and deceleration of the motor. Longer delays are present at
*       full speed and at stop to have a trapoziodal profile.
*
*       In the manual control mode the user has control of the direction and
*       percent duty cycle.  Directions cannot be changed instantly to avoid
*       dammage to the hardware.  The delete key must first be depressed to
*       bring up thedirection prompt.
*
*       The program outputs to a terminal the current speed (duty cycle) and
*       direction through the SCI port to a dummy terminal.
*
*       This program is to be used with any HC11 with BUFFALO
*       (monitor and debug program) availabe in ROM.  The program length
*       is larger than 512 bytes and therefore cannot be used with all
*       EEPROM versions of the HC11.
*
*       The HC11 is used in conjunction with kits KITDEVB103 and KITDEVB118
*       and application notes AN1300 and AN1301 for dc brushed motor drive.
*       Kits and ap notes are availale through Motorola Literature Distribution.
*
*
*TIMER REGISTER ADDRESSES
REGBAS EQU     $1000           * Register base
OC1M    EQU     $0C             * OC1 action mask register
OC1D    EQU     $0D             * OC1 action data register
TOC1    EQU     $16             * Output compare 1 register
TOC2    EQU     $18             * Output compare 2 register
TOC3    EQU     $1A             * Output compare 3 register
TCTL1  EQU     $20             * Timer control register 1
TMSK1  EQU     $22             * Timer interrupt mask register 1
TFLG1  EQU     $23             * Timer interrupt flag register 1
TCNT    EQU     $0E             * Timer counter register
 
*BUFFALO I/O ROUTINE ADDRESSES
INCHAR EQU     $FFCD           * Get character from terminal
OUTCRLF EQU     $FFC4           * Output a CR and LF to screen
OUTSTRG EQU     $FFC7           * Output a string
OTSTRGO EQU     $FFCA           * Out string w/o preceedin crlf
OUTA    EQU     $FFB8           * Output contents of acca
OUTLHLF EQU     $FFB2           * Cnvrt lft nibble to ascii & out
OUTRHLF EQU     $FFB5           * Cnvrt rt nibble to ascii & out
*
*ADDITIONAL ADDRESS AND CONSTANT EQUATES
ACIA    EQU     $9800           *
COPRST EQU     $103A
DELAY  EQU     $FFF0           * Delay time in auto mode
PIOC    EQU     $1002           *
PORTB  EQU     $1004           * Port B
EOT    EQU     $04             * End of transmission

*PSEUDO VECTOR EQUATES FOR OUTPUT COMPARE INTERRUPTS
PVOC1  EQU     $00DF
PVOC2  EQU     $00DC
PVOC3  EQU     $00D9
 
*PROGRAM VARIABLES
        ORG     $0000
PERIOD  RMB     2               * The time between Oc1 intr
PERCENT RMB     2               * Ascii bcd #'s for %dty cy
PWIDTH  RMB     2               * Hex # of pwm duty cycle %
TRIBYTS RMB     3               * Result of 8 * 16 bit mul
FLAGS   RMB     1               * Byte with all used flags
 
*START OF MAIN PROGRAM
        ORG     $C000
        LDS     #$DFFF          * User'
s stack area on EVB
        CLRA    FLAGS           * Clear all flags
        LDD     #$008D          * Time between oc1 interrupts
        STD     PERIOD          * Save in period
        CLR     PIOC            * Clear parallel I/O control reg

**SETUP OF PSEUDO VECTORS***
        LDAA    #$7E            * Op code for jump
        STAA    PVOC1           * OC1 pseudo vector
        STAA    PVOC2           *       "
        STAA    PVOC3           *       "

        LDD     #OC1ISR         * Address of OC1 interrupt service routine
        STD     PVOC1+1         * Finish JMP inst to OC1 routine
        LDD     #OC2ISR         * Address of OC2 interrupt servic
        STD     PVOC2+1         * Finish JMP inst to OC1 routine

*
MODE    JSR     INIT_OC                 * Initialize output compares
        CLI                     * Enable interrupts
        JSR     OUTCRLF         * Output cr and lf
        LDX     #MODEMSG                * Location of message in X
        JSR     OUTSTRG         * Output message at x
        BCLR    FLAGS $02               * Clear mode flag
        JSR     INCHAR          * Wait for user to input a char
        CMPA    #$46            * Compare to 'F'
        BNE     MODE            * Not 'F', invalid, br to mode
        JSR     INCHAR          * Second char of "F1" or "F2"
        CMPA    #$31            * Compare to 1
        BEQ     AUTO            * If 1 then automatic mode
        CMPA    #$32            * Compare to 2
        BEQ     MANUAL          * If 2 then manual mode
        BRA     MODE            * Invalid char, bra to mode
AUTO    JSR     RUN             * Automatic mode routine
        BRA     MODE            * Return to mode
MANUAL  JSR     URUN            * Manual mode routine
        BRA     MODE            * Return to mode

*INIT_OC-       This subroutine initializes the oc1 and oc2 and sets
*       toc1 and toc2 registers.
INIT_OC LDX     #REGBAS         * Set for indexed addressing
        LDAA    #%11000000              * Set OM2 & OML
        STAA    TCTL1,X         * OC2 sets its pin hi
        LDAA    #%01000000              * OC1 affects OC2 pin
        STAA    OC1M,X          * Sets OC1 action mask
        CLRA                    * OC1 sets all OCs low
        STAA    OC1D,X          * OC1 action data reg.
        LDD     PERIOD          * Period into accd
        LSLD                    * Period times 2
        ADDD    TCNT,X          * Add 2 periods of TCNT
        STD     TOC1,X          * Store in OC1 time
        ADDD    PERIOD          * Add period to OC1 time
        STD     TOC2,X          * Store OC2 time
        BCLR    TFLG1,X %00111111       * Clear OC1, OC2, &OC3 flags
        BSET    TMSK1,X %11000000       * Enable OCI & OC2 interrupts
        RTS

*URUN-  SUBROUTINE FOR MANUAL MODE OF OPERATION
*
URUN    CLR     PERCENT         * Clear percent hi byte
        CLR     PERCENT+1               * Clear percent lo byte
        JSR     GET_DIR         * Display direction prompt &
*                               * get direction
ANOTHER JSR     OUTCRLF         * Output a cr and lf
        LDX     #PERCENT                * X points to pwm % characters
        JSR     DSPLASP         * Display duty cycle percentage
        LDX     #SPDPRMT                * Prompt user for duty cycle %
        JSR     OUTSTRG         * Output prompt
        JSR     IN_SPED         * Get new Duty Cycle% from keybd
        BRSET   FLAGS $02 EXIT  * Exit if mode flag is set
        JSR     CONVERT         * Convert input to a pulse width
*                               * in hex.
        BSET    FLAGS $80               * Set the newspeed flag for OC2
        BRA     ANOTHER         * Repeat
EXIT    SEI                     * Disable interrupts
        RTS                     * Return to mode prompt routine
*
*RUN-   SUBROUTINE FOR AUTOMATIC MODE
RUN     BCLR    FLAGS $01               * Clear cntdir flag (count up 1st)
        LDAA    #$01            * Fwd pin hi rev pin low
        STAA    PORTB           * Initialize the direction
        JSR     OUTCRLF         * Output cr and lf
        LDX     #SPDMSG         * X points to speed message
        JSR     OUTSTRG         * Output message
DIRECT  COM     PORTB           * Change directions
                LDAA #$01               * Start from 1
CHANGE  LDAB    ACIA            * Get acia status register
        LSRB                    * rdrf into carry bit
        BCS     GETOUT          * rdrf=1 then get out of this mode
        PSHA                    * save count on stack
        JSR     UPDATE          * display and change pwidth approp
        PULA                    * Get count from stack
        BSET    FLAGS $80               * Set chgspd flag
        LDY     #$0002          * Count to wait until next change
        JSR     WAIT            * Wait between increments routine
        LDAB    FLAGS           * Get flags byte
        BITB    #$01            * Count direction = 1 ?
        BNE     DOWN            * Count down if =1 else count up
        ADDA    #$01            * Add one to count in acca
        DAA                     * Adding in BCD
        BNE     CHANGE          * Sum not = 0 branch to change
        BSET    FLAGS $01               * Set count direction flag
        LDY     #$0010          * Long delay count before changing
*                               * count direction.
        JSR     WAIT            * Wait between increments
        LDAA    #$99            * Start count at 99 and go down
DOWN    BITA    #$0F            * Check for hex number $_F
        BNE     LEAP            * Not $_F then leap else
        SUBA    #$06            * Subtract 6 from count for bcd #s
LEAP    SUBA    #$01            * Subraact 1 from count
        BNE     CHANGE          * Count not= 0 then change else
        BCLR    FLAGS $01               * Clear cntdir flag (count up)
        LDY     #$0010          * Lng dlay cnt bfor changin dir
        JSR     WAIT            * Wait
        BRA     DIRECT          * Branch always to direct
GETOUT  SEI                     * Disable interrupts
        RTS
*
*UPDATE-
*
UPDATE  PSHA                    * Save count on stack
        PSHA                    * Save count again on stack
        JSR     OUTLHLF         * Output left nibble as ascii
        STAA    PERCENT         * Store ascii form of left nibble
        PULA                    * Get copy of count from stack
        JSR     OUTRHLF         * Output right nibble as ascii
        STAA    PERCENT+1               * Store ascii form of rt nibble
        LDAA    #$08            * Ascii bs into acca
        JSR     OUTA            * Output a back space
        JSR     OUTA            * Another bs, ready to output %
        PULA                    * Get count from stack
CONVERT LDX     #PERCENT                * X points ascii bcd % characters
        JSR     BCDHEX          * Convert from ascii bcd to hex
        LDX     #PERIOD         * Multiplier
        JSR     MUL2BY1         * period*percent=tribyts
        JSR     DIV3BYT         * tribyts/100=pwidth(accd)
        STD     PWIDTH          * Store result in PWIDTH
        RTS

*WAIT-  This subroutine provides the delays between increments or
*       decrements in the count in automatic mode. It also serves
*       to give longer delays at full speed in both forward and
*       reverse directions and at stop. A number in Y indicates
*       how many continious delays there will be.
WAIT    LDX     #REGBAS         * Set up for indexed addressing
        PSHA                    * Save count on stack
AGAIN   LDD     #DELAY          * Delay time for oc3
        ADDD    TCNT,X          * Add timer count to delay
        STD     TOC3,X          * Store in oc3 timer
        BCLR    TFLG1,X %11011111       * Clear the oc3 flag
CIRCLE  BRSET   TFLG1,X %00100000 TSTY  * Oc3 flag set? yes>tsty
        LDAA    #$55            * Reset cop so no time out
        STAA    COPRST          *
        LDAA    #$AA            *
        STAA    COPRST          *
        BRA     CIRCLE          * Poll oc3 flag
TSTY    DEY                     * Decrement Y
        BNE     AGAIN           * Y=0 then return, else loop again
                PULA            * Pull count from stack
        RTS
*
*GET_DIR-       This subroutine prompts the user for a direction
*       F1=fwd and F2=rev) then writes the appropriate
*       byte to port B. This subroutine is used for the
*       manual mode.
GET_DIR LDX     #DIR_MSG                * X points to message
        JSR     OUTSTRG         * Output message
        JSR     INCHAR          * Get character from terminal
        CMPA    #$46            * Not an "F" then invalid repeat
        BNE     GET_DIR         * IF an "F" then get 2nd character
        JSR     INCHAR          * Get character from terminal
        CMPA    #$31            * =1?
        BNE     CMPARE2                 * =1 then continue, else 2nd compa
        LDAA    #$01            * Portb0=1,portb1=0
        STAA    PORTB           * store forward bits in port b
        BRA     BACK            * return from subroutine
CMPARE2 CMPA    #$32            * =2?
        BNE     GET_DIR         * If invalid char repeat prompt
        LDAA    #$02            * =2 then portb0=0,portb1=1
        STAA    PORTB           * Store reverse bits in port b
BACK    RTS
*
*DSPLYSPD-      This subroutine displays current % duty cycle message then
*       the current %. X should point to the ascii characters
*
DSPLASP PSHX                    * Save X on stack
        LDX     #SPDMSG         * X points to message
        JSR     OTSTRGO         * Out message w/o preceeding crlf
        PULX                    * Set for indexed addressing
        LDAA    0,X             * Get first characer
        JSR     OUTA            * Output character
        LDAA    1,X             * Get 2nd character
        JSR     OUTA            * Output character
        RTS
*
*IN_SPED-       This subroutine takes characters for the new speed as a
*       a percentage.   When a cr is received the input is com-
*       plete or when more than 2 characters without a cr the
*       input is assumed to be 100%. The inputs are stored at
*       location PERCENT (2 BYTES).
*
IN_SPED JSR     INCHAR          * Get 1st input from terminal
        CMPA    #$0D            * cr ?
        BEQ     IN_SPED         * If cr then try again
        CMPA    #$7F            * Del ?
        BEQ     SETFLG          * If del then setflag,else continu
        STAA    PERCENT         * Save first charcater
        JSR     INCHAR          * Get 2nd input from terminal
        CMPA    #$0D            * CR ?
        BEQ     SHIFT           * If cr then only on digit, shift
        CMPA    #$7F            * DEl ?
        BEQ     SETFLG          * If del then setflag, else contin
        STAA    PERCENT+1               * Save 2nd character
        JSR     INCHAR          * Need a cr to indicate # entered
        CMPA    #$0D            * cr ?
        BEQ     RETURN          * If cr then return, else continue
        CMPA    #$7F            * Del ?
        BEQ     SETFLG          * If del the setflag,else continue
*                               * Redisplay prompt, invalid # entered
        JSR     OUTCRLF         * Output crlf
        LDX     #SPDPRMT                * X points to message
        JSR     OTSTRGO         * Output message w/o preceeding cr
        BRA     IN_SPED         * Start again
SETFLG  BSET    FLAGS $02               * Set mode escape flag
        BRA     RETURN          * Branch to return from subroutine
SHIFT   LDAB    PERCENT                 * Only one digit, char into accb
        LDAA    #$20            * Ascii space into acca
        STD     PERCENT         * Store double at percent
RETURN  RTS

*
*BCD_HEX-       This subroutine takes the two bytes pointed to by X
*       as ascii two digit bcd number and converts to a hex equiv-
*       alent and returns the result in ACCA.
BCDHEX  LDAA    0,X             * Get hi byte of ascii bcd number
        CMPA    #$20            * If a space then only one digit
        BNE     TUDGITS         * not space then 2 digits
        LDAA    1,X             * Only one digit
        ANDA    #$0F            * Mask out the 4 msbs
        BRA     DONE            * result in acca so done
TUDGITS ANDA    #$0F            * Mask out the 4 msbs of hi byte
        LDAB    #$0A            * Ten into accb
        MUL                     * Acca*accb=accb(result of mul)
        LDAA    1,X             * Lo byte of ascii num into acca
        ANDA    #$0F            * Mask out the 4 msbs of lo byte
        ABA                     * acca+accb=hex number in acca
DONE    RTS

*MUL2BY1-       This subroutine multiplies a 2 byte number pointed to by
*       X by a 1byte number located in acca with the result stored
*       number located in ACCB with the result stored in location
*       TRIBYTS
MUL2BY1 PSHA                    * Save hex number on the stack
        LDAB    1,X             * Get low byte of period
        MUL                     * multiply
        STAB    TRIBYTS+2               * Lowest byte of total result
        PULB                    * Get copy of hex rep of %
        PSHA                    * To be added to next mul result
        LDAA    0,X             * Get high byte of period
        MUL                     * Multiply
        STD     TRIBYTS         * Store this result in TRIBYTS
        PULB                    * Part to be added to last mul
        CLRA                    * Hi byte of accd = 0
        ADDD    TRIBYTS         * Add accd to last mul result
        STD     TRIBYTS         * 24 bit result @ TRIBYTS
        RTS
*
*DIV3BYT-       This subroutine divides a 24 bit number pointed to by Y
*       by a number in X with the result to be in ACCD
*
DIV3BYT LDD     TRIBYTS         * Get upper 16 bits of dividend
        LDX     #$0064          * Load X with divisor
        IDIV                    * Divide
        PSHB                    * Save remainder
        XGDX                    * Put quotient in accb
        PULA                    * Remainder as hi byte in accd
        PSHB                    * Save hi byte of result
        LDAB    TRIBYTS+2               * Get last byte of dividend
        LDX     #$0064          * Load X with divisor
        IDIV                    * Divide
        XGDX                    * Quotient of 2nd div in accb
        PULA                    * Get hi byte of total result
*                               * Total result now in accd
        RTS

* OC1 INTERRUPT SERVICE ROUTINE
OC1ISR  LDX     #REGBAS         * Set for indexed addressing
        LDD     TOC1,X          * Get old OC1 time
        ADDD    PERIOD          * Add one period
        STD     TOC1,X          * Store next OC1 time
        BCLR    TFLG1,X %01111111       * Clear OC1 flag bit
        RTI

* OC2 INTERRUPT SERVICE ROUTINE
OC2ISR  LDX     #REGBAS         * Set for indexed addressing
        BRSET   FLAGS $80 NEWPW * bra if newspeed flag set
        LDD     TOC2,X          * Get old OC2 tim
        ADDD    PERIOD          * Add a period
        STD     TOC2,X          * Store next OC2 time
        BCLR    TFLG1,X %10111111       * Clear OC2 flag
        RTI
NEWPW   LDD     TOC1,X          * Use time for oc1 as reference
        ADDD    PERIOD          * Add a period
        ADDD    PERIOD          * Add a second period
        SUBD    PWIDTH          * Subtract pw % to get oc2
        STD     TOC2,X          * Store next oc2 time
        BCLR    FLAGS %10000000 * Clear newspeed flag
        BCLR    TFLG1,X %10111111       * Clear OC2 flag
        RTI
*
*menus
*
MODEMSG FCC     'ENTER OPERATION MODE: F1=AUTO, F2=MANUAL:'
        FCB     EOT
DIR_MSG FCC     'ENTER DIRECTION (F1=fwd, F2=rev): '
        FCB     EOT
SPDMSG  FCC     'PWM DUTY CYCLE %: '
        FCB     EOT
SPDPRMT FCC     'ENTER PWM DUTY CYCLE AS % (1-99): '
        FCB     EOT

corner
© 1996-2008 CommunityHeaven LLC. All rights reserved. Reproduction in whole or in part, in any form or medium without express written permission is prohibited.
Violators of this policy may be subject to legal action. Please read our Terms Of Use and Privacy Statement for more information.
North American business development: Nicolai Wadstrom. Publisher: Lars Hagelin.
Resource Listings