;********************************************************************** ;Template: 84temp.asm * ; * ; * ; buggy1.asm * ; * ; version 0.1 * ; * ; DJW 8-8-98 * ; * ; Experiments with interrupt-based pwm on 2wd buggy * ; * ;********************************************************************** list p=16F84 ; list directive to define processor #include ; processor specific variable definitions __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC ; ************* ; CONSTANTS ; ************* tmr0_preset EQU d'155' ; count preset for TMR0 = 255 - (interrupt period in m/c cycles) pwm_cycle EQU d'100' ; no of TMR0 interrupts per pwm cycle tim1_cycle EQU d'100' ; no of TMR0 interrupts per timer1 cycle (100 => 0.01s) ; ************* ; VARIABLES ; ************* ;General w_temp EQU 0x0C ; variables used for context saving status_temp EQU 0x0D ; ;PWM System pwm_count EQU 0x0E ; interrupt count for pwm cycle left_count EQU 0x0F ; interrupt count for left motor on-pulse right_count EQU 0x10 ; interrupt count for right motor on-pulse left_speed EQU 0x11 ; required pulse width for left motor (no of interrupts) right_speed EQU 0x12 ; required pulse width for right motor (no of interrupts) ;General Purpose Timer(s) timer1 EQU 0x11 ; Timer1 value tim1_count EQU 0x12 ; TMR0 interrupt count for timer1 cycle ; ************************ ; I/O PORT ASSIGNMENTS ; ************************ ;Port A ;Port B left_drive EQU 0 left_direction EQU 1 right_drive EQU 2 right_direction EQU 3 test1 EQU 4 ; **************** ; ENTRY POINTS ; **************** ;Processor Startup/Reset Entry Point ORG 0x000 ; processor reset vector goto main ; go to beginning of program ;Interrupt Entry Point ORG 0x004 ; interrupt vector location movwf w_temp ; save off current W register contents movf STATUS,w ; move status register into W register movwf status_temp ; save off contents of STATUS register call TimerInterruptHandler ; service the interrupt movf status_temp,w ; retrieve copy of STATUS register movwf STATUS ; restore pre-isr STATUS register contents swapf w_temp,f swapf w_temp,w ; restore pre-isr W register contents retfie ; return from interrupt ; **************** ; MAIN PROGRAM ; **************** main ;Set Up I/O Ports clrf PORTA clrf PORTB bsf STATUS,RP0 ; select bank 1 movlw b'00000000' ; port A all o/p movwf TRISA movlw b'00000000' ; port B all o/p movwf TRISB bcf STATUS,RP0 ; select bank 0 movlw b'10101010' movwf PORTA movwf PORTB goto stop ;Initialise Motor Control System ;(Port B initially clear, so both motors off and forward) movlw pwm_cycle ; movwf pwm_count ; init pwm system clrf left_speed ; and set clrf left_count ; pulse widths clrf right_speed ; to zero clrf right_count ; ;Initialise Software Timers movlw tim1_cycle ; set movwf tim1_count ; timer1 clrf timer1 ; inactive ;Initialise Interrupts bsf STATUS,RP0 ; select bank 1 bsf OPTION_REG,PSA ; no pre-scale bcf OPTION_REG,T0CS ; internal clock bcf STATUS,RP0 ; select bank 0 movlw tmr0_preset ; movwf TMR0 ; pre-set interrupt clock clrf INTCON ; everything off bsf INTCON,T0IE ; TMR0 int enabled bsf INTCON,GIE ; interrupts on ;Control Buggy ; forward, half speed, 1 sec ; stop 2 secs ; reverse, half speed, 1 sec ; stop 2 secs ; forward, full speed, 1 sec ; stop 2 secs ; reverse, full speed, 1 sec ; stop 2 secs ;Test prog start bsf PORTB,left_direction ; set both motors reverse bsf PORTB,right_direction movlw d'50' ; set both speed controls for 50% movwf left_speed movwf right_speed movlw d'100' ; set timer 1 for 1 sec movwf timer1 wait1 movf timer1,F ; and wait for timeout btfsc STATUS,Z goto wait1 bcf PORTB,left_direction ; set both motors forward bcf PORTB,right_direction movlw d'00' ; set both speed controls for 0% movwf left_speed movwf right_speed movlw d'100' ; set timer 1 for 1 sec movwf timer1 wait2 movf timer1,F ; and wait for timeout btfsc STATUS,Z goto wait2 goto start ; and start all over again stop goto stop ; wait here for ever (or until reset...) ; *************** ; SUBROUTINES ; *************** ; ****************** ; INTERRUPT CODE ; ****************** ; Called from general interrupt handler which looks after context & retfie TimerInterruptHandler ; come here on each TMR0 interrupt ; reset timer for next interval & clear flag movlw tmr0_preset movwf TMR0 bcf INTCON,T0IF ; service motor PWM cycle decfsz pwm_count,F ; decrement pwm interrupt count goto pwm_off ; and if not 0 then skip to pulse length checks movlw pwm_cycle ; zero, so end of pwm cycle movwf pwm_count ; reload cycle count movlw left_speed ; reload left motor movwf left_count ; pulse width btfsc STATUS,Z ; and if it is not 0 then bsf PORTB,left_drive ; turn the left motor on movlw right_speed ; reload right motor movwf right_count ; pulse width btfsc STATUS,Z ; and if it is not 0 then bsf PORTB,right_drive ; turn the right motor on goto tim1 ; pwm done so go to timer ; check for ends of motor drive pulses pwm_off decf left_count,F ; decrement count for left motor btfsc STATUS,Z ; check if it is zero bcf PORTB,left_drive ; and if it is then turn left motor off decf right_count,F ; decrement count for right motor btfsc STATUS,Z ; check if it is zero bcf PORTB,right_drive ; and if it is then turn right motor off ; General Purpose Timer ; If timer is active (ie timer1 <> 0) then the interrupt count is decremented ; on every TMR0 interrupt. ; When interrupt count gets to 0 timer1 is decremented and ; interrupt count is reset to the constant tim1_cycle. ; When timer is inactive (ie timer1 = 0) the interrupt routine does nothing and ; the count remains at tim1_cycle. ; Timer is restarted by a higher level routine setting timer1 to non-zero ; tim1 movf timer1,F ; check if timer active btfsc STATUS,Z ; and if not goto tmr_ex ; then exit decfsz tim1_count,F ; timer active so decrement timer interrupt count goto tmr_ex ; and if not yet zero then exit movlw tim1_cycle ; timer active and count=0, so movwf tim1_count ; reload counter decf timer1,F ; and update (ie decrement) timer tmr_ex return end