; Filename: P.ASM ; ********************************************** ; * Home ball sculpture * ; * Revision: 1.2 * ; * Date 2/11-00 * ; * Part: 16F84-10 * ; * Fuses: OSC: RC * ; * WDT: OFF/ON (C84/F84) * ; * Compiled using MPASM V1.40 * ; ********************************************** ; * Include files: * ; * P16F84.INC * ; ********************************************************************** ; ********************************************************************** list p=16F84 radix dec include "..\..\pictools\mpasm\p16c84.inc" __FUSES _CP_OFF & _WDT_OFF & _RC_OSC & _PWRTE_ON ; ERRORLEVEL 1,-302 ; Turn OFF message ID 302 ;>>>>>>>>>>>>>>> | ; PROCEDURE LIFT | ;clear store | ; cnt cnt | ;TURN DETECTOR | ;|<--------|<-----------| ;|--------------------------->|-----|---------->| ; OUT ! move calculated !OUT/2! TOP_CORR | ; |..call DISP ;>>>>>>>>>>>>>>> | store clear ; PROCEDURE LIFT | cnt cnt ; | DETECTOR TURN ; |----------->|-------->| ; |<----------|-----|<---------------------------| ; | TOP_CORR !OUT/2! move calculated ! OUT ! ; | ; |..call DISP ;>>>>>>>>>>>>>>> | ; AT TOP | ; |<----------| ; | TOP_L ; |......................ball rolls to center position ; |------->| ; TOP_R1 |.............wait some minutes with ball at top ; |--------->| ; TOP_R2 | ; |..ball begins to roll ; |<------| ; |..........wait while ball rolls down ; ************************************ ; * Port B (RB0-RB7) bit definitions * ; ************************************ MOTOR0 EQU 0 ;Motor driver output MOTOR1 EQU 1 ;Motor driver output MOTOR2 EQU 2 ;Motor driver output POS_DET EQU 3 ;Position detector SOUND EQU 4 ;Sound driver output Unused2 EQU 5 Unused3 EQU 6 BUTTON EQU 7 ;Push-button RBTRIS EQU 0E8h ; RBINIT EQU 000h ; M_LEDON EQU 0F7h M_BEEP EQU 010h ; ************************************ ; * Constants * ; ************************************ ; 3 steps corresponds to 1 mm (30 steps=1 cm) INIT_H EQU 0x08 ;Initial left/right movement MAX_H EQU 0x40 ;Maximum movement before ERROR set OUT_L EQU 0x60 ;Extra movement at end TOP_L_L EQU 0x60 ;Left tilt at top to ensure ball falls down TOP_R_L EQU 0x20 ;Right tilt at top to ensure ball falls down TOP_R1_L EQU 0x20 ;Right tilt at top before wait TOP_R2_L EQU 0x60 ;Right tilt at top to ensure ball begins to roll TOP_CORR_L EQU 0x32 ;Extra move at top center to correct for unsymmetry START_L_L EQU 0x60 ;Extra tilt at center start START_R_L EQU 0x20 ;Steps per back tilt at start START_NB EQU 0x08 ;Number of back steps ; ************************************ ; * Flag variable bits * ; ************************************ B_BUTON EQU 00h ;Button is pressed in now B_BUTPRESS EQU 01h ;Button has been pressed B_FAST EQU 02h ;Move fast B_RIGHT EQU 03h ;Move in right direction B_SENSE EQU 04h ;Break on magnet sensor B_TEST EQU 05h ;Test mode on M_DIRECTION EQU 0x08 ;Mask with 1 in B_RIGHT bit M_SPEEDTEST EQU 0x24 ;Mask with 1 in B_SPEED and B_TEST ; ************************************ ; * Variables * ; ************************************ FLAGS EQU 10h MSTATE EQU 11h ;Motor state, 0-3 DWAIT1MS EQU 12h DWAIT100MS EQU 13h DWAIT1M EQU 14h C256MS EQU 15h N_DISP EQU 16h ;Counter within display routing N_LIFT EQU 17h ;Counts number of lifts N_MOV_L EQU 1Ah ;Max moves before return N_MOV_H EQU 1Bh N_CNT_L EQU 1Ch ;Running count of moves N_CNT_H EQU 1Dh N_TOT_L EQU 1Eh ;(All the way round) + (OUT_L) N_TOT_H EQU 1Fh N_BEEP EQU 20h N_MOVWAIT EQU 21h ;Random wait counter N_TOPWAIT EQU 22h ; ************************************ ; * Reset vector * ; ************************************ org 0x000 ; Reset vector location goto Start ; Begining of Program ; ************************************ ; * Interrupt vector and routine * ; ************************************ org 0x004 ; Interupt vector location IntRoutine clrwdt ; Clear watchdog timer retfie ; End of interrupt routine ; ************************************ ; * START * ; ************************************ Start ;** Initialise port B movlw RBINIT movwf PORTB ;** Initialise RBTRIS in bank 1 bsf STATUS,RP0 movlw RBTRIS movwf TRISB ;** Initialise OPTION reg in bank 1 movlw 0x87 movwf OPTION_REG bcf STATUS,RP0 ;** Initialise INTCON movlw 0x00 movwf INTCON ;** Initialise program variables clrf FLAGS clrf MSTATE clrf N_MOVWAIT ;;** Check for test mode call WAIT100MS btfss PORTB, BUTTON bsf FLAGS, B_TEST call WAIT1S call WAIT1S call WAIT1S call WAIT1S call WAIT1S call BEEP ;*********************************************************** ;** INITIAL WHEEL MOVEMENT ********************************* ;** Make ready bsf FLAGS, B_FAST clrf N_CNT_H clrf N_MOV_L ;** Move a bit to the left movlw INIT_H movwf N_MOV_H call MOVE call FWAIT1S ;** Move twice as much to the right bsf FLAGS, B_RIGHT movlw INIT_H * 2 movwf N_MOV_H call MOVE call FWAIT1S ;** Move a bit to the left again bcf FLAGS, B_RIGHT movlw INIT_H movwf N_MOV_H call MOVE call FWAIT1S ;** Position is now guaranteed to be "between" ;** Set circumference estimate and position to zero clrf N_TOT_H clrf N_TOT_L clrf N_CNT_H clrf N_CNT_L ;** Two calls to LIFT will calibrate circumference (N_MAX) clrf N_LIFT incf N_LIFT, F call LIFT incf N_LIFT, F call LIFT ;** Is now close to center position ;** Now move a little more so the ball falls bcf FLAGS, B_SENSE movlw START_L_L movwf N_MOV_L clrf N_MOV_H call MOVE call FWAIT1S ;** Turn movlw M_DIRECTION xorwf FLAGS, F call WAIT100MS ;** Now move back in steps, and let ball roll in between movlw START_NB movwf N_LIFT L_TB movlw START_R_L movwf N_MOV_L clrf N_MOV_H call MOVE movlw .10 movwf N_TOPWAIT L_RD call WAIT1S decfsz N_TOPWAIT, F goto L_RD decfsz N_LIFT, F goto L_TB ;** Ball should now be at bottom ;*********************************************************** ;** ETERNAL LOOP STARTS HERE ******************************* L_LIFT ;** Slow if not test mode bcf FLAGS, B_FAST btfsc FLAGS, B_TEST bsf FLAGS, B_FAST ;** Lift seven times to reach top clrf N_LIFT incf N_LIFT, F call LIFT incf N_LIFT, F call LIFT incf N_LIFT, F call LIFT incf N_LIFT, F call LIFT incf N_LIFT, F call LIFT incf N_LIFT, F call LIFT incf N_LIFT, F call LIFT ;** At top, move a little more movlw TOP_L_L movwf N_MOV_L clrf N_MOV_H call MOVE ;** Turn bsf FLAGS, B_RIGHT call FWAIT1S ;** Move a little back movlw TOP_R1_L movwf N_MOV_L clrf N_MOV_H call MOVE call FWAIT1S ;** Ball is now at top centre, wait some minutes movlw .10 movwf N_TOPWAIT L_TW call WAIT1M decfsz N_TOPWAIT, F goto L_TW ;** Finished waiting ; call BEEP ;** Now move slowly in steps, and let ball roll movlw .6 movwf N_TOPWAIT L_TR movlw TOP_R_L movwf N_MOV_L clrf N_MOV_H call MOVE call WAIT15S decfsz N_TOPWAIT, F goto L_TR ;** Turn and long wait bsf FLAGS, B_RIGHT movlw .5 movwf N_TOPWAIT L_BW1 call WAIT1M decfsz N_TOPWAIT, F goto L_BW1 ;--;** After wait move a little more ;-- movlw TOP_R2_L ;-- movwf N_MOV_L ;-- clrf N_MOV_H ;-- call MOVE ;-- call FWAIT1S ;--;** Move back, while the ball rolls down ;-- bcf FLAGS, B_RIGHT ;-- movlw TOP_R1_L + TOP_R2_L - TOP_L_L ;-- movwf N_MOV_L ;-- clrf N_MOV_H ;-- call MOVE ;-- call FWAIT1S ;--;** Turn and long wait while ball rolls and at the bottom ;-- bsf FLAGS, B_RIGHT ;-- movlw .5 ;-- movwf N_TOPWAIT ;--L_BW1 call WAIT1M ;-- decfsz N_TOPWAIT, F ;-- goto L_BW1 ;--;** Also some seconds, since minute wait is short in fast mode ;-- movlw .10 ;-- movwf N_TOPWAIT ;--L_BW2 call WAIT1S ;-- decfsz N_TOPWAIT, F ;-- goto L_BW2 ;** Loop goto L_LIFT ;** ETERNAL LOOP ENDS HERE ********************************* ;*********************************************************** ERR_MOVE ;** bsf FLAGS, B_RIGHT call WAIT1S call MRIGHT bcf FLAGS, B_RIGHT call WAIT1S call MLEFT goto ERR_MOVE ;******************************** MDRIVE ;Get motor driver data ;******************************** ;** This code must reside in the first 255 words of memory ;** since the upper bits of the program counter are loaded ;** from PCLATH when adding to PCL. ;** Turn off motor current movlw 0f8h andwf PORTB, F ;** Constrain MSTATE (array index) to 0-3 movlw 03h andwf MSTATE, F ;** Array lookup MSTATE is index movf MSTATE, W addwf PCL, F ;** Array contents, the four driver output values retlw 1 retlw 4 retlw 6 retlw 3 ;******************************** LIFT ;******************************** ;** Move from center to end bsf FLAGS, B_SENSE movlw MAX_H + 2 movwf N_MOV_H call MOVE call FWAIT1S ;** Sensor has trigged now store circumference movf N_CNT_H, W movwf N_TOT_H movf N_CNT_L, W movwf N_TOT_L ;** Now move a little more bcf FLAGS, B_SENSE movlw OUT_L movwf N_MOV_L clrf N_MOV_H call MOVE call FWAIT1S ;** Turn movlw M_DIRECTION xorwf FLAGS, F call WAIT100MS ;** Clear circumference counter clrf N_CNT_L clrf N_CNT_H ;** Calculate length and move to OUT_L/2 before center bcf STATUS, C rrf N_TOT_H, W movwf N_MOV_H rrf N_TOT_L, W movwf N_MOV_L call MOVE call FWAIT1S ;** ############Move to center and an empirical value extra movlw (OUT_L / 2) + TOP_CORR_L ; movlw TOP_CORR_L movwf N_MOV_L clrf N_MOV_H call MOVE movf N_LIFT, W ;** Display (light and sound) call DISP ;** Finished return ;******************************** MOVE ;Step motor ;******************************** ;** Position sensor. ;** Return if break on sensor set and sensor trigged. L_MS btfss FLAGS, B_SENSE goto L_M0 btfss PORTB, POS_DET return ;** Increment 16 bit counter L_M0 incf N_CNT_L, F btfsc STATUS, Z incf N_CNT_H, F ;** Check counter. ERROR if high byte=MAX_H movf N_CNT_H, W sublw MAX_H btfsc STATUS, Z goto ERR_MOVE ;** Move motor. Right or left movement. btfsc FLAGS, B_RIGHT decf MSTATE, F btfss FLAGS, B_RIGHT incf MSTATE, F call MDRIVE iorwf PORTB, F ;** Check for short or long wait. btfsc FLAGS, B_FAST goto L_M1 ;** Long waits movlw .15 movwf N_MOVWAIT L_MW call WAIT10MS decfsz N_MOVWAIT, F goto L_MW ;** Fast mode short waits L_M1 call WAIT10MS call WAIT10MS ;** Return if programmed move count reached (N_MOV_L/H=0) movf N_MOV_L, F btfss STATUS, Z goto L_M2 movf N_MOV_H, F btfsc STATUS, Z return ;** Decrement counter decf N_MOV_H, F L_M2 decf N_MOV_L, F ;** Loop end goto L_MS ;******************************** MOFF ;Turn motor driver off ;******************************** movlw 0f8h andwf PORTB, F return ;******************************** MRIGHT ;Turn motor one step right ;******************************** incf MSTATE, F ;Next state call MDRIVE ;Get driver output value iorwf PORTB, F ;Set outputs return ;******************************** MLEFT ;Turn motor one step left ;******************************** decf MSTATE, F ;Next state call MDRIVE ;Get driver output value iorwf PORTB, F ;Set outputs return ;******************************** DISP ;******************************** movwf N_DISP ;** Pull button output low to light diode movlw M_LEDON andwf PORTB, F ;** TRISB register is in bank 1 L_DIS bsf STATUS,RP0 bcf TRISB, POS_DET bcf STATUS,RP0 ;** Wait a bit call WAIT100MS call WAIT100MS ;** Release button output ;** TRISB register is in bank 1 bsf STATUS,RP0 bsf TRISB, POS_DET bcf STATUS,RP0 call WAIT100MS call WAIT100MS call BEEP ;** Loop counter decfsz N_DISP, F goto L_DIS return ;******************************** BEEP ;******************************** return movlw .255 movwf N_BEEP L_BEEP movlw M_BEEP xorwf PORTB, F nop nop nop nop nop nop nop nop nop nop nop nop decfsz N_BEEP, F goto L_BEEP return ;******************************** WAIT1MS ;******************************** ;** Number of loops, empirical constant movlw .67 movwf DWAIT1MS ;** Wait loop W1MSA decfsz DWAIT1MS, F goto W1MSA ;** Every 256 ms (every 256-th time this routine is called) ... decfsz C256MS, F return ;** ... do this: ;** B_BUTON follows push button state. ;** Set B_BUTPRESS whenever the button is released. btfss PORTB, BUTTON goto W1B_BUTON btfss FLAGS, B_BUTON return bcf FLAGS, B_BUTON bsf FLAGS, B_BUTPRESS ;* In current version the button is only used to flip mode movlw M_SPEEDTEST xorwf FLAGS, F bcf FLAGS, B_BUTPRESS return W1B_BUTON bsf FLAGS, B_BUTON return ;******************************** WAIT10MS ;******************************** movlw .10 movwf DWAIT100MS W10MA call WAIT1MS decfsz DWAIT100MS, F goto W10MA return ;******************************** WAIT100MS ;******************************** movlw .100 movwf DWAIT100MS W100MA call WAIT1MS decfsz DWAIT100MS, F goto W100MA return ;******************************** WAIT1S ;******************************** movlw .250 movwf DWAIT100MS W1SA call WAIT1MS decfsz DWAIT100MS, F goto W1SA movlw .250 movwf DWAIT100MS W1SB call WAIT1MS decfsz DWAIT100MS, F goto W1SB movlw .250 movwf DWAIT100MS W1SC call WAIT1MS decfsz DWAIT100MS, F goto W1SC movlw .250 movwf DWAIT100MS W1SD call WAIT1MS decfsz DWAIT100MS, F goto W1SD return ;******************************** FWAIT1S ;******************************** ;** Wait only if FAST mode btfsc FLAGS, B_FAST call WAIT1S ; movlw .1 ; call DISP return ;******************************** WAIT15S ;******************************** movlw .15 goto W1MS ;******************************** WAIT1M ;******************************** ;** Wait 1 second instead of 1 min if test mode set movlw .60 btfsc FLAGS, B_TEST movlw .1 W1MS movwf DWAIT1M W1MA call WAIT1S decfsz DWAIT1M, F goto W1MA return END