On Fri, 31 Jan 2003, Scott Pierce wrote: > I have four inputs on PortA that I want to read pulse values from but not > at the same time. Say I have a subroutine to read PortA pin 0, grab the > pulse length from it, then return to the calling subroutine, then I want > to use the same pulse reading subroutine to grab the pulse length on PortA > pin 1 and so on. Is there a way to do this or do I have to write a > separate subroutine for each pin on PortA. The reason I ask is because I > am using BTFSC PORTA, PIN to wait until the pin goes low. My understanding > of BTFSC is that the bit (PIN) value must be a literal and cannot be stored > in a register. If I tried to use a register value it would take the actual > address of the register and try to use that instead of what is contained in > the register. Do I understand that correctly? Is there a trick to doing > what I want to do? Here is a snippet of my source code so you can get a > better idea of what I'm trying to do. As you will see, The four > subroutines basically do the exact same thing with the exception of reading > a different pin on PortA and writing to one of four different > registers. This would not be a problem except this fills half of my > program memory on my 16F84A and this code is only a third or so of the end > program. If there is no work around, should I just move to a PIC with more > program memory? Thanks in advance. It looks to me that you're doing more than "measuring" pulses. (If you ever wish to just measure pulses though, then check out : http://www.piclist.com/techref/microchip/pulsewidth-sd.htm ) It might make more sense to write this in terms of state machines. It looks like for each pulse input you have (at least) four states: 1) Idle 2) low and waiting for high 3) high waiting for low 4) high (and counting) and waiting for low. Since Wouter has mentioned Vertical Counters, maybe this is a good time to introduce an example. It might be totally applicable to your application, but it ought to be an interesting way to approach the problem. --- Let's assume you wish to simultaneously measure 4 pulses (although, you can measure 8 in the same amount of time). Let's assume that you wish to allow each pulse counter to be 4-bits wide (or longer as you'll soon see). Before diving into the particulars, let's look at a single vertical counter. In general, a counter can be expressed like: if(counting enabled) count = count + 1; If the counter is just a single bit wide, then you can write the truth table like this: count enable | count carry ----------------+------------- 0 0 0 0 0 1 1 0 1 0 1 0 1 1 0 1 And the boolean equations are (assuming VHDL-like excution and not C-like) count = count ^ enable carry = count & enable In PIC assembly: ; W = Enable xorwf count,F comf count,F andwf count,W comf count,F ; W now is the carry out If you change your perspective slightly and call the "Enable" bit a carry- in, then you can see that we've developed a 1-bit adder! Of course, one of the addends is zero... In psuedo code, you could express it like so. if(carry is set) { bit = bit + 1 if(bit == 0) { // bit rolled over so set carry carry = 1; } else { carry = 0; } } The truth table: bit carry in | bit carry out ----------------+------------------- 0 0 0 0 0 1 1 0 1 0 1 0 1 1 0 1 But this is exactly the same truth table as above! State machine ------------- For this particular application, there are four states and thus we'll need at least two bits per state to encode them. Idle ---- stays in idle until instructed to start the algorithm State 1 ------- Input is high, we're waiting for it to go low. When it goes low, we'll go to State 2 State 2 ------- Input is low, we're waiting for it to go high. When it goes high we'll go into State 3 State 3 ------- Input is high and we're running the counter. When the input goes low, we'll go into the idle state. A truth table for this state machine is: state input | Next State ------------------------------ idle X idle state 1 H->L state 2 state 2 L->H state 3 state 3 H->L idle let's assign state values: name AB ------------- idle = 00 state 1 = 01 state 2 = 10 state 3 = 11 The truth table for these state assignments is: Next State AB I AB ----------- 01 0 10 01 1 01 10 0 10 10 1 10 --> start counting 11 0 00 --> stop counting 11 1 11 --> counting If you use the Idle state (00) as a don't care, then this truth table can be expressed: ; W = input xorwf A,F ; A = A ^ I xorwf B,W ; W = B ^ I xorwf B,F ; B = B ^ I ^ B = I xorwf B,W ; W = B ^ I ^ I = B andwf A,F ; A = (A ^ I) & B comf A,F ; A = (A' ^ I) | B' This is obviously wasteful since two whole bytes are used for only two bits. However, notice that actually 8 state machines are being computed in parallel! Okay, let's put it all together. I changed things a little from above and wrote (and tested :) this little routine illustrating the whole idea: ;------------------------------------------------------------ ; ; Vertical Pulse Counting - a routine illustrating vertical ; counters for measuring pulse widths. ; ; The two state variables, A & B control the behavior of the ; counters. If A & B are low, the counters are in an idle state ; and should not advance (regardless of the input) ; If A & B are both high, the counters will count and continue ; to count until the input goes low. When this happens, A&B ; go low again and the counters are in the idle state. ; When A is low and B is high, the counters are waiting for ; the input to go low. When this happens, the state machine ; advances to the next state. ; When A is high and B is low, the counters are waiting for ; the input to go high. When this happens, both A & B go high ; and the counters are enabled. ; ; The counters are "vertical counters". Which is to say, they're ; not "horizontal". Normally we think of the bits of a variable ; all residing in one memory location. However, this is only a ; convenience. There's no reason bit 0 can be in one memory ; location while bit 1 is another, and so on. If arranged this ; way, it's possible to use boolean logic and process 8 states ; (or counters) in parallel. ; ; The benefit is that individual bits do not need to be examined. ; Boolean equations control the program flow. This simplifies ; isochronous coding too. The problem with vertical counters ; is that it's difficult to extract the counter value. ; ; vpc: ; movf PORTA,W ; Read I vpc_sim: movwf Input movf B,W movwf Idle movf A,W iorwf Idle,F ; save the idle state xorwf Input,W ; W = A ^ I andwf B,W ; W = (A ^ I) & B xorlw 0xff ; W = (A' ^ I) | B' movwf A ; A = (A' ^ I) | B' movf Input,W movwf B ; B = I ; Don't count if we're in the idle state movf Idle,W andwf A,F andwf B,F ; only count if the input has gone high andwf A,W andwf B,W ; count xorwf C0,F comf C0,F andwf C0,W comf C0,F xorwf C1,F comf C1,F andwf C1,W comf C1,F xorwf C2,F comf C2,F andwf C2,W comf C2,F xorwf C3,F comf C3,F andwf C3,W comf C3,F return ;---------------------------- start: clrf C0 clrf C1 clrf C2 clrf C3 clrf A clrf B ; verify counter doesn't advance call vpc movlw 0xff call vpc ; still in idle state, shouldn't count movlw 0 call vpc movlw 0xff call vpc movlw 1 movwf B ; should stay in state 1 movlw 1 call vpc ; input goes low - stay in state 2 movlw 0 call vpc ; input goes high - go to state 3 and start counting movlw 1 call vpc loop movlw 1 call vpc ; check the carry out andlw 1 skpnz goto loop ; input goes low - go to state 0 and stop counting movlw 0 call vpc movlw 0 call vpc movlw 1 call vpc goto $ ------ Whew! Scott -- http://www.piclist.com hint: PICList Posts must start with ONE topic: [PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads