Return to KLUBNL.PL main page

rsgb_lf_group
[Top] [All Lists]

Re: LF: Re: USART in the 16F628

To: [email protected]
Subject: Re: LF: Re: USART in the 16F628
From: "Larry Kayser" <[email protected]>
Date: Sat, 26 Jan 2002 19:24:00 -0500
In-reply-to: <000e01c1a6b0$5661f600$3c9e01d4@g4jnt>
Reply-to: [email protected]
Sender: <[email protected]>
At 09:28 PM 2002/01/26 +0000, you wrote:
Yes please.  I haven't got round to using any of my '628s yet, but had heard a
few vibes that things were not as they seem

Andy  'JNT

>I will send any and all who ask a copy of this ASM file, which I happen to
>call PIC8_4B.ASM, configured to run on a 4 MHz crystal or 4 MHz internal
>oscillator by just compiling it with MPASM.

It is a great pleasure to be able to send you something Andy....

Larry
VA3LK

;******************************************************************************
;[email protected]
        LIST    p=16F628        ;PICF628 is the target processor
;
        #include        "P16F628.INC"   ;Include header file
;
        ErrorLevel      0       ;0 for Messages, Warnings, Errors
        ErrorLevel      -302    ;1 for Warnings, Errors
                                ;2 for Errors
                                ;-302 to suppress Page Message
                                ;
;enable _hs_osc, _pwrte_on, when programming the device
;******************************************************************************
                cblock  h'20'   ;bank 0  h'20' to h'7f'. 96 locations
                savew1  ;SAVEW1 *MUST* be at location h'20'!
                savestatus
                savepclath      
                savefsr
                rx_data         ;the received byte from the serial UART
                tx_data         ;byte to be transmitted via UART
                endc
;******************************************************************************
                cblock  h'A0' ;bank 1
                savew2          ;SAVEW2 *MUST* be at location h'A0'.
                endc
;
        org     h'0000'         ;set code origin to beginning of rom start
        goto    initialize      ;we must get past interrupt vector at 0004
;
;INTERRUPT ROUTINE

        org     h'0004'         ;interrupt vector location
inthandler
        movwf   savew1          ;save w register! (at h'20', h'A0', etc.)
        movf    status,w                ;w now has copy of status
        clrf    status          ;ensure we are in bank 0 now!
        movwf   savestatus              ;save status
        movf    pclath,w                ;save pclath
        movwf   savepclath      
        clrf    pclath          ;explicitly select Page 0
;
        movf    fsr,w
        movwf   savefsr         ;save fsr (just in case)
;
vector_to_interrupt
;
        btfsc   intcon,t0if             ;test to see which interrupt 
        goto    service_t0if    ;needs servicing...
;
        btfsc   intcon,intf             ;there can be many different sources 
        goto    service_intf    ;of interrupt...
                                        ;add as many checks here as you 
                                        ;have possible interrupt sources.... 
;
service_t0if
        nop                             ;!!! or do something useful here...
;
t0if_done
                bcf     intcon,t0if             ;clear interrupt flag that 
caused interrupt.
                goto    intclean                ;restore and return from 
interrupt!
;
service_intf    
                nop                     ;!!! or do something useful here...
;
intf_done       bcf     intcon,intf     ;clear flag that caused interrupt.
                goto    intclean        ;restore and return from interrupt!
;
intclean
                movf    savefsr,w
                movwf   fsr             ;restore fsr
;       
                movf    savepclath,w
                movwf   pclath          ;restore pclath. (Page=original)
;
                movf    savestatus,w
                movwf   status          ;restore status! (bank=original)
;
                swapf   savew1,f        ;restore w from *original* bank! 
                swapf   savew1,w        ;swapf does not affect any flags!
;
                retfie                  ;return from interrupt!
                                        ;gie is auto-re-enabled.
;
initialize                              ;initialize ports and registers

        bcf     status,rp0              ;first do page 0 stuff. yep, page 0

gie01   bcf     intcon,gie              ;turn gie off 
        btfsc   intcon,gie              ;MicroChip recommends this check!
        goto    gie01                   ;without this check
                                        ;you are not sure gie is cleared!
        clrf    pir1            ;clear peripheral flags
;
        clrf    porta           ;clear all i/o registers...
        clrf    portb
;
        bsf     status,rp0      ;allow access to page 1 stuff!
;
        clrf    pie1            ;disable peripheral interrupts
;                               
        movlw   b'00000110'
        movwf   trisb           ;0=output  1=input
                                ; BUT for UART use RB1 and RB2 MUST be 
programmed as an INPUT! 
; 
        bsf     option_reg, not_rbpu    ;!rbpu! rb_pullup 0=enabled 
                                ; 1=disabled. enabling is based on individual 
                                ;port-latch values. currently pullups are 
                                ;disabled.
        bsf     option_reg, intedg      ;intedg 0=inc on falling 1=inc on 
                                ; rising edge. <<note: intedg and t0se use 
                                ; opposite definitions!>>
                                ;currently set for rising edge detection.
        bcf     option_reg, t0cs        ;t0cs timer0clocksource 0=internal 
clkout
                                ;1=ra4/int. currently set for internal clkout

        bcf     option_reg, t0se        ;t0se timer0signaledge 0=inc on rising 
1=inc 
                                ; on falling edge.
                                ; <<note: intedg and t0se use opposite 
                                ; definition!>>
        bcf     option_reg, psa ;psa prescaler assignment 0=tmr0 1=wdt
                                ;ps2-ps0 determine prescaler rate, which is
                                ;dependent also on whether tmr0 or wdt is 
                                ;selected:
                        ;wdt from 0-7 is div by 1 2 4 8 16 32 64 128
                        ;tmr0 from 0-7 is div by 2 4 8 16 32 64 128 256
                        ;if wdt is assigned prescaler, then tmr0 is div by 1
                        ; here we will set prescaler to divide by 16 for tmr0
                        ; !!! set this any way you want. 
                        ; This is just an example that works.
        bcf     option_reg,ps2  ;ps2 
        bsf     option_reg,ps1  ;ps1
        bsf     option_reg,ps0  ;ps0

;intcon register: bit assignments
;
;enables... 1=enable 0=disable
;<7>=gie=global_int_enable
;<6>=peie=peripheral_int_enable
;<5>=t0ie=t0_int_enable (enables <2> t0if)
;<4>=inte=int_enable (rb0/int) (enables <1> intf)
;<3>=rbie=rb_int_enable (enables <0> rbif)
;
;intcon flags. software reset. 0=reset 1=flagged
;<2>=t0if=t0_int_flag
;<1>=intf=int_flag (rb0/int)
;<0>=rbif=rb_int_flag (rb7-rb4)

        clrf    intcon          ;in this example we have no interrupts used.
;
;pie1 peripheral interrupt enable 1 register:
; bit assignments. 1=enable  0=disable
;
;<7>=pspie=parallel_slave_port_int_enable
;<6>=adie=a/d_int_enable
;<5>=rcie=receiver_int_enable for uart (may use later)
;<4>=txie=transmit_int_enable for uart (may use later)
;<3>=sspie=sync_serial_int_enable
;<2>=ccp1ie=ccp1_int_enable
;<1>=tmr2ie=timer2_int_enable
;<0>=tmr1ie=timer1_int_enable
;
        clrf    pie1            ;no interrupts used in this example
;
;uart specific initialization
                                ;txsta=Transmit STAtus and control register.
                                ;take nothing for granted.
        bcf     txsta,csrc      ; <7> (0) don't care in asynch mode
        bcf     txsta,tx9       ; <6>  0  select 8 bit mode
        bsf     txsta,txen      ; <5>  1  enable transmit function 
                                ;      *MUST* be 1 for transmit to work!!!
        bcf     txsta,sync      ; <4>  0 asynchronous mode. 
                                ;      *MUST* be 0 !!!
                                ;      If NOT 0 the async mode is NOT selected!
                                ; <3>  (0) not implemented
        bsf     txsta,brgh      ; <2>  0 disable high baud rate generator !!!
                                ; lsk for 16F628
                                ; 1    (0) trmt is read only.
        bcf     txsta,tx9d      ; <0>  (0)  tx9d data cleared to 0.
;
;   For brgh=0       baudrate=Fosc/(64(spbrg+1))
;   So when brgh=0   spbrg_value = (xtal_freq/(baudrate*d'64'))-1

;   For brgh=1       baudrate=Fosc/(16(spbrg+1)) 
;   So when brgh=1   spbrg_value = (xtal_freq/(baudrate*d'16'))-1
;
xtal_freq       =       d'4000000'      ;crystal frequency in Hertz.
baudrate        =       d'19200'        ;desired baudrate.
;                               ;now calculate spbrg_value...
;spbrg_value    =       (xtal_freq/(baudrate*d'64'))-1
spbrg_value             =       (xtal_freq/(baudrate*d'16'))-1

;
        movlw   spbrg_value     ;set baud rate generator value
        movwf   spbrg
;
        bcf     status,rp0      ;allow access to page 0 stuff again. (normal)
; 
;more uart specific initialization
;
                                ;rcsta=ReCeive STAtus and control register
;
        bsf     rcsta,spen      ; 7 spen 1=rx/tx set for serial uart mode
                                ;   !!! very important to set spen=1
        bcf     rcsta,rx9       ; 6 rc8/9 0=8 bit mode
        bcf     rcsta,sren      ; 5 sren 0=don't care in uart mode
        bsf     rcsta,cren      ; 4 cren 1=enable constant reception
                                ;!!! (and low clears errors)
                                ; 3 not used / 0 / don't care
        bcf     rcsta,ferr      ; 2 ferr input framing error bit. 1=error
                                ; 1 oerr input overrun error bit. 1=error
                                ;!!! (reset oerr by neg pulse clearing cren)
                                ;you can't clear this bit by using bcf.
                                ;It is only cleared when you pulse cren low. 
        bcf     rcsta,rx9d      ; 0 rx9d input (9th data bit). ignore.
;
;If you are using a MAX232 that uses
;charge pumping, put a delay routine
;right HERE, a few seconds
;
;we need to initialize some things, so do it here.
;
        movf    rcreg,w         ;clear uart receiver
        movf    rcreg,w         ; including fifo
        movf    rcreg,w         ; which is three deep.
;
        movlw   0               ;any character will do.
        movwf   txreg           ;send out dummy character
                                ; to get transmit flag valid!
;
main
        bsf     intcon,gie      ;enable interrupts if you are using any!
;                               
loop
        call    ser_in          ;get UART input into W and rx_data
        call    transmitw       ;send W to the UART transmitter
        goto    loop            ;blithely echo characters forever...
;*****************************************************************
;SER_IN
ser_in
        btfsc   rcsta,oerr
        goto    overerror       ;if overflow error...
        btfsc   rcsta,ferr
        goto    frameerror      ;if framing error...
uart_ready
        btfss   pir1,rcif
        goto    ser_in          ;if not ready, wait...
;                       
uart_gotit
        bcf     intcon,gie      ;turn gie off.
        btfsc   intcon,gie      
        goto    uart_gotit
;
        movf    rcreg,w         ;recover uart data
        bsf     intcon,gie      ;re-enable interrupts!!
        movwf   rx_data         ;save for later
        return
;
overerror                       
        bcf     intcon,gie      ;turn gie off. 
        btfsc   intcon,gie      ;
        goto    overerror       ;
;
        bcf     rcsta,cren      ;pulse cren off...
        movf    rcreg,w         ;flush fifo
        movf    rcreg,w         ; all three elements.
        movf    rcreg,w
        bsf     rcsta,cren      ;turn cren back on.
                                ;this pulsing of cren
                                ;will clear the oerr flag.
        bsf     intcon,gie      ;enable interrupts.
        goto    ser_in          ;try again...
;
frameerror                      
        bcf     intcon,gie      ;turn gie off.
        btfsc   intcon,gie      ;
        goto    frameerror      
;
        movf    rcreg,w         ;reading rcreg clears ferr flag.
        bsf     intcon,gie      ;enable interrupts.
        goto    ser_in          ;try again...
;
;TRANSMIT subroutine:
transmit
        movf    tx_data,w       ;copy tx_data to w.
transmitw
        btfss   pir1,txif
        goto    transmitw       ;wait for transmitter interrupt flag
gietx   bcf     intcon,gie      ;disable interrupts
        btfsc   intcon,gie      ;making SURE they are disabled!
        goto    gietx
        movwf   txreg           ;load data to be sent...
        bsf     intcon,gie      ;re-enable interrupts
        return
;
TransWt                 ; use to ensure that TX buffer is empty
        bsf     STATUS,RP0
TxWt    btfss TXSTA,TRMT        ; transmission is complete if hi
        goto    TxWt
        clrf    STATUS  ; RAM Page 0
        return
;
;----------------------------------------------------------------------
        end
<Prev in Thread] Current Thread [Next in Thread>