OBDII Interface Project Source Code
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