This is an updated framework program that provides for "background" serial (2400 to 38.4k baud) and has a background countdown timer that can be useful for scheduling events. This program is useful for communicating with devices like the uMP3 and the VMUSIC player.
' =========================================================================
'
' File...... Buffered_Serial_with_Timer.SXB
' Purpose...
' Author.... Jon Williams, EFX-TEK
' Copyright (c) 2007-2009 EFX-TEK
' Some Rights Reserved
' -- see http://creativecommons.org/licenses/by/3.0/
' E-mail.... jwilliams@efx-tek.com
' Started...
' Updated... 04 APR 2009 (updated for SX/B 2.00.xx)
'
' =========================================================================
' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
' -------------------------------------------------------------------------
' Conditional Compilation Symbols
' -------------------------------------------------------------------------
' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------
ID "BufSioTm"
DEVICE SX28, OSCHS2, BOR42
FREQ 50_000_000
' -------------------------------------------------------------------------
' I/O Pins
' -------------------------------------------------------------------------
TX PIN RA.3 OUTPUT ' to PC
RX PIN RA.2 INPUT ' from PC
' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------
IsOn CON 1
IsOff CON 0
Yes CON 1
No CON 0
' Bit dividers for 5.208us interrupt
Baud2400 CON 80
Baud4800 CON 40
Baud9600 CON 20
Baud19K2 CON 10
Baud38K4 CON 5
Baud1x0 CON Baud38K4 ' 1 bit period (ISR counts)
Baud1x5 CON Baud1x0 * 3 / 2 ' 1.5 bit periods
LF CON 10
FF CON 12 ' like CLS for terminals
CR CON 13
' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------
flags VAR Byte
isrFlag VAR flags.0
rxReady VAR flags.1 ' rx byte waiting
tmrRun VAR flags.2 ' 1 = running, 0 = stopped
tmpB1 VAR Byte ' work vars for subs/funcs
tmpB2 VAR Byte
tmpW1 VAR Word
cdTimer VAR Byte (5) ' countdown timer
tix_LSB VAR cdTimer(0) ' 0.1 sec counter
tix_MSB VAR cdTimer(1)
tenths VAR cdTimer(2) ' 0.1 sec units
secs VAR cdTimer(3) ' seconds
mins VAR cdTimer(4) ' minutes
rxSerial VAR Byte (16)
rxBuf VAR rxSerial(0) ' 8-byte buffer
rxCount VAR rxSerial(8) ' rx bit count
rxDivide VAR rxSerial(9) ' bit divisor timer
rxByte VAR rxSerial(10) ' recevied byte
rxHead VAR rxSerial(11) ' buffer head (write to)
rxTail VAR rxSerial(12) ' buffer tail (read from)
rxBufCnt VAR rxSerial(13) ' # bytes in buffer
txSerial VAR Byte (16) ' tx serial data
txBuf VAR txSerial(0) ' eight-byte buffer
txCount VAR txSerial(8) ' tx bit count
txDivide VAR txSerial(9) ' bit divisor timer
txLo VAR txSerial(10) ' holds start bit
txHi VAR txSerial(11) ' tx output reg
txHead VAR txSerial(12) ' buffer head (write to)
txTail VAR txSerial(13) ' buffer tail (read from)
txBufCnt VAR txSerial(14) ' # bytes in buffer
' =========================================================================
INTERRUPT NOPRESERVE 192_000 ' (4) 5.208 uSecs
' =========================================================================
Mark_ISR:
\ SETB isrFlag ' (1)
' -----------------------------------
' Update Countdown Timer when Enabled
' -----------------------------------
'
Process_Timer:
ASM
JNB tmrRun, Timer_Done ' 2/4) abort if not running
BANK cdTimer ' (1) point to timer vars
INC tix_LSB ' (1) update LSB
ADDB tix_MSB, Z ' (2) update MSB
CJNE tix_MSB, #$4B, Timer_Done ' (4/6) 0.1s elapsed?
CJNE tix_LSB, #$00, Timer_Done ' (4/6)
CLR tix_MSB ' (1) yes, reset 1-sec
SUB tenths, #1 ' (2) update tenths
JC Timer_Check ' (2/4) exit if no roll-under
MOV tenths, #9 ' (2) reset tenths
SUB secs, #1 ' (2)
JC Timer_Done ' (2/4)
MOV secs, #59 ' (2)
SUB mins, #1 ' (2)
JC Timer_Done ' (2/4)
CLR mins ' (2)
Timer_Check: ' is timer expired?
MOV W, tenths ' (1) get tenths
OR W, secs ' (1) check tenths & secs
JNZ Timer_Done ' (2/4) about if not zero
OR W, mins ' (1) check mins
SNZ ' (1/2) skip if not zero
CLRB tmrRun ' (1) clear running flag
Timer_Done:
ENDASM
' -------
' RX UART
' -------
'
' UART code by C. Gracey, A. Williams, et al
' -- buffer mods by Jon Williams
'
Receive:
ASM
BANK rxSerial ' (1)
JB rxBufCnt.3, RX_Done ' (2/4) skip if buffer is full
MOVB C, RX ' (4) sample serial input
TEST rxCount ' (1) receiving now?
JNZ RX_Bit ' (2/4) yes, get next bit
MOV W, #9 ' (1) no, prep for next byte
SC ' (1/2)
MOV rxCount, W ' (1) if start, load bit count
MOV rxDivide, #Baud1x5 ' (2) prep for 1.5 bit periods
RX_Bit:
DJNZ rxDivide, RX_Done ' (2/4) complete bit cycle?
MOV rxDivide, #Baud1x0 ' (2) yes, reload bit timer
DEC rxCount ' (1) update bit count
SZ ' (1/2)
RR rxByte ' (1) position for next bit
SZ ' (1/2)
JMP RX_Done ' (3)
RX_Buffer:
MOV W, #rxBuf ' (1) point to buffer head
ADD W, rxHead ' (1)
MOV FSR, W ' (1)
MOV IND, rxByte ' (2) move rxByte to head
INC rxHead ' (1) update head
CLRB rxHead.3 ' (1) keep 0..7
INC rxBufCnt ' (1) update buffer count
SETB rxReady ' (1) set ready flag
RX_Done:
ENDASM
' -------
' TX UART
' -------
'
' UART code by C. Gracey, A. Williams, et al
' -- buffer mods by Jon Williams
'
Transmit:
ASM
BANK txSerial ' (1)
TEST txCount ' (1) transmitting now?
JZ TX_Buffer ' (2/4) if txCount = 0, no
DEC txDivide ' (1) update bit timer
JNZ TX_Done ' (2/4) time for new bit?
MOV txDivide, #Baud1x0 ' (2) yes, reload timer
STC ' (1) set for stop bit
RR txHi ' (1) rotate TX char buf
RR txLo ' (1)
DEC txCount ' (1) update the bit count
MOVB TX, txLo.6 ' (4) output the bit
JMP TX_Done ' (3)
TX_Buffer:
TEST txBufCnt ' (1) anything in buffer?
JZ TX_Done ' (2/4) exit if empty
MOV W, #txBuf ' (2) point to buffer tail
ADD W, txTail ' (1)
MOV FSR, W ' (1)
MOV txHi, IND ' (2) move byte to TX reg
CLR txLo ' (1) clear for start bit
MOV txCount, #10 ' (2) start + 8 + 1 stop
INC txTail ' (1) update tail pointer
CLRB txTail.3 ' (1) keep 0..7
DEC txBufCnt ' (1) update buffer count
TX_Done:
ENDASM
RETURNINT ' (4)
' -------------------------------------------------------------------------
' Subroutine / Function Declarations
' -------------------------------------------------------------------------
DELAY_TIX SUB 2, 2, Word ' delay in 6.51us units
DELAY_MS SUB 2, 2, Word ' replaces PAUSE
RX_BYTE FUNC 1, 0 ' receive a byte
TX_STR SUB 2, 2, Word ' transmit a string
TX_BYTE SUB 1 ' transmit a byte
UCASE FUNC 1, 1 ' convert to uppercase
START_TIMER SUB 3, 3, Byte, Byte, Byte ' set and start the timer
' =========================================================================
PROGRAM Start
' =========================================================================
Start:
PLP_A = %1100
PLP_B = %00000000
PLP_C = %00000000
TX = 1 ' set to idle state
DELAY_MS 5 ' clear terminal RX buffer
Main:
GOTO Main
' -------------------------------------------------------------------------
' Subroutine / Function Code
' -------------------------------------------------------------------------
' Use: DELAY_TIX duration
' -- delay in ISR "ticks"
' -- 5.208us if ISR rate is 192_000
SUB DELAY_TIX
'{$IFUSED DELAY_TIX}
tixDuration VAR __WPARAM12
DO WHILE tixDuration > 0
ASM
CLRB isrFlag ' clear isr flag
JNB isrFlag, @$ ' wait for next
ENDASM
DEC tixDuration ' update duration timer
LOOP
'{$ENDIF}
ENDSUB
' -------------------------------------------------------------------------
' Use: DELAY_MS duration
' -- replaces PAUSE
' -- assumes ISR rate of 192_000
SUB DELAY_MS
'{$IFUSED DELAY_MS}
msDuration VAR __WPARAM12
msTimer VAR __PARAM3
DO WHILE msDuration > 0
msTimer = 192 ' (re)load 1ms timer
DO WHILE msTimer > 0
ASM
CLRB isrFlag ' clear isr flag
JNB isrFlag, @$ ' wait for next
DEC msTimer ' update 1ms timer
ENDASM
LOOP
DEC msDuration ' update duration timer
LOOP
'{$ENDIF}
ENDSUB
' -------------------------------------------------------------------------
' Use: aByte = RX_BYTE
' -- returns "aByte" from 8-byte circular buffer
' -- will wait if buffer is presently empty
' -- rxBufCnt holds byte count of receive buffer (0 to 8)
FUNC RX_BYTE
'{$IFUSED RX_BYTE}
ASM
JNB rxReady, @$ ' wait if empty
BANK rxSerial
MOV FSR, #rxBuf ' point to rxBuf(rxTail)
ADD FSR, rxTail
MOV __PARAM1, IND ' get byte at tail
INC rxTail ' update tail
CLRB rxTail.3 ' keep 0..7
DEC rxBufCnt ' update buffer count
SNZ ' exit if not zero
CLRB rxReady ' else clear ready flag
BANk $00
ENDASM
'{$ENDIF}
ENDFUNC
' -------------------------------------------------------------------------
' Use: TX_STR [String | Label]
' -- pass embedded string or DATA label
SUB TX_STR
'{$IFUSED TX_STR}
strAddr VAR tmpW1
strChar VAR __PARAM1
strAddr = __WPARAM12 ' get string address
DO
READINC strAddr, strChar ' read a character
IF strChar = 0 THEN EXIT ' if 0, string complete
TX_BYTE strChar ' send the byte
LOOP
'{$ENDIF}
ENDSUB
' -------------------------------------------------------------------------
' Use: TX_BYTE aByte
' -- moves "aByte" to 8-byte circular buffer (when space is available)
' -- will wait if buffer is presently full
' -- txBufCnt holds byte count of transmit buffer (0 to 8)
SUB TX_BYTE
'{$IFUSED TX_BYTE}
ASM
BANK txSerial
JB txBufCnt.3, @$ ' prevent buffer overrun
MOV W, #txBuf ' point to buffer head
ADD W, txHead
MOV FSR, W
MOV IND, __PARAM1 ' move byte to tx buf
INC txHead ' update head pointer
CLRB txHead.3 ' keep 0..7
INC txBufCnt ' update buffer count
BANK $00
ENDASM
'{$ENDIF}
ENDSUB
' -------------------------------------------------------------------------
' Use: result = UCASE char
' -- if char is lowercase alpha it is converted to uppercase
FUNC UCASE
'{$IFUSED UCASE}
ASM
CJB __PARAM1, #"a", @UC_Exit
CJA __PARAM1, #"z", @UC_EXIT
CLRB __PARAM1.5
UC_Exit:
ENDASM
'{$ENDIF}
ENDFUNC
' -------------------------------------------------------------------------
' Use: START_TIMER mins, secs, tenths
' -- loads and starts background timer
' -- tmrRun flag cleared to 0 when timer expires
SUB START_TIMER
'{$IFUSED START_TIMER}
tmrRun = IsOff ' stop while reloading
ASM
BANK cdTimer
MOV mins, __PARAM1 ' capture minutes
MOV secs, __PARAM2 ' capture seconds
MOV tenths, __PARAM3 ' capture tenths
Check_Secs:
CJB secs, #60, @Check_Tenths ' validate secs
MOV secs, #59 ' set to max if bad
Check_Tenths:
CJB tenths, #10, @ST_Exit ' validate tenths
MOV tenths, #9 ' set to max if bad
ST_Exit:
CLR tix_LSB ' reset 0.1s timer
CLR tix_MSB
BANK $00
ENDASM
tmrRun = IsOn ' start the timer
'{$ENDIF}
ENDSUB
' -------------------------------------------------------------------------
' User Data
' -------------------------------------------------------------------------
CrLf:
DATA CR, LF, 0 ' CR + LF