; ; ; Development code for servo control with RS232 comm to host PC ; Version 1 -- initial development ; ; PINOUTS: ; ; A0 - Status LED ; A1 - Input - RS232 input (receive) ; A2 - Output - RS232 output (transmit) ; A3 - NC ; A4 - NC ; B0-B7 - Servo control outputs ; ; ; processor 16F84 ;;;;;;;;;;;;;;;;;;;;;; ; Configuration word : bits 13-4 - 1 (code protection off) ;;;;;;;;;;;;;;;;;;;;;; bit 3 - 1 (power up timer disabled) ; bit 2 - 0 (watchdog timer disabled) ; bit 1,0 - 10 (HS oscillator) ; __config B'11111111111010' ; ; include "p16f84.inc" title "Variables *****************************************" RS232_delay_ctr equ 0x0c RS232_counter equ 0x0d RS232_datachar equ 0x0e temp equ 0x0f temp2 equ 0x10 temp3 equ 0x11 w_temp equ 0x12 ; ; servo positions ; pos0 equ 0x13 pos1 equ 0x14 pos2 equ 0x15 pos3 equ 0x16 pos4 equ 0x17 pos5 equ 0x18 pos6 equ 0x19 pos7 equ 0x1A curr_pos equ 0x1B servo_mask equ 0x1C ctr equ 0x1D servo_ctr equ 0x1E ; Used in ASCII conversion ASCIIO EQU 0x1F ASCIIT EQU 0x20 ASCIIH EQU 0x21 ;------------------------------------------------------------------ ; Assembler defines CR equ 0x0D LF equ 0x0A ;------------------------------------------------------------------ ; Reset vector ORG 0 goto main_code ;------------------------------------------------------------------ ; Interrupt vector ORG 4 _interrupt_vector ; Do absolutely nothing....no interrupts used end_interrupt retfie ; return from interrupt ;-------------------------------------------------------------------- ; Main program start main_code call main_init ; Beep LED 3 times movlw D'3' movwf temp3 ; temp3 = 3 init_led call beepled decfsz temp3, 1 ; temp3 = temp3 - 1 goto init_led bsf PORTA, 0 ; Turn LED on ; ; This is where all the fun begins... ; term_loop movlw 0x08 ; We're controlling 8 servos here! movwf servo_ctr ; Store this in the servo counter movlw 0x1A ; This is where the servo positions end in memory. movwf FSR ; Store in indirect register ; DEBUGGING ONLY!!! ; movlw 0x17 ; DEBUG!!! ; movwf FSR ; DEBUG!!! each_servo ; DEBUGGING ONLY!!! ; movlw D'4' ; movwf servo_ctr call configure_mask call do_single_servo ; Handle this single output ; DEBUGGING ONLY!!!!!!!!!!!!!!!!!!!!!!!! ; goto each_servo ; DEBUGGING decf FSR, 1 ; Decrement pointer decfsz servo_ctr, 1 ; Decrement the counter goto each_servo ; ; Delay for post processing after 8 servos (14ms) ; ; movlw D'14' movlw D'6' movwf temp call delay_ms goto term_loop ; Repeat main loop for each servo _main__end ;------------------------------------------------------------------ ; This will configure the bit mask that corresponds to the current servo ; Uses/modifies temp ; Output: servo_mask configure_mask clrf servo_mask ; servo_mask = 0 movf INDF, 0 ; Reference pointer to check servo[num] (position) btfsc STATUS, Z ; If it's zero, servo is off, so skip jump to end goto configure_mask_end ; Bail out with empty mask if value = 0 movf servo_ctr, 0 ; W <- servo_ctr movwf temp ; temp <- servo_ctr (via W) incf servo_mask, 1 ; servo_mask <- 1 configure_mask1 rlf servo_mask, 1 ; servo_mask = servo_mask << 1 decfsz temp, 1 ; temp-- goto configure_mask1 configure_mask_end return ;------------------------------------------------------------------ ; Does the processing for a single servo output do_single_servo movf servo_mask, W ; W <- servo_mask iorwf PORTB, 1 ; OR mask to PORTB to turn on current servo ; Note: If servo pos value == 0, mask should be set to 0 and servo won't be turned on ; Delay 1.25 ms call delay_baseon movf INDF, W ; W <- servo[num] movwf ctr ; Store in counter call stepfor comf servo_mask, 0 ; W <- ~servo_mask andwf PORTB, 1 ; PORTB = ~mask * PORTB (turn off current servo) movf INDF, W ; W <- servo[num] movwf ctr comf ctr, 1 ; Compliment...so (ctr = 255 - servo[num]) btfss STATUS, Z ; If ctr == 0, don't stepfor (it would cause problems!) call stepfor return ;------------------------------------------------------------------ ; Implements a "for" loop with ctr. Uses/modifies ctr. ; Total instructions used per iteration: 5 stepfor nop nop decfsz ctr, 1 goto stepfor return ;------------------------------------------------------------------ ; Delays for 1.25 ms, which is the base "on" time for a pulse ; 3125 instructions = 125 * 25 == (approx) 41 * 25 * 3 + (41*5) (= 3280) ; Uses temp and temp2 ; ; THIS ROUTINE WORKS...delay is closer to 1.3ms, but IT WORKS... ; MAYBE FINE TUNE WHEN CLOSER TO OVERALL SOLUTION ; DON'T QUESTION THIS ROUTINE FOR YOUR PROBLEMS. :) jp ; ; delay_baseon ; movlw D'41' movlw D'40' movwf temp ; 41 stored in temp delay_base_out movlw D'25' movwf temp2 delay_baseon_in decfsz temp2, 1 goto delay_baseon_in decfsz temp, 1 goto delay_base_out return ;------------------------------------------------------------------ ; Initialization for main program entry main_init ; ; basic register setup and pin i/o steup ; kind of stuff every prog requires ; clrwdt ; Clear watchdog timer bcf INTCON, GIE ; Clear interrupts bsf STATUS, RP0 ; Select bank 1 movlw 0x00 movwf TRISB ; Set TRISB to 0x00 (all output) movlw D'2' movwf TRISA ; Set TRISA to 0x02 (Pins 1 is input) bcf STATUS, RP0 ; Select bank0 back bcf PORTA, 0 ; Turn LED off bsf PORTA, 2 ; Set RS232 output to HIGH idle state ; ; set up initial servo positions ; movlw D'127' ; Initial servo position (should be 0 for production) movwf pos0 movwf pos1 movwf pos2 movwf pos3 movwf pos4 movwf pos5 movwf pos6 movwf pos7 ; Turn all servo outputs off clrf PORTB return ;------------------------------------------------------------------ ; beepled - Flashes LED on pin A0 on then off with short delays beepled bsf PORTA, 0 movlw D'250' movwf temp call delay_ms movlw D'250' movwf temp call delay_ms bcf PORTA, 0 movlw D'250' movwf temp call delay_ms movlw D'250' movwf temp call delay_ms return ;------------------------------------------------------------------ ; delay_ms - Delays for number of milliseconds in temp ; Uses/modifies temp2 ; Assumes 10MHz clock ; 29 * 0.0000001 * 4 * 86 = 0.0009976 sec delay_ms delay_ms_1 movlw D'86' movwf temp2 nop nop delay_ms_2 nop ; 1 nop ; 2 nop ; 3 nop ; 4 nop ; 5 nop ; 6 nop ; 7 nop ; 8 nop ; 9 nop ; 10 nop ; 11 nop ; 12 nop ; 13 nop ; 14 nop ; 15 nop ; 16 nop ; 17 nop ; 18 nop ; 19 nop ; 20 nop ; 21 nop ; 22 nop ; 23 nop ; 24 nop ; 25 nop ; 26 decfsz temp2, 1 ; +1 goto delay_ms_2 ; +2 --> Total = 29 nop decfsz temp, 1 goto delay_ms_1 nop return ;------------------------------------------------------------------ ; RS232_putchar - Sends a char via serial port on pin RA2 ; Uses true RS232 polarity ; Char is passed in reg W RS232_putchar movwf RS232_datachar ; Put w into storage byte movlw D'9' ; Put 9 into W movwf RS232_counter ; Put W into counter byte (10 bits = 1 start + 8 data + 1 stop) bcf PORTA, 2 ; Set pin RA2 low (start bit) nop nop RS232_1 call RS232_bitdelay ; Delay for the bit decfsz RS232_counter, 1 ; See if all bits sent (decrement counter) goto RS232_2 ; if not, jump ahead bsf PORTA, 2 ; Otherwise, set pin high for stop bit call RS232_bitdelay ; wait for bit delay return ; and return RS232_2 rrf RS232_datachar, 1 ; Rotate byte right through carry, store result in RS232_datachar btfss STATUS, C ; Bit test C, skip if set goto RS232_3 ; C not set (bit is a 0) bsf PORTA, 2 ; Set pin output to high goto RS232_1 ; Loop for next bit RS232_3 bcf PORTA, 2 ; Set output pin low C is set (bit is a 1) goto RS232_1 ; Loop for next bit return ;------------------------------------------------------------------ ; RS232_getchar - Receives a char via serial port on pin RA1 ; Uses true RS232 polarity ; Char is returned in W RS232_getchar movlw D'8' movwf RS232_counter ; _counter__c2c_getchar clrf RS232_datachar ; _ret__c2c_getchar RS232_getch1 btfsc PORTA, 1 goto RS232_getch1 call RS232_bitdelay2 ; __c2c_rs232_delay2 btfsc PORTA, 1 goto RS232_getch1 RS232_getch2 call RS232_bitdelay ;__c2c_rs232_delay rrf RS232_datachar, F ; _ret__c2c_getchar, F bcf RS232_datachar, 7 ; _ret__c2c_getchar, 7 btfsc PORTA, 1 ; Input on port A bsf RS232_datachar, 7 ; _ret__c2c_getchar, 7 decfsz RS232_counter, 1 ; _counter__c2c_getchar, 1 goto RS232_getch2 call RS232_bitdelay ; __c2c_rs232_delay movf RS232_datachar, W ; _ret__c2c_getchar, W ; movwf, inchar return ;------------------------------------------------------------------ ; RS232_bitdelay - Delays for a bit being sent over serial port ; Assumes 10MHz clock speed RS232_bitdelay movlw D'82' movwf RS232_delay_ctr RS232_bitdelay_1 decfsz RS232_delay_ctr, 1 goto RS232_bitdelay_1 return ;------------------------------------------------------------------ ; RS232_bitdelay2 - Delay used in receiving chars from serial port RS232_bitdelay2 movlw D'41' movwf RS232_delay_ctr RS232_bitdelay2_1 decfsz RS232_delay_ctr, 1 goto RS232_bitdelay2_1 return ;------------------------------------------------------------------ ; printcrlf - prints a CR+LF pair on the serial port ; Modifies: W, temp printcrlf movlw '\r' call RS232_putchar movlw '\n' call RS232_putchar return ;------------------------------------------------------------------ ; printbyte - Prints an 8-bit binary value in ASCII over the serial ; port. ; Input: temp ; Modifes: W, ASCIIH, ASCIIT, ASCIIO printbyte movf temp, 0 movwf ASCIIO call toascii movf ASCIIH, 0 call RS232_putchar movf ASCIIT, 0 call RS232_putchar movf ASCIIO, 0 call RS232_putchar return ;------------------------------------------------------------------ ; toascii - Converts an 8-bit binary value in ASCIIO to an ; ASCII 3-digit representation. ; Output: ASCIIH - hundredths, ASCIIT - tenths, ASCIIO - ones toascii MOVLW '0' MOVWF ASCIIH MOVWF ASCIIT DO100S MOVLW D'100' SUBWF ASCIIO,W BNC DO10S MOVWF ASCIIO INCF ASCIIH GOTO DO100S DO10S MOVLW D'10' SUBWF ASCIIO,W BNC ADJUST MOVWF ASCIIO INCF ASCIIT GOTO DO10S ADJUST MOVLW '0' ADDWF ASCIIO return END