??? 05/16/07 00:41 Modified: 05/16/07 02:24 Read: times |
#139296 - ReceiveString, rev. 2 Responding to: ???'s previous message |
Jan said:
I modified slightly the specs. Comments? Hi Jan, I modified your program enough to make it work with my old assembler on a Silicon Labs C8051F120. It never really hit me before how much more stuff you have to go through to initialize the 'F120 than one of the simpler derivatives. Anyway, I have a few comments about your version. Three of them are substantial, and the others are just matters of style. First the substantial ones:
For the record, here's a revision that works with an old Archimedes assembler and the C8051F120. -- Russ ; ----------------------------------------------------------------------------- ; asm120.s03 ; ----------------------------------------------------------------------------- ; DESCRIPTION: This is a skeleton program for the C8051F120 evaluation board ; from Silicon Labs. It demonstrates Jan's line editor ; subroutine. ; ; REVISIONS: 14 May 07 - RAC - Adapted from Jan's initial implementation ; ----------------------------------------------------------------------------- LSTOUT- ; Don't list header file $f120.inc ; Hardware register and bit definitions LSTOUT+ ; Listing back on ;------------------------------------------------------------------------------ ; Names for Numbers ;------------------------------------------------------------------------------ LED EQU P1.6 ; LED on 'F120 evaluation board BEEP_CHR EQU 07h ; Names for ASCII characters BS_CHR EQU 08h CR_CHR EQU 0Dh LF_CHR EQU 0Ah SPACE_CHR EQU 20h RX_BUFFER_SIZE EQU 10 ; Test buffer size ;------------------------------------------------------------------------------ ; Data Segment ;------------------------------------------------------------------------------ ;----- The data segment loads at address 8, immediately above the registers. RSEG DATA RxBuffer: DS RX_BUFFER_SIZE ;------------------------------------------------------------------------------ ; Stack Segment ;------------------------------------------------------------------------------ ;----- The stack starts immediately after all the other RAM variables, and ; expands upward from there. RSEG CSTACK StackBegin: DS 1 ;------------------------------------------------------------------------------ ; Boot Vector ;------------------------------------------------------------------------------ COMMON INTVEC ; Loads at address zero Startup: JMP Main ; Jump to main routine ;----- Timer 0 interrupt vector ORG Startup+0Bh ;------------------------------------------------------------------------------ ; Main ;------------------------------------------------------------------------------ ; DESCRIPTION: Shuts off the watchdog timer, initializes the hardware, then ; spins a loop forever spitting characters out the serial port. ; ; REVISIONS: 14 May 07 - RAC - Adapted from a similar program written in C. ;------------------------------------------------------------------------------ RSEG RCODE ; Loads after INTVEC Main: MOV SP,#StackBegin-1 ; Set up the stack pointer CALL InitializeHardware ; Go set up the chip MainLoop: ;----- Get a line of input from the human user call ReceiveString ;----- Print the length of the received string call TxCRLF ; Print CR/LF mov a,r0 ; Get pointer to end of data clr c ; Prepare to subtract subb a,#RxBuffer ; Calculate string length call TxHexa ; Print it call TxCRLF ; Print CR/LF ;----- Print the string itself mov r0,#RxBuffer ; Start at the beginning of the buffer Loop1: mov a,@r0 ; Get next character jz Loop2 ; It's zero - we're done call TxChar ; Not zero - go print it inc r0 ; Advance to next character sjmp Loop1 ; Repeat for entire string Loop2: call TxCRLF ; Print CR/LF JMP MainLoop ; Go do it again ; ----------------------------------------------------------------------------- ; TxChar ; ----------------------------------------------------------------------------- ; DESCRIPTION: Sends the byte in the accumulator out the UART. ; ; REVISIONS: 15 May 07 - RAC - Adapted from an old putchar() routine ; ----------------------------------------------------------------------------- TxChar: MOV SBUF,A ; Send the character JNB TI0,$ ; Spin until it's sent CLR TI0 ; Reset done flag RET ; Done ; ----------------------------------------------------------------------------- ; RxChar ; ----------------------------------------------------------------------------- ; DESCRIPTION: Waits for a byte from the UART and returns it in the ; accumulator ; ; REVISIONS: 15 May 07 - RAC - Adapted from an old putchar() routine ; ----------------------------------------------------------------------------- RxChar: JNB RI0,$ ; Wait for incoming character CLR RI0 ; Clear flag MOV A,SBUF ; Got it RET ; ----------------------------------------------------------------------------- ; InitializeHardware ; ----------------------------------------------------------------------------- ; DESCRIPTION: Sets up the C8051F120 hardware ; ; REVISIONS: 15 May 07 - RAC - Extracted from Main ; ----------------------------------------------------------------------------- InitializeHardware: ;----- Start with general initialization MOV WDTCN,#0DEh ; Disable the watchdog timer MOV WDTCN,#0ADh MOV SFRPAGE,#CONFIG_PAGE ; Switch to config page MOV XBR2,#40h ; Enable Port I/O crossbar ORL P0MDOUT,#1 ; Set UART Tx for push/pull out ORL P1MDOUT,#40h ; Set P1.6 for push/pull out ;----- Set up Timer 1 as the on-board serial port baud rate generator MOV SFRPAGE,#TIMER01_PAGE ; Timer 1 config page MOV TH1,#0F4h ; Reload value for 115.2 Kbps ANL TMOD,#0Fh ; Clear upper nibble of TMOD ORL TMOD,#20h ; Put Timer 1 into Mode 2 ORL CKCON,#10h ; SYSCLK clocks Timer 1 SETB TR1 ; Start Timer 1 ;----- Set up the onboard UART MOV SFRPAGE,#CONFIG_PAGE ; Switch to config page MOV XBR0,#04h ; Enable UART to I/O pins MOV SFRPAGE,#TIMER01_PAGE ; Timer 1 config page MOV SCON0,#50h ; Mode 1, Rx enabled ORL SSTA0,#10h ; Disable UART divide by 2 ;----- Switch from the internal oscillator to the external crystal oscillator MOV SFRPAGE,#CONFIG_PAGE ; Switch to config page MOV OSCXCN,#67h ; Enable the crystal oscillator MOV R0,#5 ; Delay for about 1.2 msec TimingLoop: MOV R1,#255 DJNZ R1,$ DJNZ R0,TimingLoop NotStableYet: ; Wait for oscillator to MOV A,OSCXCN ; stabilize ANL A,#80h JZ NotStableYet MOV CLKSEL,#1 ; Switch to external oscillator MOV SFRPAGE,#LEGACY_PAGE ; Return to default SFR page RET ; Done ; ----------------------------------------------------------------------------- ; Print Utilities ; ----------------------------------------------------------------------------- ;----- Prints CR/LF TxCRLF: mov a,#CR_CHR ; Get a carriage return call TxChar ; Go print it mov a,#LF_CHR ; Get a line feed call TxChar ; Go print it ret ; Done ;----- Prints accumulator contents as a 2-digit hex number TxHexa: push acc ; Save for second digit swap a ; Isolate most-significant nibble anl a,#0Fh add a,#TxHexaT-TxHexaX1 ; Index into table of hex digits movc a,@a+pc ; Get hex digit TxHexaX1: call TxChar ; Go print it pop acc ; Recall and isolate least significant anl a,#0Fh ; nibble add a,#TxHexaT-TxHexaX2 ; Index into table of hex digits movc a,@a+pc ; Get hex digit TxHexaX2: call TxChar ; Go print it ret ; Done TxHexaT: db '0123456789ABCDEF' ; Table of hex digits ;------------------------------------------------------------------------------ ; ReceiveString ;------------------------------------------------------------------------------ ; DESCRIPTION: This subroutine is called from many places to receive a line of ; input from a human user via a terminal connected to the onboard ; UART. Each line of input starts with the first character ; entered after this subroutine is called, and ends with a ; carriage return. ; ; This subroutine accumulates the data in a buffer called ; 'RxBuffer', which is located in the internal data RAM and is ; accessed only via indirect addressing (i.e. can be located in ; the upper 128 bytes). The symbol RX_BUFFER_SIZE gives the size ; of the buffer, in bytes. Note that to leave room for the ; trailing zero, the actual number of characters received is ; limited to RX_BUFFER_SIZE-1. ; ; On entry, this function does minor internal housekeeping to ; prepare for a new line of input (i.e. resets the pointer :-)) ; It then receives characters one by one from the user. It ; handles each received character as follows: ; ; - Backspace (08h): If the buffer is not empty, removes the ; newest character from the buffer and echoes the three- ; character sequence 08h 20h 08h (backspace space backspace) ; to the terminal to erase the most recently typed character ; from the user's screen. If the buffer is empty when the ; backspace character is received, echoes a single 07h (beep) ; to the terminal. ; ; - Carriage Return (0Dh): Appends zero character to the buffer ; to mark the end of the line and returns. ; ; - Printable characters (20h through 7Fh, inclusive): If the ; buffer is full, echoes a single 07h (beep) to the terminal. ; Otherwise appends the character to the buffer. ; ; - All other characters: Does nothing. ; ; As noted above, this function returns when it receives a ; carriage return. Nothing specific is returned in registers. ; ; The function won't guarantee to keep the value of registers ; (this is the standard behaviour of C routines both in Keil and ; SDCC), although resources usage will be determined and noted ; below. ; ; A test program is written to try the routine, which is not part ; of the routine. Test with Hyperterminal or equivalent, 9600 ; baud, 8N1, no handshake, auto terminal mode. Should beep when ; 10th character is attempted to be entered. Deleting should ; "eat" characters until the last one, after it deleting should ; beep. After enter, should write number of characters and the ; string again. ; ; RESOURCE USE: Uses and destroys ACC and R0 ; A few stack bytes ; No external memory ; No interrutps disabled ; ; REVISIONS: 13 May 07 - RAC - Initial specification ; 13 May 07 - JW - Modified specification and initial ; implementation. ; ----------------------------------------------------------------------------- ReceiveString: mov r0,#RxBuffer ; Initialize receiver pointer ;----- Loop here until a line of input has been received LoopReceive: call RxChar ; Go get a character jb acc.7,LoopReceive ; It's unprintable (>= 80h) - ignore it cjne a,#20h,$+3 ; Is it a control character (<20h)? jc ControlChars ; Yes - process separately cjne r0,#RxBuffer+RX_BUFFER_SIZE-1,StoreChar ; No - store if no overflow EchoBeep: ; Overflow or underflow - beep mov a,#BEEP_CHR sjmp SendChar StoreChar: mov @r0,a ; Put it into buffer inc r0 ; Bump pointer SendChar: call TxChar ; Go print the character sjmp LoopReceive ; Go get next character ControlChars: cjne a,#BS_CHR,NotBackSpace cjne r0,#RxBuffer,EatCharacter ;if BackSpace, eat last character sjmp EchoBeep ; if empty buffer, just beep EatCharacter: mov a,#BS_CHR ; Do what's needed to eat the character call TxChar ; on the terminal mov a,#SPACE_CHR call TxChar mov a,#BS_CHR call TxChar dec r0 ; Eat the character in the buffer sjmp LoopReceive ; Go get next character NotBackSpace: cjne a,#CR_CHR,LoopReceive ; If not CR, go get next character mov @r0,#0 ; Got CR - terminate the string ret ; Done END |