Thanks to all for your answers to my 50% stuff question. I perhaps didn't explain myself properly or didn't understand your answer correctly. Let me please rephrase my question. Let's say I want to multiply the frequency of an input square wave by some factor "F".Consider a sensor giving pulses from a rotating shaft, if the shaft accelerates then two consecutive periods are different. Every next period will be shorter than the previous one. Now if I divide the first period "P" by "F" and output an "F" amount of pulses with periods equal to "P/F" then the PIC will still be outputting pulses while the next period is already happening. I can't loose counts since I need this for positioning, direction and speed measurement purposes. I have to watch both edges for any change in the direction of the shaft.The sensor is a quadrature encoder with only A and B outputs, no Z. I have to output two channels out of phase by ~90% to the system processing the data.The phase difference is naturally the same as the incoming pulse. I have managed to do it for a fixed or slow variable frequency.I implemented it in software on an 16F84A, I know they are outdated, but I have lots of them!. When the shaft accelerates fast then I start to miss about 3 to 10% of the pulses depending on the acceleration, getting offsets in position.When the shaft is slowing down then is ok because the next period will be longer. There will be space enough in time to accommodate the multiplied pulses before the next ones will have to be outputted. I might be missing something here, I don't know what a phase accumulator is but I'll try to find out. It looks to me that this task is just not possible to fix on a base of period by period multiplication. I appreciate very much any advise or pointer to how to solve this. And sorry for taking this thread, I didn't mean to. Best regards RA ----- Original Message ----- From: "Scott Dattalo" To: Sent: Tuesday, April 29, 2003 6:09 PM Subject: Re: [PIC]: Frequency multiplier? > On Tue, 29 Apr 2003, Reinaldo Alvares wrote: > > > What if the duty cycle is not 50%, and say variable? > > Any square wave can be made into a 50% duty cycle by dividing by 2. In > other words, just watch the rising (or falling) edge. Brata's approach > still works. This is just another example of a phase accumulator. > > I haven't been monitoring this thread too closely, but the easiest way to > solve this problem for a single channel is to utilize the PIC's input > capture and timer 2 outputs. For example, configure TMR1 to capture all > rising edges and PR2 to specify TMR2's period. The value stuffed in PR2 is > simply multiplicative (and possibly filtered) factor of the capture > interval. The fact that someone hasn't suggested this solution implies > that either this is for a PIC without these peripherals or there is more > than one channel. [but after reading the original poster's request, it > appears that only one channel is required -- so maybe there's another > reason.] > > One way to do this in software is like so: > > In the (high frequency) interrupt routine: > > CurrentState = IOPort(); > rising_edge = (CurrentState ^ LastState) & CurrentState; > LastState = CurrentState; > > if(rising_edge & BIT_n) { > rollover = rising_edge_counter; > rising_edge_counter = 0; > } else > rising_edge_counter++; > > > if(freq_out == 0) { > toggle_output(); > freq_out = Fout_half_period; > } else > freq_out--; > > And in the main loop: > > if (rollover) { > Fout_update_period(); > rollover = 0; > } > > > Where Fout_update_period() scales the period of the output clock to be > a multiplicative factor of the input clock. Or more specifically, the > periods are scaled. > > This rather verbose approach is easily scalable to multiple channels. > > To monitor the rising edges and control the scaled frequency outputs, then > something like this would suitable for a high frequency interrupt (e.g. > tmr0 rollovers): > > movf Input_PORT,W ;Read the current > xorwf LastState,W ;compare to the last > xorwf LastState,F ;Save current as last > andwf LastState,W ;Get the rising edges. > > movwf temp ; > iorwf rollovers,F ;Let the main loop know > > ; before processing the rollovers, > ; generate the outputs (this way you'll be less susceptible to > ; the jitter incurred with the non-isochronous code that processes > ; the rising edges.) > > clrf FoutToggle ; assume that the outputs aren't > ; going to change > > movf Fout0_period,W ;Get the (half) period in case we roll > decf Fout0_ctr,F ;Toggle when this reaches zero > ;Check the rollovers - use btf's instead > skpnz ;of goto's for isochronous execution. > movwf Fout0_ctr ;rolled over, so reset the counter > skpnz ; > bsf FoutToggle,0 ;and set this bit for below > > > ... same for other outputs > > ; now update the outputs > > movf FoutToggle,W > xorwf Fout,W > movwf Fout > movwf Output_PORT > > ; now process the rising edges. > > > ch0: > incf Ch0_ctr ;Assume rising edge did not occur > btfsc temp,0 > goto re0 ;Handle the rising edge > > ch1: > ... > > chn: > ... > > > > > return ; or interrupt exit code > > > re0: > decf Ch0_ctr,W ; > movwf Ch0_period > clrf Ch0_ctr > > goto Ch1 > > re1: > ... > > > ------------ > > In the main loop, ch0_period and when it becomes non-zero, update the > Fout0_period. Again, this is just a detailed explanation of the phase > accumulator alogrithm proposed by Breta. > > Scott > > -- > http://www.piclist.com hint: The PICList is archived three different > ways. See http://www.piclist.com/#archives for details. > -- http://www.piclist.com#nomail Going offline? Don't AutoReply us! email listserv@mitvma.mit.edu with SET PICList DIGEST in the body