;Shawn Lankton ;Ryan Westafer ;RESET ; ;;;;;;; FINAL PROJECT for QwikFlash board ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Recieves 50kb/s UART signal from 676 chip. When information is recieved, it ; is used to look up the correct ascii code and output it to the LCD. ; ;;;;;;; Program hierarchy ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Mainline ; Initial ; LCDinitialize ; LoopTime ; LCDnibble ; BlinkAlive ; Step ; LoopTime ; ; HiPriISR ; KeyboardTranslate ; LCDbyte ; LCDnibble ; T40 ; ;;;;;;; Assembler directives ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; list P=PIC18F452, F=INHX32, C=160, N=0, ST=OFF, MM=OFF, R=DEC, X=ON #include P18F452.inc __CONFIG _CONFIG1H, _HS_OSC_1H ;HS oscillator __CONFIG _CONFIG2L, _PWRT_ON_2L & _BOR_ON_2L & _BORV_42_2L ;Reset __CONFIG _CONFIG2H, _WDT_OFF_2H ;Watchdog timer disabled __CONFIG _CONFIG3H, _CCP2MX_ON_3H ;CCP2 to RC1 (rather than to RB3) __CONFIG _CONFIG4L, _LVP_OFF_4L ;RB5 enabled for I/O ;;;;;;; Variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; cblock 0x000 ;Beginning of Access RAM ALIVECNT ;Counter for blinking "Alive" LED STEPCNT ;Counter for stepping stepper motor DARNITJOHNTEMP ;variable that john used BINARYDISPLAYCNT ;variable to display 8 bits only DISPLAYVCNT ;counts the appropriate number of bytes HALFSECONDCNT ;count for flashing LED on reset GETBITSCNT ;count to ensure that 8 bits are captured DISPLAYSTUFFFLAG ;flag that tells the Mainline when to display stuff INDEXPASS ;pass the index in this variable DMESSAGE:16 ;10 byte message buffer LCDPTR ;LCD position pointer endc ;;;;;;; Macro definitions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MOVLF macro literal,dest movlw literal movwf dest endm POINT macro address MOVLF high address, TBLPTRH MOVLF low address, TBLPTRL endm INCF1 macro movff INDF1, POSTINC1 endm INCF2 macro movff INDF2, POSTINC2 endm ;;;;;;; Vectors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; org 0x0000 ;Reset vector goto Mainline org 0x0008 ;High priority interrupt vector goto HiPriISR ;High priority interrupt handler org 0x0018 ;Low priority interrupt vector goto $ ;trap ;;;;;;; Mainline program ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Mainline rcall Initial ;Initialize everything rcall LCDinitialize ;Initialize the LCD LOOP_ rcall BlinkAlive ;Blink "Alive" LED rcall Step ;Deal with stepper motor rcall LoopTime ;Make looptime be ten milliseconds ENDLOOP_ ;;;;;;; Mainline does not return ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;; Initial subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine performs all initializations of variables and registers. Initial MOVLF B'10001110',ADCON1 ;Enable PORTA & PORTE digital I/O pins MOVLF B'11100001',TRISA ;Set I/O for PORTA MOVLF B'11001100',TRISB ;Set I/O for PORTB ; modified for P5 MOVLF B'11010010',TRISC ;Set I/O for PORTC ; modified for P5 MOVLF B'00001111',TRISD ;Set I/O for PORTD MOVLF B'00000100',TRISE ;Set I/O for PORTE MOVLF B'10001000',T0CON ;Set up Timer0 (10 millisecond looptime) MOVLF B'10001001',T3CON ;Set up Timer3 (capture rising edges) MOVLF B'00000100',CCP2CON ;Set up CCP2: capture falling edge (start bit) MOVLF 250,ALIVECNT MOVLF 2,STEPCNT ;constant to be counted to delay step clrf DISPLAYSTUFFFLAG ;zero the display stuff flag clrf LCDPTR ;zero the LCD position pointer bsf RCON,IPEN ;enable HiPri Interupts bsf INTCON,GIEH ;Global interrupt enable bsf IPR2,CCP2IP ;setup HiPri bsf PIE2, CCP2IE ;start looking for falling edge return ;;;;;;; LCDinitialize subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Initialize the Optrex 8x2 character display. ; First wait for 0.1 second, to get past display's power-on reset time. InitLCDstr db 0x33,0x32,0x28,0x01,0x0c,0x06,0x80,0x00 ;String of commands needed to initialize LCD LCDinitialize MOVLF 10,DARNITJOHNTEMP ;Wait 0.1 second REPEAT_ call LoopTime ;Call LoopTime ten times decf DARNITJOHNTEMP,F UNTIL_ .Z. bcf PORTE,RE0 ;RS=0 for command MOVLF high InitLCDstr, TBLPTRH ;Load indirect addressing pointer MOVLF low InitLCDstr, TBLPTRL tblrd* ;Read from string into TABLAT REPEAT_ movf TABLAT,W ;Copy byte to WREG call LCDnibble ;Send upper nibble call LoopTime ;Wait ten milliseconds swapf TABLAT,W call LCDnibble ;Send lower nibble call LoopTime ;Wait ten milliseconds tblrd+* ;Increment pointer and get next byte movf TABLAT,F ;Is it zero? UNTIL_ .Z. bsf PORTE, RE0 ;RS=1 for end of commands return ;;;;;;; BlinkAlive subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine briefly blinks the LED next to the PIC every two-and-a-half ; seconds. BlinkAlive bsf PORTA,RA4 ;Turn off LED decf ALIVECNT,F ;Decrement loop counter and return if not zero IF_ .Z. MOVLF 250,ALIVECNT ;Reinitialize BLNKCNT bcf PORTA,RA4 ;Turn on LED for ten milliseconds every 2.5 sec ENDIF_ return ;;;;;;; Step subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine drives the UCN5804B stepper motor controller's Step input ; low every fourth loop time, i.e., every 40 milliseconds. ; This produces a steprate of 25 steps/second. ; The stepper steps 48 steps/revolution. Step bsf PORTB,RB4 ;Drive Step input high (if not already high) bcf PORTB,RB4 ;Drive Step input low return ;return ;;;;;;; LoopTime subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine waits for TMR0 to roll over from 65535 to 00000 and to set the ; TMR0IF flag. Then it resets TMR0 to 65536-25000 = 40536 to make TMR0 count ; with a scale of about 25000. LoopTime REPEAT_ UNTIL_ INTCON, TMR0IF == 1 ;wait until ten milliseconds are up bcf INTCON,TMR0IF ;Clear flag MOVLF high 40536,TMR0H ;Skip over 40536 counts MOVLF low 40536,TMR0L return ;;;;;;; DisplayV Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Prints a string of 16 bytes (held in DMESSAGE) to the LCD on the appropriate line DisplayV lfsr 1, DMESSAGE ;load FSR1 with DMESSAGE MOVLF 1, DISPLAYVCNT ;move value into DISPLAYCNT to use as counter REPEAT_ movff POSTINC1, INDEXPASS ;grab next DMESSAGE byte call KeyboardTranslate ;translate byte and print it decf DISPLAYVCNT,F ;decrement counter UNTIL_ .Z. return ;;;;;;; LCDbyte Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Sends a byte to the LCD one nibble at a time ; WRAPPING is now handled for 2x8 display LCDbyte call LCDnibble ;send upper nibble swapf WREG, W call LCDnibble ;send lower nibble call T40 ;wait 40 microseconds incf LCDPTR, F ;maintain LCD wrap pointer movf LCDPTR, W addlw -8 ;have we put 8 bytes? IF_ .Z. ;if time to wrap, do so bcf PORTE,RE0 ;RS=0 for command movlw 0xc0 ;cursor position code for second line call LCDnibble ;send upper nibble swapf WREG, W call LCDnibble ;send lower nibble call T40 ;wait 40 microseconds bsf PORTE,RE0 ;RS=1 for finish command ELSE_ addlw -8 ; 8+8=16 bytes IF_ .Z. clrf LCDPTR ;reinitialize LCD wrap pointer bcf PORTE,RE0 ;RS=0 for command movlw 0x80 ;cursor position code for first line call LCDnibble ;send upper nibble swapf WREG, W call LCDnibble ;send lower nibble call T40 ;wait 40 microseconds bsf PORTE,RE0 ;RS=1 for finish command ENDIF_ ENDIF_ return ;;;;;;; LCDnibble Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Sends a nibble to the LCD LCDnibble bsf PORTE, RE1 ;Drive E pin high movwf PORTD ;Send it bcf PORTE, RE1 ;Drive E low so LCD will process input return ;;;;;;; T40 Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine creates a delay of about 40 us (100 cycles) T40 movlw 32 REPEAT_ decf WREG, W UNTIL_ .Z. ;burn 3 cycles * 32 loops return ;;;;;;; KeyboardTranslate Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine translates make codes into real ascii using a table KeyboardTranslate POINT SCT ;sets table pointer to scan code table movf INDEXPASS,W ;puts index in WREG addlw -21 ;subtract hex 15 to get on our index IF_ .B. ;byte was too low, set it to '!' movlw 2 ELSE_ addlw -105 IF_ .NB. ;byte was too high, set it to '!' movlw 2 ELSE_ movf INDEXPASS, W ;byte was just right, hot dog! addlw -21 ENDIF_ ENDIF_ addwf TBLPTRL, F ;two byte add IF_ .C. incf TBLPTRH, F ENDIF_ tblrd* ;read info out of table movf TABLAT, W call LCDbyte return ;;;;;;; High Priority Interrupt Handler ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Handle interrupts for UART recieving, interrupt generated on the falling edges. ; HiPriISR movlw 75 ;move 75 clockcycles for 50 us addwf CCPR2L, F ;add 75 to CCP2L clrf WREG ;remove values in W addwfc CCPR2H, F ;add carry bit to CCPR2H MOVLF B'00001010', CCP2CON ;setup CCP2 for compare mode lfsr 2, DMESSAGE ;setup indirect addressign pointer MOVLF 8, GETBITSCNT ;set the loop correctly to get 8 bits bcf PIR2,CCP2IF ;Clear flag that caused interrupt REPEAT_ ;Do 8 bits REPEAT_ UNTIL_ PIR2,CCP2IF == 1 ;burn time until the first bit bcf PIR2, CCP2IF ;clear the compare bit IF_ PORTC,RC1 == 1 ;if transmitted bit is high bsf STATUS,C ;set the carry bit ELSE_ bcf STATUS,C ;clears the carry bit ENDIF_ rrcf INDF2, F ;rotate carry bit into DMESSAGE movlw 50 ;correct number of cycles to wait for next test addwf CCPR2L, F ;add 50 to CCPR2H:CCPR2L clrf WREG addwfc CCPR2H, F decf GETBITSCNT, F ;got a bit, decriment UNTIL_ .Z. movff DMESSAGE, INDEXPASS rcall KeyboardTranslate MOVLF B'00000100',CCP2CON ;Set up CCP2: capture falling edge (start bit) bcf PIR2, CCP2IF retfie FAST ; Return from High Priority interrupt ;;;;BIG UGLY TABLE SCT db a'Q',a'1' ;scan codes in order with associated ascii.... we rule! db a'!',a'!' db a'!',a'Z' db a'S',a'A' db a'W',a'2' db a'!',a'!' db a'C',a'X' db a'D',a'E' db a'4',a'3' db a'!',a'!' db a' ',a'V' db a'F',a'T' db a'R',a'5' db a'!',a'!' db a'N',a'B' db a'H',a'G' db a'Y',a'6' db a'!',a'!' db a'!',a'M' db a'J',a'U' db a'7',a'8' db a'!',a'!' db a',',a'K' db a'I',a'O' db a'0',a'9' db a'!',a'!' db a'.',a'/' db a'L',0x3b db a'P',a'-' db a'!',a'!' db a'!',0x27 db a'!',a'[' db a'=',a'!' db a'!',a'!' db a'!',a'!' db a']',a'!' db a'!',a'!' db a'!',a'!' db a'!',a'!' db a'!',a'!' db a'!',a'!' db a'!',a'!' db a'1',a'!' db a'4',a'7' db a'!',a'!' db a'!',a'0' db a'.',a'2' db a'5',a'6' db a'8',a'!' db a'!',a'!' db a'+',a'3' db a'-',a'*' db a'9',a'!' ; END OF FILE end