PIC Microcontoller Input / Ouput Method

Detecting riseing and falling edge events

Dmitry Kiryashov [zews at AHA.RU] says

Brief explanation. You are to run 10 tasks "simultaneously". 4 of them are counting pulses (or reading some buses if you would like to ;) while 6 others are some timing, converting information, sending and receiving RS232 stuff. Each slice of code has some execution time t1,t2,t3,... You can run everything in straight way in one loop when one follows by another but you will got total loop execution time exactly equal to t1+t2+t3+...+t9+t10 which is enormously huge ;) Forgot to mention that those pulses of course are longer than 10 sampling periods.

But you can reduce it significantly if will run each task separately in different time slots. Timer constantly generates required slots. Two different types of processes: constant rate happened and floating. Sampling ports and doing RS232 for instance are constant rate processes. Those should be sampled by every pass but finding edges can be scheduled for later. To reduce total time you also need to do finding edges in parallel for all 4 port pins. So you are just collecting information for analyzing it in later time. Total execution time in this case of every loop is no more than tC+tMAX where tC is time for driving/reading constant rate part of all process and tMAX is maximal execution time of longest process. Average execution time is reduced anyway. So applying this trick with accumulating first and executing later you can either do it faster or move this part of code into timer driven interrupt and forget about it (it becomes to be transparent and you don't care about low level programming anymore just playing with flags, buffers and semaphores on "high" level of art ;))

XORing the new value with the previous value yields a mask for all the changed bits. ANDing the result of that with the old value yields 1s for all the falling edges, and ANDing with the new value yields 1s for all the rising edges. These falling and rising edge masks can be accumulated by ORing them with previous versions if that's what you want to do.

Anding that mask with inverted current bit also produces falling flag. It's very easy to check. So you need to store only one variable (last one) and being exchanging it with a new one will have flags the same time.

I've been asked to design some trick to reduce code execution time for rise and fall edge events on some port pins. For instance we have two samples, previous byte x0 and current byte x1. Each holds inside value like aAbBcCdD. As a result of playing with vetical math I realized that:

a) (x0^x1)&x1 = X0&x1 , which is "1" in case of rise event only
b) (X0^X1)&X1 = x0&X1 , which is "1" in case of fall event only

where X0=!x0, Y0=!y0

Example:

;...                            ;W holds 00ab00cd
        movwf   temp            ;save it for
        iorlw   0x55            ;future usage
        addwf   temp,W          ;get aAbBcCdD

        xorwf   prev,W          ;put x1 byte to prev
        xorwf   prev,F          ;get x0^x1 byte into W
        andwf   prev,W          ;get edges a) and b)
        iorwf   edges,F         ;detected edges
;...

We will get "rises detected" flags in 7.5.3.1. (case a) and "falls detected" flags in 6.4.2.0 (case b)

For instance edge can have a place somewhere within 10 samples period, so instead of reading and analizing it each time you can just accumulate it 10 times in edges cell and then analize it only ones. (don't forget to reset edges flags after that ;) Some clock saving anyway ;)

Probably someone can see another useful features of applying aAbBcCdD view of 4 bits variable.

How to convert 00ab00cd into aAbBcCdD? Bob Ammerman [RAMMERMAN at PRODIGY.NET] from RAm Systems says:

How about this:
   00ab00cd
+00100010
 ---------------
  0aAb0cCd
&01010101
 ----------------
  0a0b0c0d
+01010101
----------------
 aAbBcCdD

so, in code:

    ADDLW    B'00100010'
    ANDLW    B'01010101'
    ADDLW    B'01010101'

Dmitry Kiryashov [zews at AHA.RU] says

I got the same in two variations for pure W usage (without additional temp cell) and another one with temp cell usage.

2nd variation is:

        addlw   0x66    ;00ab00cd -> aAAbcCCd
        andlw   0xDD    ;-> aA0bcC0d
        addlw   0x11    ;-> aAbBcCdD

And with temp cell:

        movwf   temp    ;00ab00cd
        iorlw   0x55    ;01a101c1
        addwf   temp,W  ;aAbBcCdD

Last one is useful for storing original W for futher usage.

Questions:

See:

Christo Pelster of Pelster Says:

The Edge Detection decribed in the example above works fine. It may ben oted that the initial state in prev needs to contain the actual initial state. If one for example want to detect edges on a port with a pushbutton to ground (low-true), then the initial state needs to be set up to "1" (true). If this is not done, the code will result in a incorrect rising edge detection when it executes the first time. This is quite likely, as one ussually clears all varaibles used upon program startup and before executing the edge detection routine.

Comments: