1 ;Greetings and I hope you find this code segment for serial coms using the
\r
2 ;the 16F628 or 16F627 PIC Microprocessors.
\r
4 ;I hacked this code for the 627 and 628 from the fine work done by
\r
5 ;Friar Tom McGahee's work in his program PICUART.ASM. The
\r
6 ;Friar solved the Microchip Serial UART Coms problems for the earlier
\r
7 ;chips. I took the code and made it work for the 16F628 and
\r
8 ;16F627, it was not easy but it is done.....and it works reliably. DON'T
\r
9 ;CHANGE A SINGLE LINE OF IT, COMPILE and load and it
\r
10 ;will work. If you think you see an error, and there are some glaring look
\r
11 ;like errors in the code, DON'T CHANGE IT NOW,
\r
12 ;GET THIS CODE WORKING, then you can happily put in many hours making it
\r
13 ;simple and concise and you will learn some
\r
14 ;rather nasty lessons about Microchip and Microchip documentation. It is
\r
15 ;difficult to say anything nice about Microchip, INTEL back
\r
16 ;mid 1970's had a rather messy silicon for the first INTEL 8251's At least
\r
17 ;the Intel documentation was correct, just the silicon
\r
18 ;was broken and INTEL fixed the silicon, unlike Microchip who as far as I
\r
19 ;can find has never done anything about the Serial Coms
\r
20 ;documentation........
\r
22 ;Once you have this code working you can go through and have a good day
\r
23 ;cleaning it up and then trying to make it work again! When I :say do a
\r
24 ;Read when any reasonable person would do a Write, go back and make it a
\r
27 ;Have fun, good fun with this code segment, use it in good health and for
\r
28 ;as much profit as you can make from it.
\r
29 ;Larry Kayser, VA3LK / WA3ZIA, va3lk@rac.ca
\r
31 ;As of 20030101 this URL worked for Friar McGahee's picuart.zip,
\r
32 ;http://www.pic101.com/mcgahee/
\r
34 ;******************************************************************************
\r
35 ;kayser@sympatico.ca
\r
36 LIST p=16F628 ;PICF628 is the target processor
\r
38 #include "P16F628.INC" ;Include header file
\r
40 ErrorLevel 0 ;0 for Messages, Warnings, Errors
\r
41 ErrorLevel -302 ;1 for Warnings, Errors
\r
43 ;-302 to suppress Page Message
\r
45 ;enable _hs_osc, _pwrte_on, when programming the device
\r
46 ;******************************************************************************
\r
47 cblock h'20' ;bank 0 h'20' to h'7f'. 96 locations
\r
48 savew1 ;SAVEW1 *MUST* be at location h'20'!
\r
52 rx_data ;the received byte from the serial UART
\r
53 tx_data ;byte to be transmitted via UART
\r
55 ;******************************************************************************
\r
56 cblock h'A0' ;bank 1
\r
57 savew2 ;SAVEW2 *MUST* be at location h'A0'.
\r
60 org h'0000' ;set code origin to beginning of rom start
\r
61 goto initialize ;we must get past interrupt vector at 0004
\r
65 org h'0004' ;interrupt vector location
\r
67 movwf savew1 ;save w register! (at h'20', h'A0', etc.)
\r
68 movf status,w ;w now has copy of status
\r
69 clrf status ;ensure we are in bank 0 now!
\r
70 movwf savestatus ;save status
\r
71 movf pclath,w ;save pclath
\r
73 clrf pclath ;explicitly select Page 0
\r
76 movwf savefsr ;save fsr (just in case)
\r
80 btfsc intcon,t0if ;test to see which interrupt
\r
81 goto service_t0if ;needs servicing...
\r
83 btfsc intcon,intf ;there can be many different sources
\r
84 goto service_intf ;of interrupt...
\r
85 ;add as many checks here as you
\r
86 ;have possible interrupt sources....
\r
89 nop ;!!! or do something useful here...
\r
92 bcf intcon,t0if ;clear interrupt flag that caused interrupt.
\r
93 goto intclean ;restore and return from interrupt!
\r
96 nop ;!!! or do something useful here...
\r
98 intf_done bcf intcon,intf ;clear flag that caused interrupt.
\r
99 goto intclean ;restore and return from interrupt!
\r
103 movwf fsr ;restore fsr
\r
106 movwf pclath ;restore pclath. (Page=original)
\r
109 movwf status ;restore status! (bank=original)
\r
111 swapf savew1,f ;restore w from *original* bank!
\r
112 swapf savew1,w ;swapf does not affect any flags!
\r
114 retfie ;return from interrupt!
\r
115 ;gie is auto-re-enabled.
\r
117 initialize ;initialize ports and registers
\r
119 bcf status,rp0 ;first do page 0 stuff. yep, page 0
\r
121 gie01 bcf intcon,gie ;turn gie off
\r
122 btfsc intcon,gie ;MicroChip recommends this check!
\r
123 goto gie01 ;without this check
\r
124 ;you are not sure gie is cleared!
\r
125 clrf pir1 ;clear peripheral flags
\r
127 clrf porta ;clear all i/o registers...
\r
130 bsf status,rp0 ;allow access to page 1 stuff!
\r
132 clrf pie1 ;disable peripheral interrupts
\r
135 movwf trisb ;0=output 1=input
\r
136 ; BUT for UART use RB1 and RB2 MUST be programmed as an INPUT!
\r
138 bsf option_reg, not_rbpu ;!rbpu! rb_pullup 0=enabled
\r
139 ; 1=disabled. enabling is based on individual
\r
140 ;port-latch values. currently pullups are
\r
142 bsf option_reg, intedg ;intedg 0=inc on falling 1=inc on
\r
143 ; rising edge. <<note: intedg and t0se use
\r
144 ; opposite definitions!>>
\r
145 ;currently set for rising edge detection.
\r
146 bcf option_reg, t0cs ;t0cs timer0clocksource 0=internal clkout
\r
147 ;1=ra4/int. currently set for internal clkout
\r
149 bcf option_reg, t0se ;t0se timer0signaledge 0=inc on rising 1=inc
\r
151 ; <<note: intedg and t0se use opposite
\r
153 bcf option_reg, psa ;psa prescaler assignment 0=tmr0 1=wdt
\r
154 ;ps2-ps0 determine prescaler rate, which is
\r
155 ;dependent also on whether tmr0 or wdt is
\r
157 ;wdt from 0-7 is div by 1 2 4 8 16 32 64 128
\r
158 ;tmr0 from 0-7 is div by 2 4 8 16 32 64 128 256
\r
159 ;if wdt is assigned prescaler, then tmr0 is div by 1
\r
160 ; here we will set prescaler to divide by 16 for tmr0
\r
161 ; !!! set this any way you want.
\r
162 ; This is just an example that works.
\r
163 bcf option_reg,ps2 ;ps2
\r
164 bsf option_reg,ps1 ;ps1
\r
165 bsf option_reg,ps0 ;ps0
\r
167 ;intcon register: bit assignments
\r
169 ;enables... 1=enable 0=disable
\r
170 ;<7>=gie=global_int_enable
\r
171 ;<6>=peie=peripheral_int_enable
\r
172 ;<5>=t0ie=t0_int_enable (enables <2> t0if)
\r
173 ;<4>=inte=int_enable (rb0/int) (enables <1> intf)
\r
174 ;<3>=rbie=rb_int_enable (enables <0> rbif)
\r
176 ;intcon flags. software reset. 0=reset 1=flagged
\r
177 ;<2>=t0if=t0_int_flag
\r
178 ;<1>=intf=int_flag (rb0/int)
\r
179 ;<0>=rbif=rb_int_flag (rb7-rb4)
\r
181 clrf intcon ;in this example we have no interrupts used.
\r
183 ;pie1 peripheral interrupt enable 1 register:
\r
184 ; bit assignments. 1=enable 0=disable
\r
186 ;<7>=pspie=parallel_slave_port_int_enable
\r
187 ;<6>=adie=a/d_int_enable
\r
188 ;<5>=rcie=receiver_int_enable for uart (may use later)
\r
189 ;<4>=txie=transmit_int_enable for uart (may use later)
\r
190 ;<3>=sspie=sync_serial_int_enable
\r
191 ;<2>=ccp1ie=ccp1_int_enable
\r
192 ;<1>=tmr2ie=timer2_int_enable
\r
193 ;<0>=tmr1ie=timer1_int_enable
\r
195 clrf pie1 ;no interrupts used in this example
\r
197 ;uart specific initialization
\r
198 ;txsta=Transmit STAtus and control register.
\r
199 ;take nothing for granted.
\r
200 bcf txsta,csrc ; <7> (0) don't care in asynch mode
\r
201 bcf txsta,tx9 ; <6> 0 select 8 bit mode
\r
202 bsf txsta,txen ; <5> 1 enable transmit function
\r
203 ; *MUST* be 1 for transmit to work!!!
\r
204 bcf txsta,sync ; <4> 0 asynchronous mode.
\r
206 ; If NOT 0 the async mode is NOT selected!
\r
207 ; <3> (0) not implemented
\r
208 bsf txsta,brgh ; <2> 0 disable high baud rate generator !!!
\r
210 ; 1 (0) trmt is read only.
\r
211 bcf txsta,tx9d ; <0> (0) tx9d data cleared to 0.
\r
213 ; For brgh=0 baudrate=Fosc/(64(spbrg+1))
\r
214 ; So when brgh=0 spbrg_value = (xtal_freq/(baudrate*d'64'))-1
\r
216 ; For brgh=1 baudrate=Fosc/(16(spbrg+1))
\r
217 ; So when brgh=1 spbrg_value = (xtal_freq/(baudrate*d'16'))-1
\r
219 xtal_freq = d'4000000' ;crystal frequency in Hertz.
\r
220 baudrate = d'19200' ;desired baudrate.
\r
221 ; ;now calculate spbrg_value...
\r
222 ;spbrg_value = (xtal_freq/(baudrate*d'64'))-1
\r
223 spbrg_value = (xtal_freq/(baudrate*d'16'))-1
\r
226 movlw spbrg_value ;set baud rate generator value
\r
229 bcf status,rp0 ;allow access to page 0 stuff again. (normal)
\r
231 ;more uart specific initialization
\r
233 ;rcsta=ReCeive STAtus and control register
\r
235 bsf rcsta,spen ; 7 spen 1=rx/tx set for serial uart mode
\r
236 ; !!! very important to set spen=1
\r
237 bcf rcsta,rx9 ; 6 rc8/9 0=8 bit mode
\r
238 bcf rcsta,sren ; 5 sren 0=don't care in uart mode
\r
239 bsf rcsta,cren ; 4 cren 1=enable constant reception
\r
240 ;!!! (and low clears errors)
\r
241 ; 3 not used / 0 / don't care
\r
242 bcf rcsta,ferr ; 2 ferr input framing error bit. 1=error
\r
243 ; 1 oerr input overrun error bit. 1=error
\r
244 ;!!! (reset oerr by neg pulse clearing cren)
\r
245 ;you can't clear this bit by using bcf.
\r
246 ;It is only cleared when you pulse cren low.
\r
247 bcf rcsta,rx9d ; 0 rx9d input (9th data bit). ignore.
\r
249 ;If you are using a MAX232 that uses
\r
250 ;charge pumping, put a delay routine
\r
251 ;right HERE, a few seconds
\r
253 ;we need to initialize some things, so do it here.
\r
255 movf rcreg,w ;clear uart receiver
\r
256 movf rcreg,w ; including fifo
\r
257 movf rcreg,w ; which is three deep.
\r
259 movlw 0 ;any character will do.
\r
260 movwf txreg ;send out dummy character
\r
261 ; to get transmit flag valid!
\r
264 bsf intcon,gie ;enable interrupts if you are using any!
\r
267 call ser_in ;get UART input into W and rx_data
\r
268 call transmitw ;send W to the UART transmitter
\r
269 goto loop ;blithely echo characters forever...
\r
270 ;*****************************************************************
\r
274 goto overerror ;if overflow error...
\r
276 goto frameerror ;if framing error...
\r
279 goto ser_in ;if not ready, wait...
\r
282 bcf intcon,gie ;turn gie off.
\r
286 movf rcreg,w ;recover uart data
\r
287 bsf intcon,gie ;re-enable interrupts!!
\r
288 movwf rx_data ;save for later
\r
292 bcf intcon,gie ;turn gie off.
\r
296 bcf rcsta,cren ;pulse cren off...
\r
297 movf rcreg,w ;flush fifo
\r
298 movf rcreg,w ; all three elements.
\r
300 bsf rcsta,cren ;turn cren back on.
\r
301 ;this pulsing of cren
\r
302 ;will clear the oerr flag.
\r
303 bsf intcon,gie ;enable interrupts.
\r
304 goto ser_in ;try again...
\r
307 bcf intcon,gie ;turn gie off.
\r
311 movf rcreg,w ;reading rcreg clears ferr flag.
\r
312 bsf intcon,gie ;enable interrupts.
\r
313 goto ser_in ;try again...
\r
315 ;TRANSMIT subroutine:
\r
317 movf tx_data,w ;copy tx_data to w.
\r
320 goto transmitw ;wait for transmitter interrupt flag
\r
321 gietx bcf intcon,gie ;disable interrupts
\r
322 btfsc intcon,gie ;making SURE they are disabled!
\r
324 movwf txreg ;load data to be sent...
\r
325 bsf intcon,gie ;re-enable interrupts
\r
328 TransWt ; use to ensure that TX buffer is empty
\r
330 TxWt btfss TXSTA,TRMT ; transmission is complete if hi
\r
332 clrf STATUS ; RAM Page 0
\r
335 ;----------------------------------------------------------------------
\r