#include ;#include "banks.inc" ; This header file defines configurations, registers, and other useful ; bits of information for the PIC18F4550 microcontroller. These names ; are taken to match the data sheets as closely as possible. CONFIG WDT = OFF; Disable watchdog timer CONFIG MCLRE = ON; MCLEAR Pin on CONFIG DEBUG = OFF; disable Debug Mode CONFIG LVP = OFF; Low-Voltage programming disabled CONFIG FOSC = HSPLL_HS; HS oscillator, PLL enabled, HS used by USB CONFIG PBADEN = OFF; PORTB<4:0> pins are configured as digital I/O on Reset CONFIG VREGEN = ON ; USB voltage regulator enabled CONFIG PLLDIV = 5 ; PLL prescaler Divide by 5 (20 MHz oscillator input) CONFIG USBDIV = 2 ; USB clock source comes from the 96 MHz PLL divided by 2 CONFIG CP0 = ON ; Code Protect CONFIG CP1 = ON CONFIG CP2 = ON CONFIG CPB = ON ; Boot Sect Code Protect CONFIG CPD = OFF ; EEPROM Data Protect CONFIG WRT0 = OFF ; Table Write Protect CONFIG WRT1 = OFF CONFIG WRT2 = OFF CONFIG WRTB = ON ; Boot Table Write Protest ;--------------------scales.ASM------------------------ ; robot test - checks function of forward movement ;for the pic18f4550 20Mhz -> 4Mhz -> 100Mhz processor ;------------------------------------------------------ ; Edwin Armstrong AKA (efa) ;------------------------------------------------------ ; 03/10/09 Modified code to work with pic 18F4550 procesor (efa) ; 01/24/10 Added test code for LCD (efa) ; 02/15/10 Added and tested sound, needs work... (efa) ;------------------------------------------------------ list p=18f4550 ;------------------------------------------------------- ; setup equates for ram memory -- Pic16f648: 0x20 to 0x7F (in bank 0), 0xA0 to 0xEF (in bank 1), ; 0x120 to 0x16F (in bank 2). 256 total ram count equ 0x20 ocount equ 0x21 ncount equ 0x22 ncount1 equ 0x23 ncount2 equ 0x24 ncount3 equ 0x25 seconds equ 0x26 tenths equ 0x27 sens equ 0x28 ;sensor status flag rt_sens, etc. LCD_tmp1 equ 0x29 nops equ 0x2a ;---------------------------- LCD defines -------------------------------- ; see post includes for LCD control, at bottom of program... ; LCD and port defines #DEFINE LCD_D4 PORTA, 0 #DEFINE LCD_D5 PORTA, 1 #DEFINE LCD_D6 PORTA, 2 #DEFINE LCD_D7 PORTA, 3 #DEFINE LCD_RS PORTA, 4 ; Register Select, 0 = Command, 1 = Data #DEFINE LCD_E PORTA, 5 ; enable, strobe from 1 to 0 to send data ;--------------------- special registers and flags ------------------ porta equ PORTA portb equ PORTB portc equ PORTC portd equ PORTD w equ 0 f equ 1 FSR equ 04h EStrobe MACRO ; Strobe the "E" Bit BSF LCD_E call wait_ms ; wait 1 ms BCF LCD_E call wait_ms ; wait 1 ms ENDM ; The following are variables used by music tone equ 0x30 ;set the tone for routine sound space1 equ 0x31 ;set the spacing dur equ 0x32 ;set the duration for routine sound count1 equ 0x33 ; counter may reuse note equ 0x34 ; musical note for play routine qcount equ 0x35 ; length offset of each note padsize equ 0x36 ; flag to determine if qcount has doubled ;------ constants ,not memory locations ------ null equ 0x00 ; zero or silence #define noteC 0x71 ;These are musical notes (sort of),not memory locations ---- #define noteCs 0x79 #define noteD 0x81 #define noteDs 0x88 #define noteE 0x8e #define noteF 0x95 #define noteFs 0x9b #define noteG 0xa0 #define noteGs 0xa6 #define noteA 0xab #define noteAs 0xb0 #define noteB 0xb4 #define noteC2 0xb8 ;-------------------------------------------------------------------- org 0x800; program starts at 0x800, the bootloader lives in the code space 0x0 to 0x7ff. goto begin begin ; Initialize and setup processor to do work ; movlw 0x0F ; turn off A to D off for port A, all pin are digital movwf ADCON1 movlw 0x00 ; load w with 0000 0000 - controls input/output MOVWF TRISA ; movlw 0x00 ; load w with 0000 0000 - controls input/output MOVWF TRISB ; movlw 0x00 ; load w with 0000 0000 - controls input/output MOVWF TRISD ; ; movlw 0x32 ; load w with 0011 0010 MOVWF TRISC ; ; bcf INTCON, GIE ;disable interrupts MOVLW 0x07 ; turn comparators off and MOVWF CMCON ; enable pins for I/O functions ;**************** Clear Variables ********************* clrf sens ; clear sensors status flags ;-------------------------- Do an LCD test -------------------------------- CALL LCD_init ; Init the LCD ;**************** Clear Variables ********************* clrf porta clrf portb clrf portc clrf portd ; **************** music macros**************** NOP1 macro nop ; no operation, just a delay nop nop nop nop nop nop nop nop nop endm SING macro _note movlw _note movwf note call play endm SING2 macro _note, _dur movlw _note movwf tone movlw _dur movwf dur call sound endm TIME4 macro ;macro for 1/4 note wait call wait100th endm TIME8 macro ;macro for 1/8 note wait call wait_ms call wait_ms call wait_ms call wait_ms call wait_ms endm TIME16 macro ;macro for 1/16 note wait call wait_ms call wait_ms call wait_ms endm CHARGE macro SING2 noteC, 0x01 SING2 noteE, 0x01 SING2 noteF, 0x01 SING2 noteG, 0x02 SING2 noteE, 0x01 SING2 noteG, 0x02 endm SCALES macro SING2 noteC, 0x02 ; C D E F TIME4 SING2 noteD, 0x02 TIME4 SING2 noteE, 0x02 TIME4 SING2 noteF, 0x02 TIME4 SING2 noteG, 0x02 ; G A B _ TIME4 SING2 noteA, 0x02 TIME4 SING2 noteB, 0x02 TIME4 ;-------------------------------- Wait for a second ------------------------- movlw 0x01 ; load 1 seconds to wait in w movwf seconds ; load w value to seconds call wait ; wait for alotted 1 seconds ;---------------- here this will get you started in Jingle or Twinkle ------- SING2 noteE, 0x01 ; E _ _ _ TIME4 TIME4;note time TIME4 TIME4;note time TIME4 TIME4;note time TIME4 SING2 noteF, 0x01 ; F F F F TIME4 SING2 noteF, 0x01 TIME4 SING2 noteF, 0x01 TIME4 SING2 noteF, 0x01 TIME4 SING2 noteF, 0x01 ; F E E EE TIME4 SING2 noteE, 0x01 TIME4 SING2 noteE, 0x01 TIME4 SING2 noteE, 0x01 ; this is a double E (EE) - two E notes played close together TIME8 SING2 noteE, 0x01 TIME4 endm MainLoop: CALL LCD_init ; Init the LCD loop1 SCALES ; Play scales sleep GOTO MainLoop ;------------------------------------------------------- ; play:: subroutine to play a note of space ; 11/29/00 (efa) ;------------------------------------------------------- play movf note,w ;was movfw note musical note or 0x00 to pause incf note decfsz note ;if(note == TRUE) goto play_if1 goto play_else1 play_if1 ;***** Play a note **** movf note,w ; set tone movwf tone ; load w value for sound() movlw 0x04 ; set duration to 16 10ths seconds movwf dur ; load w value for sound() call sound goto play_endif1 play_else1 ;***** Pause, no sound ***** ;---------------------------------------------------------- ; wait for a time---- time backing up movlw 0x06 ; load wait for .8 seconds movwf seconds ; load w value to seconds call wait10th ; wait for alotted 1/10 seconds play_endif1 return ; subroutine return ;------------------------------------------------------- ; sound:: subroutine to sound for dur (duration) at tone. ; 9/30/00 (efa) calibrated 10/02/00 (efa) ;------------------------------------------------------- sound movf dur,w ;was movfw dur, duration of tone (count value) movwf ncount ;load number of counts movlw 0xff ;load max value to w (length of 1 duration) was ff movwf space1 ;load space1 with w movf tone,w ;move tone to w movwf qcount movf tone,w ;move tone to w subwf space1,f ;space1 = 255 - tone inner3 movlw 0x02 movwf padsize qinner bsf portc,7 ; ******* set bit 7 ******* movf space1,w ;space1 value movwf count ;load number of counts nop_lp1 NOP1 ; no operation, just a delay NOP1 NOP1 NOP1 decfsz count,f ; --count goto nop_lp1 ; nop_loop bcf portc,7 ; ******* clear bit 7 ****** movf space1,w ;load space1 to w movwf count1 ;load number of counts nop_lp2 NOP1 ; no operation, just a delay NOP1 NOP1 NOP1 decfsz count1,f ; --count goto nop_lp2 ; nop_loop decfsz qcount,f ; tone goto qinner decfsz padsize,f ;--padsize goto repad goto endpad repad movf tone,w movwf qcount goto qinner endpad decfsz ncount,f ; ++ncount goto inner3 ; inner loop return ; subroutine return ;------------------------------------------------------- ; LCD_init:: Initialize LCD, set it to 4bit mode ; 02/06/10 (efa) ;------------------------------------------------------- LCD_init: bcf LCD_RS ; Enter command mode, Register Select, 0 = Command, 1 = Data movlw 0x30 ; force to 8 bit mode, send upper nibble call LCD_wrtCMD_nibble call wait_ms; movlw 0x30 ; force to 8 bit mode, send upper nibble call LCD_wrtCMD_nibble call wait_ms; movlw 0x30 ; force to 8 bit mode, send upper nibble call LCD_wrtCMD_nibble call wait_ms; movlw 0x20 ; force to 4 bit mode, send upper nibble call LCD_wrtCMD_nibble call wait100th; ; wait 10 ms ; **** Now that we are in 4bit mode, send data a nibble at a time **** MOVLW 0x28 ; set to 4 bit, 2 line, 5x7 display call LCD_wrtCMD MOVLW 0x08 ; Don't shift display, hide cursor CALL LCD_wrtCMD MOVLW 0x01 ; clear and home cursor CALL LCD_wrtCMD MOVLW 0x06 ; set sursor movement to the right CALL LCD_wrtCMD ; MOVLW 0x80 ; move cursor to line 1, home on left ; CALL LCD_wrtCMD MOVLW 0x0F ; turn on display w/ blinking cursor CALL LCD_wrtCMD RETURN ;;============================================================ ; Send an instruction byte (command) to the LCD ;;============================================================ LCD_wrtCMD: BCF LCD_RS ; RS low = Command mode CALL LCDsendByte ; Send the instruction byte RETURN ;;============================================================ ; Send a character to the LCD ;;============================================================ LCD_wrtData: BSF LCD_RS ; RS high = character data CALL LCDsendByte ; Send the character RETURN ;;============================================================ ; Send an instruction byte (command) to the LCD ;;============================================================ LCD_wrtCMD_nibble: BCF LCD_RS ; RS low = Command mode movwf LCD_tmp1 ;;***************** do the upper nibble ****************** BCF LCD_D7 ; Clear data bits BCF LCD_D6 BCF LCD_D5 BCF LCD_D4 BTFSC LCD_tmp1, 7 ; Load high nibble BSF LCD_D7 BTFSC LCD_tmp1, 6 BSF LCD_D6 BTFSC LCD_tmp1, 5 BSF LCD_D5 BTFSC LCD_tmp1, 4 BSF LCD_D4 EStrobe ; strobe the E bit to send data call wait_ms ; Short delay for instruction to settle RETURN ;;============================================================ ; LCDsendByte:: Send a byte to the LCD, assumes RS already set ;;============================================================ LCDsendByte: MOVWF LCD_tmp1 ; Store byte in LCD_tmp1 ;;***************** do the upper nibble ****************** BCF LCD_D7 ; Clear data bits BCF LCD_D6 BCF LCD_D5 BCF LCD_D4 BTFSC LCD_tmp1, 7 ; Load high nibble BSF LCD_D7 BTFSC LCD_tmp1, 6 BSF LCD_D6 BTFSC LCD_tmp1, 5 BSF LCD_D5 BTFSC LCD_tmp1, 4 BSF LCD_D4 EStrobe ; strobe the E bit to send data ;;***************** do the lower nibble ****************** BCF LCD_D7 ; Clear data bits BCF LCD_D6 BCF LCD_D5 BCF LCD_D4 BTFSC LCD_tmp1, 3 ; Load low nibble BSF LCD_D7 BTFSC LCD_tmp1, 2 BSF LCD_D6 BTFSC LCD_tmp1, 1 BSF LCD_D5 BTFSC LCD_tmp1, 0 BSF LCD_D4 EStrobe ; strobe the E bit to send data RETURN ;;=========================================================== ;------------------------------------------------------- ; wait:: subroutine to "wait" for up to 255 seconds. ; Wait routine uses "pause" and variable "seconds" ; 01/31/10 (efa) - calibrated (+/- .1%) ;------------------------------------------------------- wait movwf seconds ; wait for 1-255 seconds incf seconds,f ; start 1 second back... s_loop movlw 0x0a ;max value inner counter movwf ncount1 ;load value inner counter decfsz seconds,f ; --ncount goto start ; pause for a time return ; subroutine return start movlw 0x01 ; load 1/10 seconds to wait in w movwf tenths ; load w value to seconds call wait10th ; pause for .1 seconds decfsz ncount1,f ; --ncount1 goto start ; inner1 loop goto s_loop ; go back to s_loop ;------------------------------------------------------- ; wait10th:: subroutine to "wait" for up to 255 (1/10) seconds. ; Wait routine uses "pause" and variable "seconds" ; 02/04/10 (efa) - calibrated ;------------------------------------------------------- wait10th movwf tenths ; wait for 1-255 (1/10) seconds incf tenths,f ; start 1 second back... s_loop1 movlw 0x0a ;max value inner counter movwf ncount2 ;load value inner counter decfsz tenths,f ; --ncount goto start1 ; pause for a time return ; subroutine return start1 call wait100th ; pause for .01 seconds decfsz ncount2,f ; --ncount1 goto start1 ; inner1 loop goto s_loop1 ; go back to s_loop ;------------------------------------------------------- ; wait100th:: subroutine to pause for 1/100 second ; To decrease pause decrease max value in outer loop ; 02/04/10 (efa) - calibrated ;------------------------------------------------------- wait100th movlw 0x0a ;max value outer counter (10) movwf ncount3 ;load value outer counter outer1 call wait_ms ; no operation, just a delay decfsz ncount3,f ; --ocount goto outer1 ; outer loop return ; subroutine return ;------------------------------------------------------- ; wait_ms:: subroutine to wait for 1/1000 second ; To decrease pause decrease max value in outer loop ; 1/30/10 (efa) calibrated ;------------------------------------------------------- wait_ms movlw 0x18 ;max value outer counter () movwf ocount ;load value outer counter outer movlw 0x7b ;max value inner counter movwf ncount ;load value inner counter inner nop ; no operation, just a delay decfsz ncount,f ; --ncount goto inner ; inner loop decfsz ocount,f ; --ocount goto outer ; outer loop return ; subroutine return ;------------------------------------------------------- ;------------------------------------------------------- ;; Final post-code includes ;; INCLUDE "lcd_4bit.inc" end