SAE J1850 VPW Library on PIC16F877(A) @ 20MHz

-- File: VPWM.jal
-- Author:  Shawn Standfast
-- Version 1.00.2
-- 11/1/2005
-- Library for OBDII Variable Pulse Width Modulation on PIC16F877(A) @ 20MHz
--
-- *Note - This library utilizes the CCPX Module, Timer 1, Timer 2 W/ Interrupts
--         Also, be sure to be in Bank 0 before using any procedures in this
--         library.
--
--  This library is designed around the SAE J1850 VPWM standard.  It is assumed
--  that the bus is a CSMA/CR (Carrier Sense, Multiple Access, Collision Resolution)
--  type bus. Ultimate bus control is determined by bit-by-bit arbitration.  --  The general message format used is --  SOF + 1 or 3 Header Bytes + 10 or 8 Data Bytes + 1 CRC Byte + EOD + EOF.  --- Max Frame Length = 12 Bytes
--
--  Nominal Pulse widths are as follows:
-- ---------------------------
-- | SYMBOL    |  Pulse Width |
-- ---------------------------
-- | Active 1  |  64uS        |
-- | Passive 0 |  64uS        |
-- |                          |
-- | Passive 1 |  128uS       |
-- | Active 0  |  128uS       |
-- |                          |
-- | SOF       |  200uS       |
-- | EOD       |  200uS       |
-- |                          |
-- | EOF       |  280-300uS   |
-- ---------------------------
-- Functions:  vpw_send(byte in data) return bit
-- Procedures: vpw_receive()
--             get_frame(byte in frame_num)
--
-- I/O Pin Definitions and Directions
-- pin_c2_direction = input --- vpwin
-- pin_c1_direction = output -- vpwout

-- Required Libraries:
include jpic

-- Set Bounds for Buffer Arrays
 const array_check_indices = true

 const array0_start = 0xA0      --  Output Array Start
 const array0_end   = 0xAC      --  Output Array End
 const array1_start = 0xAD      --  Input Buffer Array 1 Start
 const array1_end   = 0xB9      --  Input Buffer Array 1 End
 const array2_start = 0xBA      --  Input Buffer Array 2 Start
 const array2_end   = 0xC6      --  Input Buffer Array 2 End
 const array3_start = 0xC7      --  Input Buffer Array 3 Start
 const array3_end   = 0xD3      --  Input Buffer Array 3 End
 const array4_start = 0xD4      --  Processing Buffer Array Start
 const array4_end   = 0xE0      --  Processing Buffer Array End

 include bank_arrays

--  Other Constants
 const rising = 0x05 ----- configure for capture on rising edge
 const falling = 0x04  --- configure for capture on falling edge
 const per_short = 0x50 -- number of cycles for 64uS for tmr1
 const per_long = 0xA0  -- number of cycles for 128uS for tmr1
 const per_sof = 0xFA   -- number of cycles for 200uS for tmr1

 const per_eof = 0xAF ---- #cycles 280uS, must use 1:8 prescaler for EOF detection
 const comp_drive_low = 0x09 --- for ccp2con to drive CCP2 pin low on compare
 const comp_drive_high = 0x08 -- for ccp2con to drive CCP2 pin high on compare
 const comp_only = 0x0A -------- for ccp2con to flag only

-- I/O Pin Definitions and Directions
 pin_c2_direction = input
 pin_c1_direction = output
 var bit vpwin is pin_c2
 var bit vpwout is pin_c1
 vpwout = false

-- Some Variables
-- Byte Variables RESERVED FOR INTERRUPT ROUTINE
 var byte tmr1_low_old = 0x00, tmr1_high_old = 0x00 -- stores old tmr1 values
 var byte tmr1_low_new = 0x00, tmr1_high_new = 0x00 -- stores new tmr1 values
 var byte delta_low = 0x00, delta_high = 0x00 -- stores the difference between
                                              -- tmr1_old & tmr1_new
 var bit pulse_rec = off

-- Configure ccpXmodule ----------------------------------------------------------
f877_ccp1con = 0x00
f877_ccp2con = 0x00

f877_ccpr2l = 0x00
f877_ccpr2h = 0x00

f877_ccpr1l = 0x00
f877_ccpr1h = 0x00

pir1_ccp1if = false -- clear both CCP interrupt flags
pir2_ccp2if = false

-- Initialize Timer1------------------------------------------------------------
--
-- max frame width = SOF + 11*(8 Data Bits) + 1 CRC Byte + EOF
-- SOF = 200uS-- EOD = 200Us
-- EOF = 300uS
-- Max Byte Width 1.024 ms = (longest byte = 0xAA = 0b_1010_1010) = 128uS*8
-- Max Data Width = 12* 1.024 mS = 12.288mS
-- max frame width = 12.988mS = 0.2 + 12.288 + 0.2 + 0.3 = SOF + DATA + EOD + EOF
-- tmr1 overflows w/ a 1:4 prescaler @ 52.4288mS ample room for an entire frame
--
-- -----------------------------------------------------------------------------

 f877_t1con = 0x00  -- 1:4 prescaler for timer1
 t1ckps1 = on
 tmr1if = false  --  clear interupt flag
 f877_tmr1h = 0x00
 f877_tmr1l = 0x00

-- Initialize Timer 2 ----------------------------------------------------------

 f877_t2con = 0x02  -- 1:16 prescaler 1:1 postscaler for timer2
 f877_tmr2 = 0x00

 pir1_tmr2if = false

-- Initialize Periphial Interrupts ---------------------------------------------

 asm BSF STATUS, 5 -- bank 1
 tmr1ie = off -- disable tmr1 interupt flag
 pie1_ccp1ie = on -- enable ccp1 interrupt flag
 pie2_ccp2ie = off  -- disable ccp2 interrupt flag
 pie1_tmr2ie = off -- disable timer2 interrupts
 f877_pr2 = 0x58
 asm BCF STATUS, 5  -- bank 0

-- disable interrupts -----------------------------------------------------------

 intcon_gie = off
 intcon_peie = off

--  vpw_idle_chk is for internal use to check for inactivity on the Com. Bus
 procedure vpw_idle_chk is
   tmr1on = false
   vpwout = false -- make sure only transmitting a low signal
   pir2_ccp2if = false
   t1ckps1 = on
   t1ckps0 = on -- set 1:8 prescaler for timer1

   f877_tmr1l = 0x00  -- reset timer one high and low bytes
   f877_tmr1h = 0x00

   f877_ccpr2l = per_eof  -- set period for compare to be ~280uS
   f877_ccpr2h = 0x00

   f877_ccp2con = comp_only -- set CCP2 module to only flag when timer times out

   while vpwin loop    end loop  -- loop until bus transisitions low

   tmr1on = on     -- start timer

   while ! pir2_ccp2if loop  -- wait while bus is low
     if vpwin then      -- if activity detected on bus restart timer
       f877_tmr1l = 0x00 -- no need to reset high byte
     end if
   end loop

   pir2_ccp2if = false -- clear interrupt flag

   tmr1on = false   -- stop timer 1

   f877_tmr1l = 0x00 -- reset timer 1
   f877_tmr1h = 0x00

   t1ckps0 = false  -- 1:4 prescaler for timer1
 end procedure

 procedure crc_calc(byte in data, byte in out crc ) is -- calculates the CRC byte
 var byte bit_point = 0x80  -- that is appended to the end of the OBD message Frame
 var byte poly              -- NOTE* Procedure is to be called continuously for each
 for 8 loop                 -- byte that is transmitted.  However, once final byte is
   if (bit_point & data) != 0 then -- passed through the CRC routine the final result in crc_reg
     if (crc & 0x80) != 0 then  -- must be complimented before appending to the message.
       poly = 0x01          -- For all messages, paramater CRC should be initialized to
     else                   -- 0xFF for the first itteration.
       poly = 0x1C
     end if
     crc = ((crc << 1) | 1) ^ poly -- original C Code for CRC posted on http://obddiagnostics.com by B. Roadman
   else                            -- adapted to JAL by Shawn Standfast
     poly = 0x00
     if (crc & 0x80) != 0 then
       poly = 0x1D
     end if
     crc = (crc << 1) ^ poly
   end if
   bit_point = bit_point >> 1
 end loop
end procedure

 --  Function vpw_send(byte in data) shifts out "data" one bit at a time MSB first.   --  Arbritration is taken care of during transmission.  If the transmission is successful then the function returns true  -- else it returns false.  Call procedure repeatedly to send multiple bytes.  -- just be sure to only send one start of frame symbol per message frame.

 --  Example Usage: *success is a var of type bit
 --  Send Single byte of data:  success = vpw_send(data,true)
 --                             tmr1on = false
 --  Send Multiple bytes in the same frame:  success = vpw_send(data1,true)
 --                                          if success then
 --                                            success = vpw_send(data2,false)
 --                                          end if
 --                                          tmr1on = false
 --  Send "Array" of data:
 --                        var bit send_sof = true
 --                        var byte count = 0x00
 --                        while ((success) & (count < arrayX_put_index)) loop
 --                          temp = arrayX
 --                          success = vpw_send(temp,send_sof)
 --                          send_sof = false
 --                          count = count + 1
 --                        end loop
 --                        tmr1on = false

 function vpw_send (byte in data, bit in send_sof) return bit is
   asm bcf intcon_gie -- disables interrupts while sending. otherwise we can get
   asm bcf intcon_peie -- into all sorts of trouble. :)
   f877_ccp1con = 0x00
   var bit error_flag = false
   var volatile bit bit_out at data : 7 -- select bit to be transmitted
   var bit dom_pass = false  -- keep track of active or passive symbol
   var byte timer_low_byte, timer_high_byte, prtc_buf
   var volatile byte next_bit = 0x00 -- sets next pulse width

   for 8 loop  -- shift data out one bit at a time; MSB first

     if bit_out then  -- if bit to be sent is a One
       if dom_pass then  -- send "Active" One
         next_bit = per_short
       else  -- send "Passive" One
         next_bit = per_long
       end if
     else  -- Bit to be sent is a Zero
       if dom_pass then  -- send active zero
         next_bit = per_long
       else  -- send "Passive" zero
         next_bit = per_short
       end if
     end if
-- start of frame takes care of period adjustment for first bit.  If current
-- itteration is not sending a SOF, must adjust new period by adding pulse width
-- to current ccp2H:ccp2L registers.

     if send_sof then  -- need to send a start of frame first?
                    -- send start of frame plus first bit
       vpw_idle_chk -- verify bus is idle before beginning transmission

       f877_ccp2con = comp_drive_low -- bus will be high for SOF.  Drive bus low
                                 -- when pulse width is achieved.  should also
                                 -- drive output pin high beginning transmission

       tmr1on = on     -- begin timing bus position

       f877_ccpr2l = per_sof  -- set period for compare to be ~200uS
       f877_ccpr2h = 0x00

       pir2_ccp2if = false

       error_flag = false   -- assume success unless failure occurs

       while ! pir2_ccp2if loop end loop -- wait until timer2 times out.  Once
                                         -- this loop is exited our SOF symbol
                                         -- will have finished and our output
                                         -- pin will be low.
       -- If the bus is still active then that means another node is still
       -- transmitting.  The only other allowed active symbol that lasts for
       -- this duration is a BREAK symbol.  So we poll the bus for the shortest
       -- allowed BREAK time.  If this is passed then we will cease our attempt
       -- to transmit.
       while vpwin loop  -- allows for nodes with slower clocks to finish their
         assembler       -- SOF‘s.
           local shorter
           movf f877_tmr1h,w  -- The new starting point for the compare register
           movwf f877_ccpr2h  -- is updated while the other nodes finish.
           movf f877_tmr1l,w
           movwf f877_ccpr2l
           movf f877_tmr1h,w  -- ensures proper loading of CCP2 with the current
           movwf f877_ccpr2h  -- timer value
           bcf status_Z
           movlw 0x01
           subwf f877_ccpr2h,w -- magnitude comparison of the current high byte
           BTFSS status_Z      -- if the current timer value is greater than
             GOTO shorter      -- 0x128 then the maximum allowed transmission
           movlw 0x28          -- length for a SOF has been reached.  If it isnt
           bsf status_C
           subwf f877_ccpr2l,w -- then we need to poll the bus again and repeat.
           BTFSS status_C
             GOTO shorter
           bsf error_flag
   shorter:
         end assembler
         if error_flag then
           vpwout = false
           tmr1on = false
           f877_tmr1l = 0x00
           f877_tmr1h = 0x00
           f877_ccp2con = 0x00
           return false
          end if
        end loop

   -- SOF is always followed by data bytes.  Prep for first bit to be sent
       assembler  -- add next period to compare reference, 8-bit + 16-bit
        bank MOVF   next_bit,W
        bank ADDWF  f877_ccpr2l,f
             BTFSC  status_C
        bank INCF  f877_ccpr2h,f
       end assembler

       asm clrf f877_ccp2con      -- first bit to be transmitted is always low
       f877_ccp2con = comp_drive_high -- set ccp2 to drive output high on match

       pir2_ccp2if = false -- reset interrupt flag
       send_sof = false -- no more start of frame symbols to transmit
     else -- just send the remaining bits
       assembler  -- add next period to compare reference.  8-bit + 16-bit
       bank MOVF   next_bit,W
       bank ADDWF  f877_ccpr2l,f
            BTFSC  status_C
       bank INCF  f877_ccpr2h,f
       end assembler
     end if

     while ! pir2_ccp2if loop   -- wait until end of period, when loop is
                                -- exited bus transition should be done.
        prtc_buf = port_c  -- Check for arbitration.  If output does not
        prtc_buf = prtc_buf & 0x06 -- match input then arbitration may be lost.
        if ((prtc_buf == 0x04) & (! pir2_ccp2if)) then
        assembler
          bcf tmr1on           -- Comparison between the bus transition time
                               -- and the time remaining before bus expected
                               -- transition is used to compensate for clock
                               -- mismatch.  Therefore false "lost arbritration"
                               -- is avoided. This portion only checks for nodes
                               -- that transition early.  Nodes that transition
                               -- later are dealt with after this portion.
          bsf status_C
          bcf status_Z

          local EXITE, EXIT
          MOVF   f877_tmr1l,W   -- determine delta between expected transition
          SUBWF  f877_ccpr2l,w  -- and actual transition time.
          movwf  timer_low_byte -- timer_X_byte = ccpr2X - f877_tmr1X
          MOVF   f877_tmr1h,W
          BTFSS  status_C
            INCF   f877_tmr1h,W
          SUBWF  f877_ccpr2h,w
          movwf  timer_high_byte
          btfss  status, status_z -- the difference between high bytes must be zero
          goto   EXITE
          movlw  0x14    -- to be within tolerance the difference must be less
          bsf status_C   -- than 20 instructions.  Setting the Carry/Borrow bit
          subwf  timer_low_byte,w -- makes it available to borrow.
          BTFSS  status_C  -- If the low byte is >= 20 then a borrow
            goto EXIT -- will not have occured and status_c will still be set.
          BTFSC status_Z -- If the result is 0 then transition occured right on
            goto EXIT    -- the boundary and is still valid.
      EXITE: -- check somewhere has not passed.
          bsf error_flag
      EXIT:
      end assembler
          if (error_flag) then -- bus dominance lost.
            vpwout = false                      -- "Shut up and try again later"
            tmr1on = false
            f877_tmr1l = 0x00
            f877_tmr1h = 0x00
            f877_ccp2con = 0x00
            return false
          else -- early transitioning node transitioned within specs.  Change
            f877_tmr1l = f877_ccpr2l -- output and move on.
            f877_tmr1h = f877_ccpr2h
            tmr1on = on
          end if
       end if
       if ((prtc_buf == 0x02) & (! pir2_ccp2if)) then -- bus fault has been detected. Try again later.
         vpwout = false
         tmr1on = false
         f877_tmr1l = 0x00
         f877_tmr1h = 0x00
         f877_ccp2con = 0x00
         return false
       end if
     end loop

     pir2_ccp2if = false -- reset ccp2 interrupt flag

     if dom_pass then -- switch transition directions
       -- first must allow for nodes that are transmitting their active signals
       -- for just a little bit longer than we are.  For the short pulse, the
       -- maximum allowed overshoot in time is 32uS and for the long pulse the
       -- maximum allowed overshoot in time is 34uS.  Splitting the difference
       -- we will check for 33uS. However, I believe this to be incorrect and used 16uS.
       if vpwin then -- bus is still active
         assembler
           local loop1, done, exita
           movlw comp_only
           movwf f877_ccp2con
            MOVlW 0x14
       bank ADDWF  f877_ccpr2l,f
            BTFSC  status_C
       bank INCF  f877_ccpr2h,f
        loop1:
            BTFSS vpwin   -- loops until either the input pin changes
              goto done   -- or our "added" time expires.
            BTFSS pir2_ccp2if
              goto loop1
            bcf tmr1on  -- if the program gets here then that means the input
            bcf vpwout  -- is still set and our timer period has expired.  If
            clrf f877_tmr1l -- we were sending a short pulse then it means arbitration
            clrf f877_tmr1h -- has been lost.  If it is a long pulse then it could
            clrf f877_ccp2con -- mean a break symbol is being transmitted.  Either way
            bsf error_flag -- we need to stop transmitting and exit.
            bcf pir2_ccp2if
            goto exita
       done:
            clrf f877_ccp2con   -- updates the compare registers with new
            movf f877_tmr1h,w   -- starting values
            movwf f877_ccpr2h
            movf f877_tmr1l,w
            movwf f877_ccpr2l
            movf f877_tmr1h,w
            movwf f877_ccpr2h
            bcf pir2_ccp2if
        exita:
         end assembler
            if error_flag then
              return false
            end if
       end if
       f877_ccp2con = comp_drive_high -- if previously sending an active signal
       dom_pass = false               -- next symbol will be passive. Ergo need
     else                             -- to drive bus high on next compare.
       f877_ccp2con = comp_drive_low  -- Same logic here just opposite results
       dom_pass = on                  -- No need to check for devices with "longer"
     end if                           -- periods here because we have driven the
                                      -- bus high already.
     data = data << 1   -- shift in next bit to be sent
   end loop
   return true
 end function

 -- procedure vpw_receive configures the ccp1 module to capture timer 1 and timer2
 -- to time inactivity.  First ccp1 is configured to interrupt on the rising
 -- edge.  On the first rising edge, timer 1 is started and the ccp1 module is
 -- reset for falling edge int. On the following edge interrupts, the two different
 -- captured timer 1 values are subtracted from each other to determine the
 -- pulse witdh.  Then based upon which direction of the interrupting edge, the
 -- symbol is decoded. Once a SOF character has been decoded timer2 is enabled to start
 -- counting out 280uS to determine if IFS has been satisfied. Timer2 is reset
 -- on each valid pulse received.  Therefore, timer2 clocks 280uS from the last bit received.
 --  Once a bit is received, it is placed in a bit buffer that is shifted left
 --  after each bit.  When 8 bits have been received, that byte is placed into
 --  the first available frame buffer array.

 -- ***NOTE*** In-Frame Response has NOT been implimented yet!! If you are using
 -- this library for a VPW system that requires IFR then you will need to add it.
 -- I will get around to adding it sometime in the near future but right now I do
 -- not need it (GM doesn‘t use IFR).
 -- ----------------------------------------------------------------------------

 function vpw_receive return bit is

   var byte delta_low_old = 0x00, delta_high_old = 0x00 -- buffers delta bytes
   var volatile byte rec_buff = 0x00  -- buffers the current received byte before
                                      -- loading into the buffer array
   var byte bit_count = 0x00 -- counts number of bits received
   var volatile bit bit_rec = false -- holds current received bit
   var volatile bit data_rec = false -- determines whether data has been received
   var volatile bit bit_buff at rec_buff : 0 -- stores current received bit
   var volatile bit long_short = false -- flag indicating long or short pulse
   var volatile bit brk_rec = false -- flag indicating a BRK symbol has been received
   var volatile byte ccpconfig = 0x00 -- stores current ccp1 configuration
   var volatile bit sof_rec = false

   f877_tmr1l = 0x00 -- reset timer 1
   f877_tmr1h = 0x00
   tmr1_low_old = 0x00 -- reset tmr1 storage variables
   tmr1_high_old = 0x00
   array4_put_index = 0x00 -- reset processing buffer index to 0
   pulse_rec = false
   f877_ccp2con = 0x00

   intcon_gie = on -- enable interrupts
   intcon_peie = on

   pir1_tmr2if = false

   vpw_idle_chk -- wait until beginning of next frame before starting to receive

   asm clrf f877_ccp1con
   f877_ccp1con = rising

   while ! pir1_tmr2if loop
     while ! pulse_rec loop end loop
     pulse_rec = false
     delta_low_old = delta_low  -- buffer the delta values incase interrupt occurs
     delta_high_old = delta_high -- before we finish working with this pulse
     ccpconfig = f877_ccp1con    -- buffer ccp1 configuration incase interrupt
                                 -- occurs before we finish working with this pulse

      if ((delta_high_old == 0x00) ) then
        if delta_low_old >= 0xCC then
          sof_rec = on
          tmr2on = on
          bit_count = 0x00
          f877_tmr2 = 0x00
          array4_put_index = 0x00
        elsif ((delta_low_old <= 0xCB) & (delta_low_old >= 0x78)) then
          long_short = on
          data_rec = on
          f877_tmr2 = 0x00
        elsif ((delta_low_old <= 0x77) & (delta_low_old >= 0x2A)) then
          long_short = off
          data_rec = on
          f877_tmr2 = 0x00
        else
          data_rec = false
        end if
      elsif ((delta_high_old == 0x01) ) then
        if ((delta_low_old >= 0x2B) & (! pir1_tmr2if)) then
          brk_rec = on
          sof_rec = false
          data_rec = false
          long_short = false
          tmr1on = false
          tmr2on = false
          f877_tmr1l = 0x00
          f877_tmr1h = 0x00
          f877_tmr2 = 0x00
          array4_put_index = 0x00
          tmr1_low_old = 0x00
          tmr1_high_old = 0x00
          delta_low_old = 0x00
          delta_high_old = 0x00
          asm clrf f877_ccp1con
          f877_ccp1con = rising
        elsif delta_low_old < 0x2B then
          sof_rec = on
          tmr2on = on
          pir1_tmr2if = false
          bit_count = 0x00
          f877_tmr2 = 0x00
          array4_put_index = 0x00
        end if
      end if
      if data_rec & sof_rec then
        if ccpconfig == rising then -- if the next interrupt edge will be rising
          if long_short then        -- then that means the previous pulse was active.
            bit_rec = off           -- that means a long pulse = 0 and a short pulse = 1
          else
            bit_rec = on
          end if
        else                -- next interrupt edge will be falling, indicating the
          if long_short then -- previous pulse was passive.  long_pulse = 1 & short_pulse = 0
            bit_rec = on
          else
            bit_rec = off
          end if
        end if
        rec_buff = rec_buff << 1
        bit_buff = bit_rec
        data_rec = false
        bit_count = bit_count + 1
      end if
      if bit_count == 0x08 then
        array4 = rec_buff
        bit_count = 0x00
      end if
   end loop
   tmr1on = false
   tmr2on = false
   f877_ccp1con = 0x00
   f877_tmr1l = 0x00
   f877_tmr1h = 0x00
   f877_tmr2 = 0x00
   pir1_tmr2if = false
   pir1_ccp1if = false

   intcon_gie = false
   intcon_peie = false
   return brk_rec
 end function

 -- Table for determining pulse widths from delta values:
 --            |long pulse| short pulse|    SOF     |   break   |
 --            | max | min | max  | min | max | min | max | min |
 -- delta_high |0x00 | 0x00| 0x00 | 0x00| 0x01| 0x00| 0x01| 0x01|
 -- delta_low  |0xCC | 0x78| 0x78 | 0x2A| 0x2B| 0xCC| 0x2B| 0x2B|
 --
 -- Logic Flow:  If delta_high > 0 then either SOF or BREAK
 --              if delta_low - 0x2B > 0 & delta_high > 0 then it is a break
 --              if delta_low - 0x2B <= 0 & delta_high > 0 then it is a SOF
 --      cases for delta_high == 0
 --      IF delta_low - 0xCC > 0 then it is a SOF
 --      If delta_low - 0x78 >= 0 & delta_low - 0xCC < 0 then it is a long pulse
 --      if delta_low - 0x2A >= 0 & delta_low - 0x78 < 0 then it is a short pulse
 --      if delta_low - 0x2A < 0 then it is too short

 procedure interrupt_handler is  -- edge has been detected on ccp1
 pragma interrupt
      tmr1_low_new = f877_ccpr1l
      tmr1_high_new = f877_ccpr1h
--     tmr1_new - tmr1_old = delta
      assembler -- 16-bit subtraction of old values from the new
      btfss tmr1on
        bsf tmr1on
      bank   MOVF   tmr1_low_old,W
      bank   SUBWF  tmr1_low_new,W
      bank   MOVWF  delta_low
      bank   MOVF   tmr1_high_old,W
             BTFSS  status_C
             INCFSZ tmr1_high_old,W
      bank   SUBWF  tmr1_high_new,W
      bank   MOVWF  delta_high
      end assembler
      tmr1_low_old = tmr1_low_new  -- replace old values with new ones
      tmr1_high_old = tmr1_high_new

    if ccp1m0 then  -- rising edge interrupt has been detected on ccp1
      assembler
      clrf f877_ccp1con  -- configure for falling edge
      movlw falling
      movwf f877_ccp1con
      end assembler
    else
--    falling edge detected
      assembler
        clrf f877_ccp1con
        movlw rising
        movwf f877_ccp1con
      end assembler
    end if
    pir1_ccp1if = false
    pulse_rec = on
 end procedure
 
时间: 2024-10-04 19:22:26

SAE J1850 VPW Library on PIC16F877(A) @ 20MHz的相关文章

SAE J1850 汽车总线协议 VPW 物理层驱动程序在STM32芯片上的实现

VPW(Variable Pulse Width)是一种可变脉宽调制的汽车总线通讯方式,常用于美系的福特,通用,克莱斯勒等汽车上,主要用途为车用信息中心.仪表显示.故障检测诊断等. VPW – 以数据位为基本单位进行传输,定义了一个起始位(SOF):200us 的高电平代表开始进行位传输,定义了一个结束位(EOF):280us 的低电平表示位传输正常结束,起始位之后的数据位表示方式可认为为:电平不断的翻转,每次产生一次翻转便产生一个新的数据位,这个数据位为"0"还是"1&qu

ThinkPHP(SAE)调用验证码不能正确调用验证码

现在,将官网的方法贴出: SAE下使用ThinkPHP验证码,非SaeVcode SaeVcode其实很弱弱,连验证码的尺寸都不能设置,对于开发和美工来说,是件很头痛的事情,经过我们技术员简单测试,发现ThinkPHP自带的验证码是可以在SAE下正常运行的. 1.将“ThinkPHP\Extend\Library\ORG\Util\String.class.php”拷贝至“ ThinkPHP\Extend\Engine\Sae\Lib\Extend\Library\ORG\Util\String

汽车OBD接口定义

汽车上的OBD-II接口(母): ELM327用到的引脚: 2: SAE-J1850 PWM和SAE-1850 VPW总线(+) 4. 车身地 5. 信号地 6. CAN high (ISO 15765-4和SAE-J2284)  7. ISO 9141-2和ISO 14230-4总线的K线 10. SAE-J1850 PWM协议总线(-)(not SAE-1850 VPW) Europe, etc. Chrysler CCD Bus(+) 14. CAN low (ISO 15765-4和SA

开发人员不可不看的 OBD通讯协议知识

OBD-II Network Standards» J1850 VPW– Adopted by GM; also known as Class 2.– Adopted by Chrysler (known as J1850).– Some references to VPW mode heard about in regards to Toyota (and Honda ?).– 10.4 kbps, single wire.» J1850 PWM– Adopted by Ford; also

SAE Java相关问题小结

转自:http://blog.csdn.net/bhq2010/article/details/8580412 Sae中使用的servlet容器是jetty7.4.x 我想在web.xml中配置一个自己编写的servlet,实现web启动时的初始化工作,但是总是出现各种问题,下面总结了一下在sae中使用java的一些注意事项: 1.在eclipse中开发java web项目时,我总喜欢直接把需要的jar包复制到WEB-INF/lib下,但在开发sae项目时,最好把需要的jar包放到usr lib

CAN/J1850/

(1)CAN:(差分信号)有信号CANH=3.5V,CANL=1.5V, 没有信号CANH=2.5V,CANL=2.5V 速率:CAN系统又分为高速和低速,高速CAN系统采用硬线是动力型,速度:500kbps,控制ECU.ABS等:低速CAN是舒适型,速度:125Kbps,主要控制仪表.防盗等. (2)J1850: H:4.25V~20V L:低于3.5V 速率:20kbps~125kbps (定:美)用于福特(Ford).通用汽车(General Moter:GM).克赖斯勒(Chrysler

在 SAE 上部署 ThinkPHP 5.0 RC4

缘起 SAE 和其他的平台有些不同,不能在服务器上运行 Composer 来安装各种包,必须把源码都提交上去.一般的做法,可能是直接把源码的所有文件复制到目录中,添加到版本库.不过,这样就失去了与上游代码的同步的优势.还好 git 提供了另一个功能叫 subtree,不但提供了版本追踪的功能,让代码可以一直和上游同步,同时源码文件还能提交到当前的仓库中. 过程 首先,当然是要安装 git 的 subtree 命令.这个命令虽然随 git 一起安装了,但默认并没有启用.每个平台的安装方法有所不同,

win7 64位系统 PB连接oracle数据库出现“oracle library oci.dll could not be loaded”问题的解决方法

今天与大家分享一个自己的学习笔记,希望能给遇到同样问题的人带来帮助. 不知道大家在win7 64位系统下用 PB连接oracle数据库时,是否遇到过“oracle library oci.dll could not be loaded”问题. 今天,在win7 64位系统下用 PB连接oracle数据库时,一直出现上述错误,在百度上找了很久,都没有找到一个完整的解决方案,咨询了很多人,(他们都说是我的PB和oracle没装好,但我装的时候没出现任何问题,一切都很顺利,而且PB和oracle都能正

编译hadoop 的native library

os:centos 6.7 x64 要解决的问题:   WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable 解决的必要性 hadoop的cache和短路读(Short-Circuit Local Reads)都需要native library的支持 解决步骤 编译方法是 http://had