This framework is useful when you want "background" serial communications and are dealing with single-wire devices like our accessories (RC-4, etc.).
Note: This is very advanced; you may need to update the ISR code for your specific project.
Edit: Updated to SX/B 2.0x
' =========================================================================
'
' File...... Buffered_Sio-1W.SXB
' Purpose... Buffered serial IO over one wire (open true mode)
' 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 to SX/B 2.00.xx)
'
' =========================================================================
' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
' -------------------------------------------------------------------------
' Conditional Compilation Symbols
' -------------------------------------------------------------------------
' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------
DEVICE SX28, OSCXT2, BOR42
FREQ 20_000_000
ID "Sio-1w"
' -------------------------------------------------------------------------
' I/O Pins
' -------------------------------------------------------------------------
Sio PIN RC.7 INPUT ' No ULN, SETUP = UP
' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------
IsOn CON 1
IsOff CON 0
Yes CON 1
No CON 0
' Bit dividers for 6.51 uS interrupt
Baud2400 CON 64
Baud4800 CON 32
Baud9600 CON 16
Baud19K2 CON 8
Baud38K4 CON 4
Baud1x0 CON Baud38K4 ' 1 bit period (ISR counts)
Baud1x5 CON Baud1x0 * 3 / 2 ' 1.5 bit periods
SioDrive CON %01111111 ' make Sio pin an output
SioFloat CON %11111111 ' float Sio pin
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
tmpB1 VAR Byte ' work vars for subs/funcs
tmpB2 VAR Byte
tmpW1 VAR Word
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 NOCODE 153_600 ' (3) 6.51 uSecs
' =========================================================================
Mark_ISR:
\ SETB isrFlag ' (1)
' -------
' RX UART
' -------
'
' UART code by C. Gracey, A. Williams, et al
' -- buffer mods by Jon Williams
'
Receive:
ASM
BANK txSerial ' (1)
TEST txCount ' (1) transmitting now?
JNZ RX_Done ' (2/4) exit if yes
BANK rxSerial ' (1)
JB rxBufCnt.4, RX_Done ' (2/4) skip if buffer is full
MOVB C, Sio ' (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 rxSerial ' (1)
TEST rxCount ' (1) receiving now?
JNZ TX_Done ' (2/4) exit if yes
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 buf
RR txLo ' (1)
DEC txCount ' (1) update the bit count
JB txLo.6, TX_Bit1
TX_Bit0:
MODE $0F ' (1)
MOV !RC, #SioDrive ' (2) make Sio output
CLRB Sio ' (1) output 0
JMP TX_Done ' (3)
TX_Bit1:
MODE $0F ' (1)
MOV !RC, #SioFloat ' (2) make Sio float
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
' =========================================================================
PROGRAM Start
' =========================================================================
Start:
PLP_A = %0000 ' pull-up unused pins
PLP_B = %00000000
PLP_C = %10000000
DELAY_MS 5 ' clear device RX buffer
Main:
GOTO Main
' -------------------------------------------------------------------------
' Subroutine / Function Code
' -------------------------------------------------------------------------
' Use: DELAY_TIX duration
' -- delay in ISR "ticks"
' -- 6.51us if ISR rate is 153_600
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 153_600
SUB DELAY_MS
'{$IFUSED DELAY_MS}
msDuration VAR __WPARAM12
msTimer VAR __PARAM3
DO WHILE msDuration > 0
msTimer = 153 + msDuration.0 ' (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
' -------------------------------------------------------------------------
' User Data
' -------------------------------------------------------------------------
CrLf:
DATA CR, LF, 0 ' CR + LF