http://www.oocities.org/sstandfast/OBDII.htm
1 // File: VPWM.jal
2 // Author: Shawn Standfast
3 // Version 1.00.2
4 // 11/1/2005
5 // Library for OBDII Variable Pulse Width Modulation on PIC16F877(A) @ 20MHz
6 //
7 // *Note - This library utilizes the CCPX Module, Timer 1, Timer 2 W/ Interrupts
8 // Also, be sure to be in Bank 0 before using any procedures in this
9 // library.
10 //
11 // This library is designed around the SAE J1850 VPWM standard. It is assumed
12 // that the bus is a CSMA/CR (Carrier Sense, Multiple Access, Collision Resolution)
13 // type bus. Ultimate bus control is determined by bit-by-bit arbitration. The
14 // general message format used is SOF + 1 or 3 Header Bytes + 10 or 8 Data Bytes
15 // + 1 CRC Byte + EOD + EOF. Max Frame Length = 12 Bytes
16 //
17 // Nominal Pulse widths are as follows:
18 // +-----------+--------------+
19 // | SYMBOL | Pulse Width |
20 // |-----------+--------------+
21 // | Active 1 | 64uS |
22 // | Passive 0 | 64uS |
23 // | |
24 // | Passive 1 | 128uS |
25 // | Active 0 | 128uS |
26 // | |
27 // | SOF | 200uS |
28 // | EOD | 200uS |
29 // | |
30 // | EOF | 280-300uS |
31 // +-----------+--------------+
32 // Functions: vpw_send(byte in data) return bit
33 // Procedures: vpw_receive()
34 // get_frame(byte in frame_num)
35 //
36 // I/O Pin Definitions and Directions
37 //
38 // pin_c2_direction = input
39 // pin_c1_direction = output
40 //
41 // vpwin is pin_c2
42 // vpwout is pin_c1
43
44 // Required Libraries:
45 include jpic
46
47 // Set Bounds for Buffer Arrays
48 const array_check_indices = true
49
50 const array0_start = 0xA0 // Output Array Start
51 const array0_end = 0xAC // Output Array End
52 const array1_start = 0xAD // Input Buffer Array 1 Start
53 const array1_end = 0xB9 // Input Buffer Array 1 End
54 const array2_start = 0xBA // Input Buffer Array 2 Start
55 const array2_end = 0xC6 // Input Buffer Array 2 End
56 const array3_start = 0xC7 // Input Buffer Array 3 Start
57 const array3_end = 0xD3 // Input Buffer Array 3 End
58 const array4_start = 0xD4 // Processing Buffer Array Start
59 const array4_end = 0xE0 // Processing Buffer Array End
60
61 include bank_arrays
62
63 // Other Constants
64 const rising = 0x05 // configure for capture on rising edge
65 const falling = 0x04 // configure for capture on falling edge
66 const per_short = 0x50 // number of cycles for 64uS for tmr1
67 const per_long = 0xA0 // number of cycles for 128uS for tmr1
68 const per_sof = 0xFA // number of cycles for 200uS for tmr1
69 const per_eof = 0xAF // #cycles 280uS, must use 1:8 prescaler for EOF detection
70 const comp_drive_low = 0x09 // for ccp2con to drive CCP2 pin low on compare
71 const comp_drive_high = 0x08 // for ccp2con to drive CCP2 pin high on compare
72 const comp_only = 0x0A // for ccp2con to flag only
73
74 // I/O Pin Definitions and Directions
75 pin_c2_direction = input
76 pin_c1_direction = output
77 var bit vpwin is pin_c2
78 var bit vpwout is pin_c1
79 vpwout = false
80
81 // Some Variables
82 // Byte Variables RESERVED FOR INTERRUPT ROUTINE
83 var byte tmr1_low_old = 0x00, tmr1_high_old = 0x00 // stores old tmr1 values
84 var byte tmr1_low_new = 0x00, tmr1_high_new = 0x00 // stores new tmr1 values
85 var byte delta_low = 0x00, delta_high = 0x00 // stores the difference between
86 // tmr1_old & tmr1_new
87 var bit pulse_rec = off
88
89 // Configure ccpXmodule //--------------------------------------------------------
90 f877_ccp1con = 0x00
91 f877_ccp2con = 0x00
92
93 f877_ccpr2l = 0x00
94 f877_ccpr2h = 0x00
95
96 f877_ccpr1l = 0x00
97 f877_ccpr1h = 0x00
98
99 pir1_ccp1if = false // clear both CCP interrupt flags
100 pir2_ccp2if = false
101
102 // Initialize Timer1------------------------------------------------------------
103 //
104 // max frame width = SOF + 11*(8 Data Bits) + 1 CRC Byte + EOF
105 // SOF = 200uS
106 // EOF = 300uS
107 // Max Byte Width (longest byte = 0b_1010_1010) = 128uS*8 = 1.024mS
108 // Max Data Width = 12*1024mS = 12.288mS
109 // max frame width = 12.788mS
110 // tmr1 overflows w/ a 1:4 prescaler @ 52.4288mS ample room for an entire frame
111 //
112 // //---------------------------------------------------------------------------
113
114 f877_t1con = 0x00 // 1:4 prescaler for timer1
115 t1ckps1 = on
116 tmr1if = false // clear interupt flag
117 f877_tmr1h = 0x00
118 f877_tmr1l = 0x00
119
120 // Initialize Timer 2 // --------------------------------------------------------
121 f877_t2con = 0x02 // 1:16 prescaler 1:1 postscaler for timer2
122 f877_tmr2 = 0x00
123
124 pir1_tmr2if = false
125
126 // Initialize Periphial Interrupts // -------------------------------------------
127
128 asm BSF STATUS, 5 // bank 1
129 tmr1ie = off // disable tmr1 interupt flag
130 pie1_ccp1ie = on // enable ccp1 interrupt flag
131 pie2_ccp2ie = off // disable ccp2 interrupt flag
132 pie1_tmr2ie = off // disable timer2 interrupts
133 f877_pr2 = 0x58
134 asm BCF STATUS, 5 // bank 0
135
136 // disable interrupts //---------------------------------------------------------
137
138 intcon_gie = off
139 intcon_peie = off
140
141 // vpw_idle_chk is for internal use to check for inactivity on the Com. Bus
142 procedure vpw_idle_chk is
143 tmr1on = false
144 vpwout = false // make sure only transmitting a low signal
145 pir2_ccp2if = false
146 t1ckps1 = on
147 t1ckps0 = on // set 1:8 prescaler for timer1
148
149 f877_tmr1l = 0x00 // reset timer one high and low bytes
150 f877_tmr1h = 0x00
151
152 f877_ccpr2l = per_eof // set period for compare to be ~280uS
153 f877_ccpr2h = 0x00
154
155 f877_ccp2con = comp_only // set CCP2 module to only flag when timer times out
156
157 while vpwin loop end loop // loop until bus transisitions low
158
159 tmr1on = on // start timer
160
161 while ! pir2_ccp2if loop // wait while bus is low
162 if vpwin then // if activity detected on bus restart timer
163 f877_tmr1l = 0x00 // no need to reset high byte
164 end if
165 end loop
166
167 pir2_ccp2if = false // clear interrupt flag
168
169 tmr1on = false // stop timer 1
170
171 f877_tmr1l = 0x00 // reset timer 1
172 f877_tmr1h = 0x00
173
174 t1ckps0 = false // 1:4 prescaler for timer1
175 end procedure
176
177 procedure crc_calc(byte in data, byte in out crc ) is // calculates the CRC byte
178 var byte bit_point = 0x80 // that is appended to the end of the OBD message Frame
179 var byte poly // NOTE* Procedure is to be called continuously for each
180 for 8 loop // byte that is transmitted. However, once final byte is
181 if (bit_point & data) != 0 then // passed through the CRC routine the final result in crc_reg
182 if (crc & 0x80) != 0 then // must be complimented before appending to the message.
183 poly = 0x01 // For all messages, paramater CRC should be initialized to
184 else // 0xFF for the first itteration.
185 poly = 0x1C
186 end if
187 crc = ((crc << 1) | 1) ^ poly // original C Code for CRC posted on http:// obddiagnostics.com by B. Roadman
188 else // adapted to JAL by Shawn Standfast
189 poly = 0x00
190 if (crc & 0x80) != 0 then
191 poly = 0x1D
192 end if
193 crc = (crc << 1) ^ poly
194 end if
195 bit_point = bit_point >> 1
196 end loop
197 end procedure
198
199
200 // Function vpw_send(byte in data) shifts out "data" one bit at a time
201 // MSB first. Arbritration is taken care of during transmission. If the
202 // transmission is successful then the function returns true else it returns
203 // false. Call procedure repeatedly to send multiple bytes. just be sure to
204 // only send one start of frame symbol per message frame.
205
206 // Example Usage: *success is a var of type bit
207 // Send Single byte of data: success = vpw_send(data,true)
208 // tmr1on = false
209 // Send Multiple bytes in the same frame: success = vpw_send(data1,true)
210 // if success then
211 // success = vpw_send(data2,false)
212 // end if
213 // tmr1on = false
214 // Send "Array" of data:
215 // var bit send_sof = true
216 // var byte count = 0x00
217 // while ((success) & (count < arrayX_put_index)) loop
218 // temp = arrayX
219 // success = vpw_send(temp,send_sof)
220 // send_sof = false
221 // count = count + 1
222 // end loop
223 // tmr1on = false
224
225 function vpw_send (byte in data, bit in send_sof) return bit is
226 asm bcf intcon_gie // disables interrupts while sending. otherwise we can get
227 asm bcf intcon_peie // into all sorts of trouble. :)
228 f877_ccp1con = 0x00
229 var bit error_flag = false
230 var volatile bit bit_out at data : 7 // select bit to be transmitted
231 var bit dom_pass = false // keep track of active or passive symbol
232 var byte timer_low_byte, timer_high_byte, prtc_buf
233 var volatile byte next_bit = 0x00 // sets next pulse width
234
235 for 8 loop // shift data out one bit at a time; MSB first
236
237 if bit_out then // if bit to be sent is a One
238 if dom_pass then // send "Active" One
239 next_bit = per_short
240 else // send "Passive" One
241 next_bit = per_long
242 end if
243 else // Bit to be sent is a Zero
244 if dom_pass then // send active zero
245 next_bit = per_long
246 else // send "Passive" zero
247 next_bit = per_short
248 end if
249 end if
250 // start of frame takes care of period adjustment for first bit. If current
251 // itteration is not sending a SOF, must adjust new period by adding pulse width
252 // to current ccp2H:ccp2L registers.
253
254 if send_sof then // need to send a start of frame first?
255 // send start of frame plus first bit
256 vpw_idle_chk // verify bus is idle before beginning transmission
257
258 f877_ccp2con = comp_drive_low // bus will be high for SOF. Drive bus low
259 // when pulse width is achieved. should also
260 // drive output pin high beginning transmission
261
262 tmr1on = on // begin timing bus position
263
264 f877_ccpr2l = per_sof // set period for compare to be ~200uS
265 f877_ccpr2h = 0x00
266
267 pir2_ccp2if = false
268
269
270 error_flag = false // assume success unless failure occurs
271
272 while ! pir2_ccp2if loop end loop // wait until timer2 times out. Once
273 // this loop is exited our SOF symbol
274 // will have finished and our output
275 // pin will be low.
276 // If the bus is still active then that means another node is still
277 // transmitting. The only other allowed active symbol that lasts for
278 // this duration is a BREAK symbol. So we poll the bus for the shortest
279 // allowed BREAK time. If this is passed then we will cease our attempt
280 // to transmit.
281 while vpwin loop // allows for nodes with slower clocks to finish their
282 assembler // SOF's.
283 local shorter
284 movf f877_tmr1h,w // The new starting point for the compare register
285 movwf f877_ccpr2h // is updated while the other nodes finish.
286 movf f877_tmr1l,w
287 movwf f877_ccpr2l
288 movf f877_tmr1h,w // ensures proper loading of CCP2 with the current
289 movwf f877_ccpr2h // timer value
290 bcf status_Z
291 movlw 0x01
292 subwf f877_ccpr2h,w // magnitude comparison of the current high byte
293 BTFSS status_Z // if the current timer value is greater than
294 GOTO shorter // 0x128 then the maximum allowed transmission
295 movlw 0x28 // length for a SOF has been reached. If it isnt
296 bsf status_C
297 subwf f877_ccpr2l,w // then we need to poll the bus again and repeat.
298 BTFSS status_C
299 GOTO shorter
300 bsf error_flag
301 shorter:
302 end assembler
303 if error_flag then
304 vpwout = false
305 tmr1on = false
306 f877_tmr1l = 0x00
307 f877_tmr1h = 0x00
308 f877_ccp2con = 0x00
309 return false
310 end if
311 end loop
312
313 // SOF is always followed by data bytes. Prep for first bit to be sent
314 assembler // add next period to compare reference, 8-bit + 16-bit
315 bank MOVF next_bit,W
316 bank ADDWF f877_ccpr2l,f
317 BTFSC status_C
318 bank INCF f877_ccpr2h,f
319 end assembler
320
321 asm clrf f877_ccp2con // first bit to be transmitted is always low
322 f877_ccp2con = comp_drive_high // set ccp2 to drive output high on match
323
324 pir2_ccp2if = false // reset interrupt flag
325 send_sof = false // no more start of frame symbols to transmit
326 else // just send the remaining bits
327 assembler // add next period to compare reference. 8-bit + 16-bit
328 bank MOVF next_bit,W
329 bank ADDWF f877_ccpr2l,f
330 BTFSC status_C
331 bank INCF f877_ccpr2h,f
332 end assembler
333 end if
334
335 while ! pir2_ccp2if loop // wait until end of period, when loop is
336 // exited bus transition should be done.
337 prtc_buf = port_c // Check for arbitration. If output does not
338 prtc_buf = prtc_buf & 0x06 // match input then arbitration may be lost.
339 if ((prtc_buf == 0x04) & (! pir2_ccp2if)) then
340 assembler
341 bcf tmr1on // Comparison between the bus transition time
342 // and the time remaining before bus expected
343 // transition is used to compensate for clock
344 // mismatch. Therefore false "lost arbritration"
345 // is avoided. This portion only checks for nodes
346 // that transition early. Nodes that transition
347 // later are dealt with after this portion.
348 bsf status_C
349 bcf status_Z
350
351 local EXITE, EXIT
352 MOVF f877_tmr1l,W // determine delta between expected transition
353 SUBWF f877_ccpr2l,w // and actual transition time.
354 movwf timer_low_byte // timer_X_byte = ccpr2X - f877_tmr1X
355 MOVF f877_tmr1h,W
356 BTFSS status_C
357 INCF f877_tmr1h,W
358 SUBWF f877_ccpr2h,w
359 movwf timer_high_byte
360 btfss status, status_z // the difference between high bytes must be zero
361 goto EXITE
362 movlw 0x14 // to be within tolerance the difference must be less
363 bsf status_C // than 20 instructions. Setting the Carry/Borrow bit
364 subwf timer_low_byte,w // makes it available to borrow.
365 BTFSS status_C // If the low byte is >= 20 then a borrow
366 goto EXIT // will not have occured and status_c will still be set.
367 BTFSC status_Z // If the result is 0 then transition occured right on
368 goto EXIT // the boundary and is still valid.
369 EXITE: // check somewhere has not passed.
370 bsf error_flag
371 EXIT:
372 end assembler
373 if (error_flag) then // bus dominance lost.
374 vpwout = false // "Shut up and try again later"
375 tmr1on = false
376 f877_tmr1l = 0x00
377 f877_tmr1h = 0x00
378 f877_ccp2con = 0x00
379 return false
380 else // early transitioning node transitioned within specs. Change
381 f877_tmr1l = f877_ccpr2l // output and move on.
382 f877_tmr1h = f877_ccpr2h
383 tmr1on = on
384 end if
385 end if
386 if ((prtc_buf == 0x02) & (! pir2_ccp2if)) then // bus fault has been detected. Try again later.
387 vpwout = false
388 tmr1on = false
389 f877_tmr1l = 0x00
390 f877_tmr1h = 0x00
391 f877_ccp2con = 0x00
392 return false
393 end if
394 end loop
395
396 pir2_ccp2if = false // reset ccp2 interrupt flag
397
398 if dom_pass then // switch transition directions
399 // first must allow for nodes that are transmitting their active signals
400 // for just a little bit longer than we are. For the short pulse, the
401 // maximum allowed overshoot in time is 32uS and for the long pulse the
402 // maximum allowed overshoot in time is 34uS. Splitting the difference
403 // we will check for 33uS. However, I believe this to be incorrect and used 16uS.
404 if vpwin then // bus is still active
405 assembler
406 local loop1, done, exita
407 movlw comp_only
408 movwf f877_ccp2con
409 MOVlW 0x14
410 bank ADDWF f877_ccpr2l,f
411 BTFSC status_C
412 bank INCF f877_ccpr2h,f
413 loop1:
414 BTFSS vpwin // loops until either the input pin changes
415 goto done // or our "added" time expires.
416 BTFSS pir2_ccp2if
417 goto loop1
418 bcf tmr1on // if the program gets here then that means the input
419 bcf vpwout // is still set and our timer period has expired. If
420 clrf f877_tmr1l // we were sending a short pulse then it means arbitration
421 clrf f877_tmr1h // has been lost. If it is a long pulse then it could
422 clrf f877_ccp2con // mean a break symbol is being transmitted. Either way
423 bsf error_flag // we need to stop transmitting and exit.
424 bcf pir2_ccp2if
425 goto exita
426 done:
427 clrf f877_ccp2con // updates the compare registers with new
428 movf f877_tmr1h,w // starting values
429 movwf f877_ccpr2h
430 movf f877_tmr1l,w
431 movwf f877_ccpr2l
432 movf f877_tmr1h,w
433 movwf f877_ccpr2h
434 bcf pir2_ccp2if
435 exita:
436 end assembler
437 if error_flag then
438 return false
439 end if
440 end if
441 f877_ccp2con = comp_drive_high // if previously sending an active signal
442 dom_pass = false // next symbol will be passive. Ergo need
443 else // to drive bus high on next compare.
444 f877_ccp2con = comp_drive_low // Same logic here just opposite results
445 dom_pass = on // No need to check for devices with "longer"
446 end if // periods here because we have driven the
447 // bus high already.
448 data = data << 1 // shift in next bit to be sent
449 end loop
450 return true
451 end function
452
453 // procedure vpw_receive configures the ccp1 module to capture timer 1 and timer2
454 // to time inactivity. First ccp1 is configured to interrupt on the rising
455 // edge. On the first rising edge, timer 1 is started and the ccp1 module is
456 // reset for falling edge int. On the following edge interrupts, the two different
457 // captured timer 1 values are subtracted from each other to determine the
458 // pulse witdh. Then based upon which direction of the interrupting edge, the
459 // symbol is decoded. Once a SOF character has been decoded timer2 is enabled to start
460 // counting out 280uS to determine if IFS has been satisfied. Timer2 is reset
461 // on each valid pulse received. Therefore, timer2 clocks 280uS from the last bit received.
462 // Once a bit is received, it is placed in a bit buffer that is shifted left
463 // after each bit. When 8 bits have been received, that byte is placed into
464 // the first available frame buffer array.
465
466 // ***NOTE*** In-Frame Response has NOT been implimented yet!! If you are using
467 // this library for a VPW system that requires IFR then you will need to add it.
468 // I will get around to adding it sometime in the near future but right now I do
469 // not need it (GM doesn't use IFR).
470 // //--------------------------------------------------------------------------
471
472 function vpw_receive return bit is
473
474 var byte delta_low_old = 0x00, delta_high_old = 0x00 // buffers delta bytes
475 var volatile byte rec_buff = 0x00 // buffers the current received byte before
476 // loading into the buffer array
477 var byte bit_count = 0x00 // counts number of bits received
478 var volatile bit bit_rec = false // holds current received bit
479 var volatile bit data_rec = false // determines whether data has been received
480 var volatile bit bit_buff at rec_buff : 0 // stores current received bit
481 var volatile bit long_short = false // flag indicating long or short pulse
482 var volatile bit brk_rec = false // flag indicating a BRK symbol has been received
483 var volatile byte ccpconfig = 0x00 // stores current ccp1 configuration
484 var volatile bit sof_rec = false
485
486 f877_tmr1l = 0x00 // reset timer 1
487 f877_tmr1h = 0x00
488 tmr1_low_old = 0x00 // reset tmr1 storage variables
489 tmr1_high_old = 0x00
490 array4_put_index = 0x00 // reset processing buffer index to 0
491 pulse_rec = false
492 f877_ccp2con = 0x00
493
494 intcon_gie = on // enable interrupts
495 intcon_peie = on
496
497 pir1_tmr2if = false
498
499 vpw_idle_chk // wait until beginning of next frame before starting to receive
500
501 asm clrf f877_ccp1con
502 f877_ccp1con = rising
503
504 while ! pir1_tmr2if loop
505 while ! pulse_rec loop end loop
506 pulse_rec = false
507 delta_low_old = delta_low // buffer the delta values incase interrupt occurs
508 delta_high_old = delta_high // before we finish working with this pulse
509 ccpconfig = f877_ccp1con // buffer ccp1 configuration incase interrupt
510 // occurs before we finish working with this pulse
511
512 if ((delta_high_old == 0x00) ) then
513 if delta_low_old >= 0xCC then
514 sof_rec = on
515 tmr2on = on
516 bit_count = 0x00
517 f877_tmr2 = 0x00
518 array4_put_index = 0x00
519 elsif ((delta_low_old <= 0xCB) & (delta_low_old >= 0x78)) then
520 long_short = on
521 data_rec = on
522 f877_tmr2 = 0x00
523 elsif ((delta_low_old <= 0x77) & (delta_low_old >= 0x2A)) then
524 long_short = off
525 data_rec = on
526 f877_tmr2 = 0x00
527 else
528 data_rec = false
529 end if
530 elsif ((delta_high_old == 0x01) ) then
531 if ((delta_low_old >= 0x2B) & (! pir1_tmr2if)) then
532 brk_rec = on
533 sof_rec = false
534 data_rec = false
535 long_short = false
536 tmr1on = false
537 tmr2on = false
538 f877_tmr1l = 0x00
539 f877_tmr1h = 0x00
540 f877_tmr2 = 0x00
541 array4_put_index = 0x00
542 tmr1_low_old = 0x00
543 tmr1_high_old = 0x00
544 delta_low_old = 0x00
545 delta_high_old = 0x00
546 asm clrf f877_ccp1con
547 f877_ccp1con = rising
548 elsif delta_low_old < 0x2B then
549 sof_rec = on
550 tmr2on = on
551 pir1_tmr2if = false
552 bit_count = 0x00
553 f877_tmr2 = 0x00
554 array4_put_index = 0x00
555 end if
556 end if
557 if data_rec & sof_rec then
558 if ccpconfig == rising then // if the next interrupt edge will be rising
559 if long_short then // then that means the previous pulse was active.
560 bit_rec = off // that means a long pulse = 0 and a short pulse = 1
561 else
562 bit_rec = on
563 end if
564 else // next interrupt edge will be falling, indicating the
565 if long_short then // previous pulse was passive. long_pulse = 1 & short_pulse = 0
566 bit_rec = on
567 else
568 bit_rec = off
569 end if
570 end if
571 rec_buff = rec_buff << 1
572 bit_buff = bit_rec
573 data_rec = false
574 bit_count = bit_count + 1
575 end if
576 if bit_count == 0x08 then
577 array4 = rec_buff
578 bit_count = 0x00
579 end if
580 end loop
581 tmr1on = false
582 tmr2on = false
583 f877_ccp1con = 0x00
584 f877_tmr1l = 0x00
585 f877_tmr1h = 0x00
586 f877_tmr2 = 0x00
587 pir1_tmr2if = false
588 pir1_ccp1if = false
589
590 intcon_gie = false
591 intcon_peie = false
592 return brk_rec
593 end function
594
595
596 // Table for determining pulse widths from delta values:
597 // |long pulse| short pulse| SOF | break |
598 // | max | min | max | min | max | min | max | min |
599 // delta_high |0x00 | 0x00| 0x00 | 0x00| 0x01| 0x00| 0x01| 0x01|
600 // delta_low |0xCC | 0x78| 0x78 | 0x2A| 0x2B| 0xCC| 0x2B| 0x2B|
601 //
602 // Logic Flow: If delta_high > 0 then either SOF or BREAK
603 // if delta_low - 0x2B > 0 & delta_high > 0 then it is a break
604 // if delta_low - 0x2B <= 0 & delta_high > 0 then it is a SOF
605 // cases for delta_high == 0
606 // IF delta_low - 0xCC > 0 then it is a SOF
607 // If delta_low - 0x78 >= 0 & delta_low - 0xCC < 0 then it is a long pulse
608 // if delta_low - 0x2A >= 0 & delta_low - 0x78 < 0 then it is a short pulse
609 // if delta_low - 0x2A < 0 then it is too short
610
611 procedure interrupt_handler is // edge has been detected on ccp1
612 pragma interrupt
613 tmr1_low_new = f877_ccpr1l
614 tmr1_high_new = f877_ccpr1h
615 // tmr1_new - tmr1_old = delta
616 assembler // 16-bit subtraction of old values from the new
617 btfss tmr1on
618 bsf tmr1on
619 bank MOVF tmr1_low_old,W
620 bank SUBWF tmr1_low_new,W
621 bank MOVWF delta_low
622 bank MOVF tmr1_high_old,W
623 BTFSS status_C
624 INCFSZ tmr1_high_old,W
625 bank SUBWF tmr1_high_new,W
626 bank MOVWF delta_high
627 end assembler
628 tmr1_low_old = tmr1_low_new // replace old values with new ones
629 tmr1_high_old = tmr1_high_new
630
631 if ccp1m0 then // rising edge interrupt has been detected on ccp1
632 assembler
633 clrf f877_ccp1con // configure for falling edge
634 movlw falling
635 movwf f877_ccp1con
636 end assembler
637 else
638 // falling edge detected
639 assembler
640 clrf f877_ccp1con
641 movlw rising
642 movwf f877_ccp1con
643 end assembler
644 end if
645 pir1_ccp1if = false
646 pulse_rec = on
647 end procedure