Mike McLaren - K8LH (Westland, MI) says:
I just finished cleaning up an assembly lanugauge source file for a little 12F683 demo' program that shows one way (of probably many) to do reliable 9600 baud bit-banged serial I/O on this chip... It uses TMR2 generated 104-usec interrupts, as well as interrupt-on-change to detect the start bit, using the built-in 12F683 8-MHz INTOSC... Please feel free to use it if you think it may be useful...
list p=12F683, b=8, c= 102, n=71, t=on, st=off, f=inhx32 ;****************************************************************** ;* * ;* Filename: 12F683 Serial.asm * ;* Author: Mike McLaren, K8LH (k8lh@arrl.net) * ;* Date: 27-Nov-04 (rev 22-Dec-04) * ;* * ;* Test 'bit-banged' 9600 baud serial I/O Routines * ;* Uses 12F683 INTOSC at 8-MHz * ;* * ;* * ;* * ;* MPLab: 7.00 (tabs=8) * ;* MPAsm: 3.90 * ;* * ;****************************************************************** #include <p12f683.inc> errorlevel -302 __config _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSC ; ; file register variables ; PROC232 equ 0x20 ;RS-232 Process Latch TXCNT equ 0x21 ;TX-232 bit count TXVAR equ 0x22 ;TX-232 data byte RXCNT equ 0x23 ;RX-232 bit count RXVAR equ 0x24 ;RX-232 data byte ; ; PROC232 flag bits ; RXFLAG equ 0x00 ;1=rx in progress RXCHAR equ 0x01 ;1=rx char available TXFLAG equ 0x02 ;1=tx in progress ; other constants RXPIN equ 0x03 ;RS-232 RX (GP3) TXPIN equ 0x04 ;RS-232 TX (GP4) BAUDX equ .208 ;208 for 9600 baud ; ; file locations used by ISR for saving and restoring the stack ; W_ISR equ 0x70 ;ISR 'W' S_ISR equ 0x71 ;ISR 'STATUS' P_ISR equ 0x72 ;ISR 'PCLATH' ; ; other vars ; PTRL equ 0x78 ;PRTSTR routine PTRH equ 0x79 ;PRTSTR routine ; Hardware notes: ; ; <1> Using INTOSC 8-MHz, 500-nsec instruction cycle ; <2> Using GP3 for 9600 baud 'bit banged' serial input ; <3> Using GP4 for 9600 baud 'bit banged' serial output ; <4> RS-232 signals inverted with MAX232 or 2N7000 drivers ; <5> Using 2700 ohm pull-up resistor on GP3 ; ; This program simply prints a text string to Hyperterminal ; and echos typed characters back to Hyperterminal... ; ; Setup Hyperterminal for 9600, 8, 1, none... Use a MAX232 or ; similar level shifting circuit (I use a pair of 2N7000s) for ; connection between the 12F683 and PC... ; ;****************************************************************** ;* * ;* * ;* * ;* * ;* * ;****************************************************************** org 0x0000 START clrf STATUS ; |B0 movlw b'00010000' ;tx pin in 'stop' condition |B0 movwf GPIO ;setup GPIO latch |B0 goto MAIN ; |B0 ;****************************************************************** ;* * ;* Interrupt Service Routine for 'bit-banged' Serial I/O * ;* * ;* Interrupts are generated every 104-us by TMR2 for 9600 * ;* baud shift operations and by IOC (interrupt on change) * ;* on the RX start bit leading edge on RX pin GP3... * ;* * ;* 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 TMR2 is advanced * ;* by 1/2 bit (52-usec)... Note - advancing TMR2 could * ;* potentially mess up a tx-in-progress, so, don't send & * ;* receive at the same time... * ;* * ;****************************************************************** org 0x0004 ; ; save W and STATUS registers on entry ; 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 ; ; 27-Nov-04, test for GP3 (RXPIN) start bit leading edge ; btfss INTCON,GPIF ;IOC "start bit" interrupt? |B0 goto ISR_TX ;no, branch |B0 movf GPIO,W ;yes, read GPIO |B0 bcf INTCON,GPIF ;clear IOC interrupt flag |B0 bsf PROC232,RXFLAG ;indicate RX in progress |B0 movlw d'10' ;10 bits (start + 8 data + stop) |B0 movwf RXCNT ;initialize RX bit counter |B0 movlw BAUDX/2 ; |B0 movwf TMR2 ;inc TMR2 by 1/2 bit (52-usec) |B0 goto ISR_X ;turn off GP3 IOC & exit |B0 ; ; 23-Nov-04, code to test bit-banged serial output... ; RS-232 code processed each 104-usec interrupt for 9,600 baud... ; ISR_TX btfss PROC232,TXFLAG ;TX in progress? |B0 goto ISR_RX ;no, branch |B0 movf TXCNT,W ;get TX bit count |B0 xorlw b'00001011' ;start bit? |B0 btfsc STATUS,Z ;no, branch |B0 goto ISR_TX1 ;yes, send start bit |B0 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 ;clear TX pin |B0 decf TXCNT,f ;decrement bit counter |B0 btfsc STATUS,Z ;last bit? |B0 bcf PROC232,TXFLAG ;yes, indicate end of TX |B0 ; ; 25-Nov-04, code to test bit-banged serial input... ; ISR_RX btfss PROC232,RXFLAG ;RX in progress? |B0 goto ISR_XIT ;no, branch |B0 bcf STATUS,C ;assume bit=0 |B0 btfsc GPIO,RXPIN ;is it a 0? |B0 bsf STATUS,C ;no, bit=1 |B0 rrf RXVAR,f ;shift bit into RXVAR |B0 decfsz RXCNT,f ;all 10 bits? |B0 goto ISR_XIT ;no, branch |B0 rlf RXVAR,f ;yes, get rid of the stop bit |B0 bcf PROC232,RXFLAG ;clear RX-in-progress flag |B0 bsf PROC232,RXCHAR ;indicate character available |B0 ISR_X bsf STATUS,RP0 ;select bank 1 |B1 movlw b'00001000' ;mask for bit 3 |B1 xorwf IOC,f ;toggle GP3 IOC |B1 bcf STATUS,RP0 ;select bank 0 |B0 ; ISR_XIT bcf PIR1,TMR2IF ;clear TMR2 irq flag |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? ; ;****************************************************************** ;****************************************************************** ; ; Initialization ; MAIN movlw b'00000111' ; |B0 movwf CMCON0 ;digital I/O |B0 bsf STATUS,RP0 ;bank 1 |B1 clrf ANSEL ;digital I/O |B1 movlw b'01110001' ; |B1 movwf OSCCON ;8-mhz INTOSC system clock |B1 movlw b'00001000' ;GP3 input, all others output |B1 movwf TRISIO ; |B1 ; ; 27-Nov-04, code for interrupt-on-change on GP3 (RXPIN) to detect ; RS-232 RX start bit ; movlw b'00001000' ; |B1 movwf IOC ;set IOC for GP3 input |B1 ; ; wait for INTOSC to become stable before doing anything else ; STABLE btfss OSCCON,HTS ;oscillator stable? |B1 goto STABLE ;no, branch |B1 bcf STATUS,RP0 ;bank 0 |B0 ; ; clear RS-232 flags before turning on interrupts ; clrf PROC232 ;clear process latch variable |B0 ; ; configure TIMER2 for 104-usec interrupts (8-MHz clock)... ; clrf TMR2 ;clear TMR2 register |B0 bsf STATUS,RP0 ;select Bank 1 |B1 bsf INTCON,PEIE ;enable peripheral irqs |B1 clrf PIE1 ;mask all peripheral irqs |B1 bsf PIE1,TMR2IE ;except for TMR2 irqs |B1 bcf STATUS,RP0 ;select Bank 0 |B0 clrf PIR1 ;clear peripheral irq flags |B0 movlw b'00000000' ;pre 1, post 1:1 |B0 movwf T2CON ;for 500-nsec ticks (8-mhz clock) |B0 bsf STATUS,RP0 ;select Bank 1 |B1 movlw BAUDX-1 ;number of 500-nsec ticks |B1 movwf PR2 ;104-usec interrupts |B1 bcf STATUS,RP0 ;select Bank 0 |B0 bsf INTCON,GIE ;enable global irqs |B0 bsf INTCON,GPIE ;enable interrupt-on-change irqs |B0 bsf T2CON,TMR2ON ;start TMR2 |B0 ;****************************************************************** ; ; Print a string ; movlw low GREET ;Greeting string address lo |B0 movwf PTRL ; |B0 movlw high GREET ;Greeting string address hi |B0 movwf PTRH ; |B0 call PRTSTR ;print greeting string |B0 ; ; Echo characters coming from Hyperterminal... ; TEST call RX232 ;receive character |B0 call TX232 ;echo character |B0 goto TEST ; |B0 ;****************************************************************** ;****************************************************************** ; ; TX232 - enter with character to be sent in W ; TX232 btfsc PROC232,TXFLAG ;TX in progress? |B0 goto TX232 ;yes, branch and wait |B0 movwf TXVAR ;stuff character |B0 movlw b'00001011' ; |B0 movwf TXCNT ;set TX bit count |B0 bsf PROC232,TXFLAG ;initiate TX |B0 return ; |B0 ;****************************************************************** ; ; RX232 - exit with received character in W ; RX232 btfss PROC232,RXCHAR ;character available flag? |B0 goto RX232 ;no, loop |B0 movf RXVAR,W ;yes, get character |B0 bcf PROC232,RXCHAR ;clear flag |B0 return ; |B0 ;****************************************************************** ; PRTSTR call GETSTR ;Get a string character |B0 andlw b'11111111' ; |B0 btfsc STATUS,Z ;Last character? |B0 return ;Yes, return |B0 call TX232 ;Output char |B0 incfsz PTRL,F ;Increment pointer |B0 goto PRTSTR ; |B0 incf PTRH,F ; |B0 goto PRTSTR ; |B0 GETSTR movf PTRH,W ; |B0 movwf PCLATH ; |B0 movf PTRL,W ; |B0 movwf PCL ; |B0 GREET dt 0x1b, 0x5b, a'H' ;home cursor dt 0x1b, 0x5b, a'J' ;clear screen dt "K8LH 12F683 Serial Test Code v1.0" dt 0x0d, 0x0a, 0x0a, 0x00 end
Questions:
--- 12F683Serial-original.asm 2008-04-21 17:56:20.000000000 -0400 +++ 12F683Serial.asm 2008-05-03 19:58:40.000000000 -0400 @@ -20,3 +20,3 @@ - __config _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSC + __config _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSCIO ; @@ -39,4 +39,4 @@ -RXPIN equ 0x03 ;RS-232 RX (GP3) -TXPIN equ 0x04 ;RS-232 TX (GP4) +RXPIN equ 0x00 ;RS-232 RX (GP0) +TXPIN equ 0x01 ;RS-232 TX (GP1) BAUDX equ .208 ;208 for 9600 baud @@ -48,2 +48,3 @@ P_ISR equ 0x72 ;ISR 'PCLATH' +RX_MASK equ 0x73 ; Mask with RXPIN on others off ; @@ -82,4 +83,4 @@ START clrf STATUS ; |B0 - movlw b'00010000' ;tx pin in 'stop' condition |B0 - movwf GPIO ;setup GPIO latch |B0 + clrf GPIO ; clear it + bsf GPIO,TXPIN ; init TXPIN in stop condition goto MAIN ; |B0 @@ -134,3 +135,3 @@ movf TXCNT,W ;get TX bit count |B0 - xorlw b'00001011' ;start bit? |B0 + xorlw b'00001010' ;start bit? |B0 btfsc STATUS,Z ;no, branch |B0 @@ -161,4 +162,5 @@ ISR_X bsf STATUS,RP0 ;select bank 1 |B1 - movlw b'00001000' ;mask for bit 3 |B1 + movf RX_MASK,w xorwf IOC,f ;toggle GP3 IOC |B1 + bcf STATUS,RP0 ;select bank 0 |B0 @@ -202,4 +204,5 @@ movwf OSCCON ;8-mhz INTOSC system clock |B1 - movlw b'00001000' ;GP3 input, all others output |B1 + movlw b'00000000' ; Set mask as needed - 1 is input |B1 movwf TRISIO ; |B1 + bsf TRISIO,RXPIN ; make the RXPIN an input ; @@ -208,4 +211,13 @@ ; - movlw b'00001000' ; |B1 - movwf IOC ;set IOC for GP3 input |B1 + movlw b'00000000' ;set mask as needed |B1 + movwf IOC ;set IOC off initially |B1 + bsf IOC,RXPIN ; Set the receive pin for IOC + +; enabled weak pull up on RXPIN + clrf WPU ; set off weak pull ups |B1 + bsf WPU,RXPIN ; make the receive pin a pull up + +; Set the RX_MASK properly + clrf RX_MASK + bsf RX_MASK,RXPIN ; @@ -216,2 +228,3 @@ bcf STATUS,RP0 ;bank 0 |B0 + ; @@ -264,3 +277,3 @@ movwf TXVAR ;stuff character |B0 - movlw b'00001011' ; |B0 + movlw b'00001010' ; |B0 movwf TXCNT ;set TX bit count |B0