Code:
;********************************************************************* ; Function Description: ;********************************************************************* ; Demonstration of the Simple Commands decoder and HEX routines to ; add commands, HEX data entry, and HEX data print via the serial port ; to a PIC program. The code was developed for the 16F873A, but can be ; adapted to most PIC's with a UART. Runs in the background and no ; interrupts are used to free the interrupt routine for user tasks. ; Command decoder and print routines are loaded in page 1 memory to ; free page 0 memory for the user's program. ; Commands are similar to Motorola style @@Xnxx commands where @@ is ; command start, X capital letter is command, n small letter (optional) ; is sub command, and xx (optional) are HEX data charaters. For Simple ; Commands each data entry expects a known number of characters, no end ; of line or parity is used, and no error testing is performed on the ; data to siplify the code. ; Basic entry and print of single and multi-byte HEX data and control ; functions are demonstrated. Data is sent directly to memory but an ; example of a buffered load is shown. Nested menus are demonstrated ; for easy expansion of the command set as the project grows. By ; selecting and customizing the routines you need for your application, ; adding a custom command menu to your program is easy! ; ; These routines are free for public use but please acknowledge the ; author when using them in your program by commenting your code with ; "Simple Commands by Richard H McCorkle" (Is that so much to ask?) ; Thanks! ; ;********************************************************************* ; Serial Command Functions: ;********************************************************************* ; NOTE: Make sure that RTS is connected to CTS at the PIC serial port ; (DB-9 pin 7 tied to pin 8) and a standard serial cable (all pins ; connected) is used or commands may not function correctly. ; The demo command set is defined as: ; Command Function ; @@- Decrement v1 down 1 count ; @@+ Increment v1 up 1 count ; @@Bxxxxxxxxxx Buffered load of 40-bit value v4 ; @@E Toggle keyboard echo ; @@L Load register commands ; @@L0x Load 4-bit value v0 ; @@L1xx Load 8-bit value v1 ; @@L2xxxx Load 16-bit value v2 ; @@L3xxxxxx Load 24-bit value v3 ; @@L4xxxxxxxxxx Load 40-bit value v4 directly ; @@P Print value to serial TX port ; @@Pc Print Command Bit state ; @@P0 Print a 4-bit value from v0 ; @@P1 Print an 8-bit value from v1 ; @@P2 Print a 16-bit value from v2 ; @@P3 Print 24-bit value a or b (nested menu) ; @@P3a Print the 24-bit register v3 ; @@P3b Print the high 24-bits of 40-bit register v4 ; @@R Reset Command Bit C,0 ; @@S Set Command Bit C,0 ; @@Z Zero 40-bit v4 register ;********************************************************************* ; Program Listing: ;********************************************************************* TITLE "Simple Commands Demonstration - Richard H McCorkle, June 1, 2006" LIST n=58, p=PIC16F873A errorlevel 1 include P16F873A.INC __CONFIG _HS_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF & _BODEN_OFF & _DEBUG_OFF & _WRT_OFF & _CPD_OFF & _LVP_OFF ;********************************************************************* ; Define Storage Locations ;********************************************************************* ;NOTE: Keep registers in H -> L sequential order for indexed ops! CBLOCK 0x20 ;Bank 0 Registers - 80 max, 25 used flg0 ;flag bit storage cHdr0 ;communication header flags ; cHdr1 ;if adding headers, add cHdr1,2, etc Hbyte,Mbyte,Lbyte ;Binary-to-HEX print storage BytCt,Dadr ;serial data entry regs btmp ;background temporary storage ; User variables v0 ;4 bit variable (0-F) v1 ;8 bit variable Hv2,Lv2 ;16 bit variable Hv3,Mv3,Lv3 ;24 bit variable Hv4,Mv4,Lv4 ;40 bit variable Sv4,SSv4 Hbuf,Mbuf,Lbuf ;40-bit Transfer Buffer Sbuf,SSbuf ENDC ;Registers 70-7F common in all banks so stack and buffers stored here ;If not common in PIC used, don't use bank 1 registers in the ;background without disabling interrupts first as background routine ;could be interrupted in either bank and W may not get saved properly ;in W_TEMP on interrupt. CBLOCK 0x70 ;Common registers - 16 max, 6 used W_TEMP ;temp storage for W on interrupt STAT_TEMP ;ditto for status reg PCL_TEMP ;ditto for PCLATH FSR_TEMP ;ditto for FSR TX_BUF ;the next char to be xmitted RX_BUF ;the last char received ENDC ;********************************************************************* ; Hardware Bit Assignments: ;********************************************************************* #define HPF PCLATH,3 ;Hi Program Memory Flag #define Zflag STATUS,Z ;Zero Flag #define Cflag STATUS,C ;Carry Flag #define CmdB PORTC,0 ;Command Bit ;********************************************************************* ; Flag Bit Assignments: ;********************************************************************* #define BrdyF flg0,0 ;Byte Ready flag #define LoByt flg0,1 ;Low Byte flag #define Nrdy flg0,2 ;Not Ready flag #define KBE flg0,3 ;Keyboard Echo flag #define bufF flg0,4 ;Buffered Load flag #define LBF flg0,5 ;Load From Buffer flag ;#define N/U flg0,6 ;Spare flag ;#define N/U flg0,7 ;Spare flag ;********************************************************************* ; Command Header Flags: ;********************************************************************* ;if adding headers, add Hdr7, Hdr8, etc keeping Nrtn last #define Hdr0 cHdr0,0 ;Header 0 Flag (@ ) #define Hdr1 cHdr0,1 ;Header 1 Flag (@@ ) #define Hdr2 cHdr0,2 ;Header 2 Flag (@@P ) #define Hdr3 cHdr0,3 ;Header 3 Flag (@@P3) #define Hdr4 cHdr0,4 ;Header 4 Flag (@@L ) #define Hdr5 cHdr0,5 ;Header 5 Flag (@@L0) #define Hdr6 cHdr0,6 ;Header 6 Flag (Nrtn) ;#define Hdr7 cHdr0,7 ;Header 7 Flag (N/U ) ;********************************************************************* ; Initialization ;********************************************************************* ;Set start of code and interrupt vector org 0 ;initialize code nop ;required for the ICD clrf STATUS ;ensure we are at bank 0 clrf PCLATH ;ensure page bits are cleared goto Start org 4 ;interrupt routine movwf W_TEMP ;"push" instructions swapf STATUS,W ;swapf affects NO status bits bcf STATUS,RP0 ;select bank 0 movwf STAT_TEMP ;save STATUS movf PCLATH,W movwf PCL_TEMP ;save PCLATH clrf PCLATH ;select page 0 movf FSR,W movwf FSR_TEMP ;save FSR bcf INTCON,INTF ;clear interrupt goto Int_srv ;initialize bank 0 ports and control registers Start clrf PORTA ;clear port output latches clrf PORTB clrf PORTC clrf INTCON ;disable all interrupts for now ;initialize bank 1 control regs bsf STATUS,RP0 ;select bank 1 ; Insert user initialize code here movlw 0xfe ;0 as output, 1-5 as inputs, movwf TRISC ;2 serial port pins clrf OPTION_REG ;no TMR0, int on falling edge clrf PIE1 ;no int on async xmt bsf TXSTA,TXEN ;enable USART Tx (async mode) bsf TXSTA,BRGH ;set USART BRGH = 1 movlw D'129' ;set async rate at 9600 baud movwf SPBRG ;129 for 20 MHz clock ;back to bank 0 bcf STATUS,RP0 ;bank 0 for RCSTA reg bsf RCSTA,CREN ;enable USART rcv (async mode) bsf RCSTA,SPEN ;enable serial port bsf INTCON,INTE ;enable interrupt on RB0 clrf flg0 ;clear all flags clrf cHdr0 ;clear cmd headers ; clrf cHdr1 ;if adding headers, add cHdr1,2, etc ; Insert user initialize code here ; bsf INTCON,GIE ;enable interrupts if used ;********************************************************************* ; Background Routine ;********************************************************************* ;In background routines, insure variables used (like temp) aren't ;changed during an interrupt as this could cause trouble on return. ;Btmp used for temp storage in command decoder to prevent this. Bkgnd call Rx232 ;check for character received btfss BrdyF ;if no byte ready goto $ + 7 ;jump past process command bcf BrdyF ;clear byte ready flag bsf HPF ;set hi program flag call CmdProc ;Process command bcf HPF ;reset hi program flag btfsc LBF ;if load buffered flag set call Buf2v4 ;load v4 from buffer ; Insert user background code here goto Bkgnd ;********************************************************************* ; Interrupt Service Routine ;********************************************************************* Int_srv ;Insert user interrupt code here pop bcf STATUS,RP0 movf FSR_TEMP,W ;restore FSR movwf FSR movf PCL_TEMP,W ;restore PCLATH movwf PCLATH swapf STAT_TEMP,W ;restore STATUS movwf STATUS swapf W_TEMP ;set status bits swapf W_TEMP,W ;restore W retfie ;return from interrupt ;********************************************************************* ; Subroutines ;********************************************************************* ;Load 40-bit v4 reg from buffer to prevent partial load from ;affecting ongoing process until full 40-bit value is entered. Buf2v4 bcf bufF ;clear buffer flag bcf LBF ;clear load buffered flag movf Hbuf,W ;move buffer to v4 movwf Hv4 movf Mbuf,W movwf Mv4 movf Lbuf,W movwf Lv4 movf Sbuf,W movwf Sv4 movf SSbuf,W movwf SSv4 return ;********************************************************************* ;Get serial Rx data from the USART Rx232 btfss PIR1,RCIF ;received a char? return ;no - return movf RCSTA,W ;check Rx status for error andlw 0x06 ;only error bits btfss Zflag ;if any set, jump to goto RxErr ;error service routine movf RCREG,W ;get char from input buffer movwf RX_BUF ;store in RX_BUF btfss KBE ;if keyboard echo set goto $ + 4 bsf HPF ;set hi program flag call Tx ;echo it back out Tx port bcf HPF ;reset hi program flag bsf BrdyF ;set byte available flag return RxErr bcf RCSTA,CREN ;clear CREN to clear overrun error movf RCREG,W ;read RCREG to clear framing error bsf RCSTA,CREN ;set CREN to rcv bcf BrdyF ;clear byte ready flag clrf cHdr0 ;clear header flags ; clrf cHdr1 ;if adding headers, add cHdr1,2, etc return ;********************************************************************* ; Page 1 Programs ;********************************************************************* ;To save space in the first page of program memory for the user's ;application the command decoder and print routines are loaded into ;page 1 of program memory. The HPF flag (PCLATH,3) is set to access ;page 1 programs from page 0, and needs to be reset when the routine ;returns to page 0. To access page 0 routines from page 1, clear ;HPF before call, set HPF when the routine returns to page 1. org 800 ;load following routines into page 1 ;********************************************************************* ; Simple Commands by Richard H McCorkle ;********************************************************************* ;Check command received via USART Rx mode. When adding additional ;headers keep number return as first routine by adjusting the ;header pointers in number return and SBC acordingly CmdProc btfss Hdr6 ;is header 6 flag set? (Number Return) goto H5 ;no, test next header call GetByt ;get data bytes btfsc Nrdy ;check not ready return ;if set, get next data btfsc bufF ;if buffered load selected bsf LBF ;set load from buffer flag goto Chf ;clear header flags and exit ;********************************************************************* ;@@L0x Load register with single byte H5 btfss Hdr5 ;header 5 flag set (@@L0 received)? goto H4 ;no, test for next header call HexC ;convert input to value movwf v0 ;save in v0 goto Chf ;clear header flags and exit ;********************************************************************* ;@@L Load register commands H4 btfss Hdr4 ;header 4 flag set (@@L received)? goto H3 ;no, test for next header ;@@L0x Load 4-bit value v0 movlw "0" ;is char a "0" ? call RxChk btfss Zflag goto $ + 3 ;no, next header bsf Hdr5 ;set Header 5 flag return ;@@L1xx Load 8-bit value v1 movlw "1" ;is char a "1" ? call RxChk btfss Zflag goto $ + 5 ;no, next header movlw v1 ;move indirect address to W G1R movwf Dadr ;store in Dadr movlw 0x01 ;get 1 register (2 bytes) goto SBC ;@@L2xxxx Load 16-bit value v2 movlw "2" ;is char a "2" ? call RxChk btfss Zflag goto $ + 5 ;no, next header movlw Hv2 ;move indirect address to W G2R movwf Dadr ;store in Dadr movlw 0x02 ;get 2 registers (4 bytes) goto SBC ;@@L3xxxxxx Load 24-bit value v3 movlw "3" ;is char a "3" ? call RxChk btfss Zflag goto $ + 5 ;no, next header movlw Hv3 ;move indirect address to W G3R movwf Dadr ;store in Dadr movlw 0x03 ;get 3 registers (6 bytes) goto SBC ;@@L4xxxxxxxxxx Load 40-bit value v4 movlw "4" ;is char a "4" ? call RxChk btfss Zflag goto Chf ;no valid @@L command, exit movlw Hv4 ;move indirect address to W G5R movwf Dadr ;store in Dadr movlw 0x05 ;get 5 registers (10 bytes) SBC movwf BytCt bsf Nrdy ;set not ready flag bsf Hdr6 ;set Header 6 flag return ;********************************************************************* ;@@P3x An example of a nested menu command H3 btfss Hdr3 ;header 3 flag set (@@P3 received)? goto H2 ;no, test for next header ;@@P3a Print the 24-bit register v3 movlw "a" ;is char an "a" ? call RxChk btfss Zflag goto $ + 3 ;no, next header call prt3 goto Prtn ;clear header flags and exit ;@@P3b Print the high 24-bits of 40-bit register v4 movlw "b" ;is char a "b" ? call RxChk btfss Zflag goto Chf ;no valid @@P3 command, exit call prt4 goto Prtn ;clear header flags and exit ;********************************************************************* ;@@P Print Commands H2 btfss Hdr2 ;header 2 flag set (@@P received)? goto H1 ;no, test for next header ;@@P3 Print 24-bit value a or b (nested menu) movlw "3" ;is char a "3" ? call RxChk btfss Zflag goto $ + 3 ;no, next header bsf Hdr3 ;set Header 3 flag return ;@@P0 Print a 4-bit value movlw "0" ;is char a "0" ? call RxChk btfss Zflag goto $ + 3 ;no, next header call prt0 goto Prtn ;clear header flags and exit ;@@P1 Print an 8-bit value movlw "1" ;is char a "1" ? call RxChk btfss Zflag goto $ + 3 ;no, next header call prt1 goto Prtn ;clear header flags and exit ;@@P2 Print a 16-bit value movlw "2" ;is char a "2" ? call RxChk btfss Zflag goto $ + 3 ;no, next header call prt2 goto Prtn ;clear header flags and exit ;@@Pc Print Command Bit state movlw "c" ;is char a "c" ? call RxChk btfss Zflag goto Chf ;no valid @@P command, exit movlw "0" btfsc CmdB movlw "1" call Tx Prtn call TxCrLf ;send new line goto Chf ;clear header flags and exit ;********************************************************************* ;@@X Main Menu Commands H1 btfss Hdr1 ;header 1 flag set (@@ received)? goto H0 ;no, test for command start ;@@- Decrement v1 down 1 count movlw "-" ;is char a "-" ? call RxChk btfss Zflag goto $ + 3 ;no, next header decf v1 goto Chf ;clear header flags and exit ;@@+ Increment v1 up 1 count movlw "+" ;is char a "+" ? call RxChk btfss Zflag goto $ + 3 ;no, next header incf v1 goto Chf ;clear header flags and exit ;@@Bxxxxxxxxxx Buffered 40-bit load register v4 command movlw "B" ;is char a "B" ? call RxChk btfss Zflag goto $ + 4 ;no, next header bsf bufF ;set Buffer Flag movlw Hbuf ;move indirect address to W goto G5R ;@@E Toggle keyboard echo movlw "E" ;is char an "E" ? call RxChk btfss Zflag goto $ + 5 ;no, next header movf flg0,W xorlw 0x08 ;toggle 3 bit movwf flg0 goto Chf ;clear header flags and exit ;@@L Load register commands movlw "L" ;is char an "L" ? call RxChk btfss Zflag goto $ + 3 ;no, next header bsf Hdr4 ;set Header 4 flag return ;@@P Print value to serial TX port movlw "P" ;is char a "P" ? call RxChk btfss Zflag goto $ + 3 ;no, next header bsf Hdr2 ;yes, set header 2 flag return ;@@R Reset Command Bit movlw "R" ;is char an "R" ? call RxChk btfss Zflag goto $ + 3 ;no, next header bcf CmdB ;clear command bit goto Chf ;clear header flags and exit ;@@S Set Command Bit movlw "S" ;is char an "S" ? call RxChk btfss Zflag goto $ + 3 ;no, next header bsf CmdB ;set command bit goto Chf ;clear header flags and exit ;@@Z Zero 40-bit v4 register movlw "Z" ;is char a "Z" ? call RxChk btfss Zflag goto Chf ;no valid @@ command, exit clrf Hv4 ;clear v4 register clrf Mv4 clrf Lv4 clrf Sv4 clrf SSv4 goto Chf ;clear header flags and exit ;********************************************************************* ;Decode @@ as command start, set Hdr1 flag H0 movlw "@" ;is char a "@" ? call RxChk btfsc Zflag goto $ + 4 btfsc Hdr0 ;If @ rcvd but second char not @ bcf Hdr0 ;clear header 0 flag and return ;exit btfsc Hdr0 ;was header 0 flag set? goto $ + 3 bsf Hdr0 ;no, set header 0 flag (@ rcvd) return ;exit bsf Hdr1 ;yes, set header 1 flag (@@ rcvd) return ;exit ;********************************************************************* ;clear header flags and exit Chf clrf cHdr0 ;clear header flags ; clrf cHdr1 ;if adding headers, add cHdr1,2, etc return ;********************************************************************* ; Check Received byte for match to character in W on call ; Sets Zflag if match RxChk movwf btmp movf RX_BUF,W subwf btmp,W return ;********************************************************************* ; Hex Convert - convert ASCII 0-9 or A-F to number 0-15 in W ; converts small a-f to caps by clearing 32 bit first so either caps ; or smalls for a-f work. Invalid chars produce some hex value HexC movf RX_BUF,W ;get the byte movwf btmp btfss btmp,6 ;number or char? goto $ + 4 bcf btmp,5 ;clear 32 bit (convert small to caps) movlw D'55' ;subtract 55 to convert A-F to values 10-15 goto $ + 2 movlw D'48' ;subtract 48 to convert 0-9 values subwf btmp,W andlw 0x0f ;discard high bits (convert to hex return ;if invalid character entered) ;********************************************************************* ; Get Bytes - fetch number of registers in BytCt and store ; at address starting at Dadr, clear Nrdy when finished GetByt movf Dadr,W ;get storage address movwf FSR call HexC ;convert input to value btfsc LoByt ;if LoByte set, goto $ + 5 movwf INDF ;load in storage swapf INDF ;move to hi nibble bsf LoByt ;set low byte flag return addwf INDF ;add to value in storage bcf LoByt ;clear low byte flag decfsz BytCt ;got all the registers? goto $ + 3 bcf Nrdy ;clear not ready flag return incf FSR ;point to next data movf FSR,W movwf Dadr ;and store in Dadr return ;********************************************************************* ; Hex Print Routines ;********************************************************************* ;Display data in the same Hex format used for data entry. ;print the 4-bit value in v0 prt0 movf v0,W ;print 4-bit value movwf Lbyte goto hp4 ;********************************************************************* ;print the 8-bit value in v1 prt1 movf v1,W ;print 8-bit value movwf Lbyte goto hp8 ;********************************************************************* ;print the 16-bit value in v2 prt2 movf Hv2,W ;print 16-bit value movwf Mbyte movf Lv2,W movwf Lbyte goto hp16 ;********************************************************************* ;print the 24-bit value in v3 prt3 movf Hv3,W ;print 24-bit value movwf Hbyte movf Mv3,W movwf Mbyte movf Lv3,W movwf Lbyte goto hp24 ;********************************************************************* ;print the high 24-bits of the 40-bit register v4 prt4 movf Hv4,W ;print 24-bit value movwf Hbyte movf Mv4,W movwf Mbyte movf Lv4,W movwf Lbyte goto hp24 ;********************************************************************* ;output chars in Hbyte, Mbyte, Lbyte as HEX ASCII to TX DATA hp24 swapf Hbyte,W movwf TX_BUF call TxHex ;print Hbyte hi nibble in hex movf Hbyte,W movwf TX_BUF call TxHex ;print Hbyte low nibble in hex hp16 swapf Mbyte,W movwf TX_BUF call TxHex ;print Mbyte hi nibble in hex movf Mbyte,W movwf TX_BUF call TxHex ;print Mbyte low nibble in hex hp8 swapf Lbyte,W movwf TX_BUF call TxHex ;print Lbyte hi nibble in hex hp4 movf Lbyte,W movwf TX_BUF goto TxHex ;print Lbyte low nibble in hex ;********************************************************************* ;convert lo nibble in TX_BUF to HEX ASCII and send TxHex movf TX_BUF,W ;get transmit data andlw 0x0f ;mask hi bits sublw 0x09 ;9 - W if >9, Cflag = 0 movf TX_BUF,W ;get data andlw 0x0f ;mask hi bits btfss Cflag ;is input >9 addlw 0x07 ;if >9 add 7 for A-F addlw "0" ;make ASCII Tx bsf STATUS,RP0 ;set bank 1 to access TXSTA reg btfss TXSTA,TRMT ;test for Tx buffer empty goto $ - 1 ;wait till buffer empty bcf STATUS,RP0 ;back to bank 0 movwf TXREG ;send it return ;********************************************************************* ;transmit carriage return, line feed TxCrLf movlw "\r" ;send CR to Tx call Tx movlw "\n" ;send LF to Tx goto Tx ;Tx returns to caller ;********************************************************************* de "SmplCmds - Richard H McCorkle, 06/01/2006" de " " END
Questions: