📄 12f675 serial demo 3.asm
字号:
list p=12F675, b=8, c= 102, n=71, t=on, st=off, f=inhx32
;******************************************************************
;* *
;* Filename: 12F675 Serial Demo 3.asm *
;* Author: Mike McLaren, K8LH (k8lh@arrl.net) *
;* Date: 16-Jan-06 (last revision 30-Mar-07) *
;* *
;* Half Duplex Bit-Banged 9600 Baud Serial I/O Demo *
;* (2-Pin Version with 8-Byte Circular RX Buffer) *
;* *
;* 稶ses 12F675 INTOSC running at 4-MHz *
;* 稡it rate error 0.16% plus or minus 1.0% for INTOSC *
;* 稡it-banged 9600 baud serial I/O *
;* 稨alf Duplex (should not TX and RX simultaneously) *
;* 稵MR0 interrupts at 104-usec intervals (every 104 *
;* instruction cycles) and IOC (interrupt on change) *
;* for RX start bit leading edge detection on RXPIN *
;* 稢ircular 8-byte RX character buffer *
;* 稩nverted TX and RX signals (MAX232A or similar *
;* inverting RS-232 interface required) *
;* 稲elatively small - the ISR and the support routines *
;* Init232, Put232, Get232, and PutString use 124 words *
;* of code space at locations 0004 through 007F and 20 *
;* of 64 RAM locations for variables and RX buffer... *
;* 稺orst case 51% ISR instruction cycle 'overhead' *
;* (54-usecs) when a complete RX character is added to *
;* the circular buffer once every 1.04-msecs... *
;* *
;* *
;* MPLab: 7.30 (tabs=8) *
;* MPAsm: 5.01 *
;* *
;******************************************************************
#include <p12f675.inc>
errorlevel -302
__config _MCLRE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT
;
; RS-232 file register variables, 16 locations [20..2F]
;
RXBUFF equ h'20' ; RX buffer, 8 bytes [20..27]
;
PROC232 equ h'28' ; RS-232 Process Latch
TXCNT equ h'29' ; TX-232 bit count
TXVAR equ h'2A' ; TX-232 data byte
RXCNT equ h'2B' ; RX-232 bit count
RD_PTR equ h'2C' ; RX buffer RD pointer
WR_PTR equ h'2D' ; RX buffer WR pointer
RXCHAR equ h'2E' ; RX char buffer for main
FSRTMP equ h'2F' ;
;
; other variables
;
PTRL equ h'30' ; PutString routine
PTRH equ h'31' ; PutString routine
TEMP equ h'32' ; PutByte routine
;
; PROC232 flag bits
;
RXFLAG equ 0x00 ; 1 = RX in progress
TXFLAG equ 0x02 ; 1 = TX in progress
;
; constants
; ---------------------------------------------------
TXPIN equ h'05' ; TXPIN = GP5 (pin 2) on RGBX board
RXPIN equ h'03' ; RXPIN = GP3 (pin 4)
;
; file locations used by ISR for saving & restoring context
;
W_ISR equ h'5C' ; ISR 'W'
S_ISR equ h'5D' ; ISR 'STATUS'
P_ISR equ h'5E' ; ISR 'PCLATH'
F_ISR equ h'5F' ; ISR 'FSR'
;******************************************************************
;
; _Title macro - home cursor, clear screen, print a string
;
_Title macro str ;
local String, Print
movlw low String ;
movwf PTRL ;
movlw high String ;
movwf PTRH ;
goto Print ;
String dt 0x1b,"[2J" ; home cursor, clear screen
dt str,0
Print call PutString ; print string
endm
;
; _Print macro - print in-line character string
;
_Print macro str ;
local String, Print
movlw low String ;
movwf PTRL ;
movlw high String ;
movwf PTRH ;
goto Print ;
String dt str,0
Print call PutString ; print string
endm
;******************************************************************
;* *
;* *
;* *
;* *
;* *
;******************************************************************
org 0x0000
RESET clrf STATUS ; |B0
movlw b'00000111' ; |B0
movwf CMCON ; comparator off, digital I/O |B0
goto Main ; |B0
;******************************************************************
;* *
;* Interrupt Service Routine for 'bit-banged' Serial I/O *
;* *
;* Interrupts are generated every 104-us by TMR0 for 9600 *
;* baud shift operations and by IOC (interrupt on change) *
;* on the start bit leading edge on RXPIN (GP3, pin 4)... *
;* *
;* On detecting the RX start bit leading edge, GP3 IOC is *
;* turned off, RXFLAG is set to indicate rx-in-progress, *
;* RXCNT bit count variable is set, and TMR0 is set up to *
;* interrupt in approximately 1/2 bit time (52-usec)... *
;* *
;******************************************************************
org 0x0004
;
; save context
;
ISR movwf W_ISR ; save W-reg |B?
swapf STATUS,W ; doesn't change STATUS bits |B?
movwf S_ISR ; save STATUS reg |B?
clrf STATUS ; bank 0 |B0
movf PCLATH,W ; get PCLATH |B0
movwf P_ISR ; save PCLATH |B0
movf FSR,W ; get FSR |B0
movwf F_ISR ; save FSR |B0
;
; test for GP3 (RXPIN) start bit leading edge
;
ISR_IOC btfss INTCON,GPIF ; IOC "start bit" interrupt? |B0
goto ISR_SET ; no, branch |B0
movf GPIO,W ; yes, read GPIO |B0
bcf INTCON,GPIF ; clear IOC interrupt flag |B0
btfsc GPIO,RXPIN ; RXPIN low (start bit)? |B0
goto ISR_XIT ; no, wrong polarity, branch |B0
bsf PROC232,RXFLAG ; indicate RX in progress |B0
movlw d'10' ; (1 start + 8 data + 1 stop) |B0
movwf RXCNT ; initialize RX bit counter |B0
;
bcf INTCON,T0IF ; clear TMR0 interrupt flag |B0
movlw -d'52'+d'39' ; 1/2 bit time (52-usecs) |B0
movwf TMR0 ; |B0
goto ISR_X ; turn off GP3 IOC & exit |B0
;
; clear TMR0 interrupt flag, prep TMR0 for next interrupt
;
ISR_SET bcf INTCON,T0IF ; clear TMR0 interrupt flag |B0
movlw -d'104'+2 ; setup for next 104-usec int |B0
addwf TMR0,f ; |B0
;
; bit-banged serial output
;
ISR_TX btfss PROC232,TXFLAG ; TX in progress? |B0
goto ISR_RX ; no, branch |B0
movf TXCNT,W ; get TX bit count |B0
bnz ISR_TX0 ; no, branch, send next bit |B0
movlw d'10' ; 10 bits (start + 8 data + stop) |B0
movwf TXCNT ; initialize TX bit counter |B0
goto ISR_TX1 ; send the start bit |B0
ISR_TX0 rrf TXVAR,f ; shift lsb into C |B0
bsf TXVAR,7 ; set bit 7 for stop bits |B0
btfsc STATUS,C ; skip if C=0 |B0
bsf GPIO,TXPIN ; set TX pin |B0
btfss STATUS,C ; skip if C=1 |B0
ISR_TX1 bcf GPIO,TXPIN ; clr TX pin |B0
decfsz TXCNT,f ; last bit shifted out? |B0
goto ISR_RX ; no, branch |B0
bcf PROC232,TXFLAG ; yes, indicate end of TX |B0
;
; bit-banged serial input
;
ISR_RX btfss PROC232,RXFLAG ; RX in progress? |B0
goto ISR_XIT ; no, branch, else |B0
movf WR_PTR,W ; get WR_PTR (RXBUFF + 00..07) |B0
movwf FSR ; setup indirect address |B0
bcf STATUS,C ; clear Carry, assume data = 0 |B0
btfsc GPIO,RXPIN ; TRPIN = 0 ? |B0
bsf STATUS,C ; no, set Carry, data = 1 |B0
rrf INDF,f ; shift bit into our character |B0
decfsz RXCNT,f ; all 10 bits? |B0
goto ISR_XIT ; no, branch |B0
rlf INDF,f ; yes, get rid of the stop bit |B0
;
; we now have a complete RX character in RXBUFF[WR_PTR]
;
bcf PROC232,RXFLAG ; clear RX-in-progress flag |B0
;
; if WR_PTR + 1 = RD_PTR the buffer is full so exit, else
; increment WR_PTR variable for the next receive character
;
incf WR_PTR,W ; W = WR_PTR + 1 |B0
andlw RXBUFF+h'07' ; this works for 20..27 |B0
xorwf RD_PTR,W ; WR_PTR+1 = RD_PTR (full)? |B0
skpz ; yes, ignore new character |B0
incf WR_PTR,f ; else add it to the buffer |B0
bcf WR_PTR,3 ; keep in range 20..27 |B0
;
; when entered from the ISR_IOC routine, this code turns off
; the interrupt-on-change feature while receiving a character
;
; when fallen into from the ISR_RX routine above, this code
; turns interrupt-on-change back on in order to detect the
; next receive character start bit falling edge
;
ISR_X bsf STATUS,RP0 ; select bank 1 |B1
movlw 1<<RXPIN ; mask for RXPIN/GP3 IOC |B1
xorwf IOC,f ; toggle RXPIN/GP3 IOC |B1
bcf STATUS,RP0 ; select bank 0 |B0
;
; restore context
;
ISR_XIT movf F_ISR,W ; |B0
movwf FSR ; restore FSR |B0
movf P_ISR,W ; |B0
movwf PCLATH ; restore PCLATH |B0
swapf S_ISR,W ; |B0
movwf STATUS ; restore STATUS |B?
swapf W_ISR,f ; don't screw up STATUS |B?
swapf W_ISR,W ; restore W-reg |B?
retfie ; return from interrupt |B?
;******************************************************************
;* *
;* Companion Put232 and Get232 subroutines *
;* *
;******************************************************************
;
; Put232 - enter with character to be sent in W
;
Put232 btfsc PROC232,TXFLAG ; TX in progress? |B0
goto Put232 ; yes, branch and wait |B0
movwf TXVAR ; stuff character |B0
bsf PROC232,TXFLAG ; initiate TX |B0
return ; |B0
;
; Get232 - exit with received character in W
; - performs RXBUFF 'unload buffer' operation
;
Get232 movf RD_PTR,W ; |B0
xorwf WR_PTR,W ; RD_PTR = WR_PTR (buff empty)? |B0
bz Get232 ; yes, loop, wait for character |B0
movf FSR,W ; get and save FSR |B0
movwf FSRTMP ; |B0
movf RD_PTR,W ; |B0
movwf FSR ; setup indirect address |B0
movf INDF,W ; get RXBUFF[RD_PTR] character |B0
movwf RXCHAR ; save it for later |B0
movf FSRTMP,W ; |B0
movwf FSR ; restore FSR |B0
incf RD_PTR,W ; increment RD_PTR |B0
andlw b'00100111' ; keep it in range 20..27 |B0
movwf RD_PTR ; |B0
movf RXCHAR,W ; get receive character |B0
return ; |B0
;******************************************************************
;* *
;* Companion Init232 subroutine *
;* *
;******************************************************************
Init232 movlw RXBUFF ; RX circular buffer address |B0
movwf RD_PTR ; init circular buffer RD ptr |B0
movwf WR_PTR ; init circular buffer WR ptr |B0
clrf PROC232 ; clear RS232 process latch |B0
clrf TXCNT ; init TXCNT variable |B0
bsf GPIO,TXPIN ; put TXPIN in idle state |B0
;
bsf STATUS,RP0 ; bank 1 |B1
bsf TRISIO,RXPIN ; set RXPIN as input |B1
bcf TRISIO,TXPIN ; set TXPINas output |B1
movlw b'10001000' ; no weak pull-ups and no |B1
movwf OPTION_REG ; prescaler for TMR0 |B1
bsf IOC,RXPIN ; turn on RXPIN IOC |B1
bcf STATUS,RP0 ; bank 0 |B0
;
clrf INTCON ; clear interrupt flags/enables |B0
bsf INTCON,T0IE ; enable TMR0 interrupts |B0
bsf INTCON,GPIE ; enable IOC interrupts |B0
bsf INTCON,GIE ; enable global interrupts |B0
return ; |B0
;******************************************************************
;
; PutString sends a character string through the RS232 port
;
; Entry: setup PTRL and PTRH to string address before entry
; string must be terminated with a 00 byte
;
PutString
call GetTable ; get a table character |B0
andlw b'11111111' ; |B0
skpnz ; 00 byte, last character? |B0
return ; yes, return |B0
call Put232 ; else,output character |B0
incfsz PTRL,F ; increment pointer |B0
goto PutString ; |B0
incf PTRH,F ; |B0
goto PutString ; |B0
;
GetTable
movf PTRH,W ; |B0
movwf PCLATH ; |B0
movf PTRL,W ; |B0
movwf PCL ; |B0
;
; Print byte in W as two ASCII nybbles
;
PutByte movwf TEMP ; save byte |B0
swapf TEMP,W ; swap nybbles in W |B0
call Hex2Asc ; process left nybble |B0
movf TEMP,W ; process right nybble |B0
Hex2Asc andlw b'00001111' ; mask off left nybble |B0
addlw h'36' ; |B0
btfsc STATUS,DC ; |B0
addlw h'07' ; |B0
addlw 0-6 ; ($FA) |B0
goto Put232 ; print ASCII nybble |B0
;******************************************************************
;* *
;* *
;* *
;* *
;* *
;******************************************************************
Main bsf STATUS,RP0 ; bank 1 |B1
call h'3FF' ; get factory calibration value |B1
movwf OSCCAL ; set OSCCAL calibration value |B1
clrf ANSEL ; set all pins to digital mode |B1
movlw b'00011111' ; GP5/TXPIN output |B1
movwf TRISIO ; all others inputs |B1
bcf STATUS,RP0 ; bank 0 |B0
movlw b'00111111' ; set all outputs high |B0
movwf GPIO ; |B0
;
; initialize/turn on RS232 package
;
call Init232 ; |B0
;
; _Title macro - home cursor, clear screen, and print a string
;
_Title "K8LH 12F675 Half Duplex 9600 Baud Serial I/O Demo\r\n\n"
;
; Echo characters coming from Hyperterminal
;
Loop call Get232 ; receive character |B0
call Put232 ; echo character back |B0
goto Loop ; loop forever |B0
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -