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.